11
\$\begingroup\$

Background

The Pythagorean theorem asserts that for a right triangle with hypotenuse \$c\$ and other sides \$a\$ and \$b\$, the area of the square placed upon \$c\$ is equal to the sum of the areas placed upon \$a\$ and \$b\$. This is normally written algebraically as \$a^2+b^2 = c^2\$.

One way to prove this is to draw two squares of side length \$a+b\$. In one, draw four identical \$abc\$ triangles such that their hypotenuses form a square of side length \$c\$. In the other, draw four more identical \$abc\$ triangles such that they form two rectangles with side lengths \$a\$ and \$b\$ and the same length sides are adjacent. This creates two squares with side length \$a\$ and \$b\$ respectively.

Visualization of the Pythagorean theorem

So now we have four triangles of area \$\frac{1}{2}ab\$ in each square of area \$(a+b)^2\$. In addition, the left square contains a square of area \$c^2\$ and the right square contains two squares of area \$a^2\$ and \$b^2\$ respectively. Summing up the areas inside the two equal squares, we get

$$c^2 + 4(\frac{1}{2}ab) = a^2 + b^2 + 4(\frac{1}{2}ab)$$

Subtracting like terms from both sides, we get

$$c^2 = a^2 + b^2$$

The nifty thing about this method is that it actually shows what "the area of the square placed upon" a side means.

Now of course you're wondering how I generated the diagram. I used a free SVG to PNG converter (this one) to generate the image from an SVG.

The SVG

<svg width="4400" height="2200"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink= "http://www.w3.org/1999/xlink">
  <style>
    svg {
      background-color:  white;
    }

    text {
      font:  3000% "Times New Roman";
      text-anchor:  end;
    }

    text.superscript {
      font-size:  1200%;
      text-anchor:  start;
    }
  </style>

  <rect x="100" y="100" width="2000" height="2000" fill="none" stroke="black" />
  <polygon points="900,100 100,1300 1300,2100 2100,900" fill="none" stroke="black" />
  <text x="1100" y="1300">c</text>
  <text x="1100" y="1100" class="superscript">2</text>

  <rect x="2300" y="100" width="2000" height="2000" fill="none" stroke="black" />
  <polygon points="3100,1300 3100,100 2300,1300 4300,1300 3100,2100"
           fill="none" stroke="black" />
  <text x="2750" y="1850">a</text>
  <text x="2750" y="1700" class="superscript">2</text>
  <text x="3750" y="950">b</text>
  <text x="3750" y="700" class="superscript">2</text>
</svg>

Some tags broken across multiple lines to eliminate scrolling on this site. This does not seem to affect parsing of the SVG code (I ported it back to my code to check).

Review suggestions

As always, you can review any aspect of the SVG or CSS code. But here are some areas that are of particular interest to me.

  1. Does this meet best standards for an SVG?
  2. In particular, is there a better way of keeping the numbers consistent?
  3. Is the resulting image visually appealing and easy to read?
  4. Is there a better visualization? For example, I've seen images that put both squares atop one another and use different colors or animation. Is there an appealing way to do something like that with a static black and white image?

Some requirements that may not be obvious.

  1. This is a black and white image. No color.
  2. No animation. Just a static image.
  3. \$a \le b \lt c\$. The first two simply by definition. If there's a smaller leg, we're calling that one \$a\$. The last by the definition of a right triangle. The hypotenuse is always the longest side.
  4. The image is deliberately created large. Please keep the \$a+b\$ squares the same size.

Beyond that feel free to move things around, change the stroke, change the margins, or change the proportions. But do try to remember that this is a code review. While I am certain that any number of people could draw a better visualization by hand or GImP, this uses SVG for that purpose. So please propose edits to the SVG rather than changes to the image. For example, a patterned fill is certainly possible, but please include how to do that rather than just saying, "The image would look better filled with a polka-dot pattern."

My plan is to use this to fix my T-shirt design on Zazzle, as the current image doesn't scale well.

\$\endgroup\$
  • \$\begingroup\$ You’re asking for changes to code and not to the image. So this is unsolicited advice: make the darkness of the lines and the text more similar. The lines now are very thin wrt the letters, and fade into the background. (I’m reading on a phone so that might exaggerate the effect.) \$\endgroup\$ – Cris Luengo Jun 15 at 15:13
7
\$\begingroup\$

Wow! I’ve never reviewed an image before. Neat.

First, I’d flip your left square to align the corners of the right-most triangles in the left square with the horizontal line in the right square. This gives a visual indication that those dimensions (a and b) in both squares are the same. With the original image, your eye has to draw the line all the way across the left square to see it line up with the left triangles of the left square.

Second, both squares have the same four triangles, except in your right diagram, you have to mentally flip 2 of the triangles to make corresponding triangles in the same orientation between left and right squares. If you drew one of the diagonals between the opposite corners of the a/b rectangles, then all 4 triangles can be mentally translated from the left to the right image, without needing rotations or flips.

I’ve number the triangles in my image, below, to show you what I mean, but I’m not certain you’d want to number them in your final t-shirt design.

Pythagorean squares with corresponding triangles numbered for comparison

The SVG Code

Styling

You've used styles to assign attribute to text elements, so you don't have to specify the attributes in each <text/> element, but you continue to specify both the fill and stroke for <rect/> and <polygon/> elements. Let's add a style for these:

rect, polygon {
    fill: none;
    stroke: black;
}

Coordinates

I would use two group nodes with translations to draw the left and right squares using the same coordinate system, with the 0,0 coordinate to where the centre of the large rectangles will be. The rectangle's corners will then all be ±1000,±1000.

<g transform="translate(1100, 1100)">
    <rect x="-1000" y="-1000" width="2000" height="2000" />
</g>

<g transform="translate(3300, 1100)">
    <rect x="-1000" y="-1000" width="2000" height="2000" />
</g>

Symbols

It is pretty clear both these rectangles will be the same; the code for them is identical. But we can do better. Like moving common code into a subroutine, let's move our common shapes into a definition.

<defs>
    <rect id="square" x="-1000" y="-1000" width="2000" height="2000" />
</defs>

<g transform="translate(1100, 1100)">
    <use xlink:href="#square" />
</g>

<g transform="translate(3300, 1100)">
    <use xlink:href="#square" />
</g>

Next, let's add our triangles. The triangles are all identical, so again it makes sense to use a common definition.

<defs>
    <rect id="square" x="-1000" y="-1000" width="2000" height="2000" />
    <polygon id="triangle" points="0,0 1200,0 0,800" />
</defs>

I've put the right-angle of the triangle at the 0,0 coordinate, which will make it fairly easy to position each triangle at one of the 4 corners of the left square:

<g transform="translate(1100, 1100)">
    <use xlink:href="#square" />
    <use xlink:href="#triangle" transform="translate(-1000,-1000) rotate(0)" />
    <use xlink:href="#triangle" transform="translate(+1000,-1000) rotate(90)" />
    <use xlink:href="#triangle" transform="translate(+1000,+1000) rotate(180)" />
    <use xlink:href="#triangle" transform="translate(-1000,+1000) rotate(270)" />
</g>

For the right square, we just need to update the positions of the triangles. Unfortunately, these require knowledge of the a,b values:

<g transform="translate(3300, 1100)">
<use xlink:href="#square"/>
    <use xlink:href="#triangle" transform="translate( -200, +200) rotate(0)" />
    <use xlink:href="#triangle" transform="translate( -200,-1000) rotate(90)" />
    <use xlink:href="#triangle" transform="translate(+1000,+1000) rotate(180)" />
    <use xlink:href="#triangle" transform="translate(-1000, +200) rotate(270)" />
</g>

Text Grouping

Finally, the text nodes need to be added back in, taking into account the new coordinate system. Again, you draw these in similar ways. You draw a letter, and then draw the superscript "2" at an offset from the letter's origin. Sometimes, it is 200 pixels higher, sometimes it is 150 pixels higher. Why the discrepancy? Intentional or accidental?

Let's be more rigid about how we lay out the text. Let's put the text into a group, with the letter at 0,0 and the superscript at 0,200, and move the text group to the correct position with a transform.

    <g transform="translate(-550, 550)">
        <text x="0" y="200">a</text>
        <text x="0" y="0" class="superscript">2</text>
    </g>

    <g transform="translate(450, -450)">
        <text x="0" y="200">b</text>
        <text x="0" y="0" class="superscript">2</text>
    </g>

Now we can see a structure to how the text is drawn, and be consistent between the areas.

Refactored Code

<svg width="4400" height="2200"
     xmlns="http://www.w3.org/2000/svg"
     xmlns:xlink= "http://www.w3.org/1999/xlink">
  <style>
    svg {
      background-color:  white;
    }

    rect, polygon {
        fill: none;
        stroke: black;
    }

    text {
      font:  3000% "Times New Roman";
      text-anchor:  end;
    }

    text.superscript {
      font-size:  1200%;
      text-anchor:  start;
    }
  </style>

  <defs>
    <rect id="square" x="-1000" y="-1000" width="2000" height="2000"/>
    <polygon id="triangle" points="0,0 1200,0 0,800" />
  </defs>

  <g transform="translate(1100, 1100)">
    <use xlink:href="#square" />

    <use xlink:href="#triangle" transform="translate(-1000,-1000) rotate(0)" />
    <use xlink:href="#triangle" transform="translate(+1000,-1000) rotate(90)" />
    <use xlink:href="#triangle" transform="translate(+1000,+1000) rotate(180)" />
    <use xlink:href="#triangle" transform="translate(-1000,+1000) rotate(270)" />

    <text x="0" y="200">c</text>
    <text x="0" y="0" class="superscript">2</text>
  </g>

  <g transform="translate(3300, 1100)">
    <use xlink:href="#square"/>

    <use xlink:href="#triangle" transform="translate( -200, +200) rotate(0)" />
    <use xlink:href="#triangle" transform="translate( -200,-1000) rotate(90)" />
    <use xlink:href="#triangle" transform="translate(+1000,+1000) rotate(180)" />
    <use xlink:href="#triangle" transform="translate(-1000, +200) rotate(270)" />

    <g transform="translate(-550, 550)">
      <text x="0" y="200">a</text>
      <text x="0" y="0" class="superscript">2</text>
    </g>

    <g transform="translate(450, -450)">
      <text x="0" y="200">b</text>
      <text x="0" y="0" class="superscript">2</text>
    </g>
  </g>
</svg>

Is this a better? It is certainly longer, so that is a negative. However, I like that the triangle coordinates are simply 0,0, 1200,0 and 0,800. Changing the size of the triangle works perfectly for the left square; the right square you still need to adjust 4 numbers in the translate() calls to get the triangles to line up properly, and will need to manually move the a² and b² text positions, but at least the superscripted 2's don't need to be adjusted separately.

You could use a PHP script, or an XSLT stylesheet to generate this SVG document, with the a parameter as input, and it could do the calculations for you, and fill in the calculated numbers in the required 10 places.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.