Maintained by: David J. Birnbaum (djbpitt@gmail.com) Last modified: 2022-11-14T15:48:43+0000
Those who haven’t grown up with the US political system often have trouble understanding
the Electoral College, which seems to undermine the principle of one person, one
vote
and imbue not individuals, but states, with control of national elections,
a result that some find self-evidently anti-democratic. Whether one endorses it or not,
the Electoral College was created for a reason, and you can read about the details at a page
maintained by the National Archives and Records Administration (NARA). The most
important detail for our purposes is that electoral votes are allocated on a
winner-take-all basis, which means, for example, that a candidate who carries a state by
51% to 49% wins 100% of that state’s electoral votes, rather than just 51% of them.
(There are two states that in principle allocate electoral votes proportionately, but in
the 2012 presidential election their votes went entirely to one candidate, so we can
simplify our task by regarding them as winner-take-all states, too.)
The data for this assignment are at http://dh.obdurodon.org/election_2012_data.xml and consist of an XML representation of the voting in the 2012 presidential election. The data set (scraped from http://en.wikipedia.org/wiki/United_States_presidential_election,_2012) contains entries for each state (plus DC) that controls electoral votes, in the form:
<state name="Pennsylvania" acro="PA" elec="20">
<candidate party="Democrat">2925786</candidate>
<candidate party="Republican">2641387</candidate>
<candidate party="Libertarian">49094</candidate>
<candidate party="Green">20849</candidate>
</state>
There are many ways to visualize this information, the parameters of which include popular vote (raw and percentage) and electoral vote. For example, at http://upload.wikimedia.org/wikipedia/commons/b/bf/2012_Presidential_Election_EVstack.svg, the image is organized around a vertical axis in the middle. The X axis stretches left and right from 0 (in the middle) to 100 (at the left and right edges), and the horizontal length of a bar indicates the margin of victory of the winning candidate. You can see, for example, at the bottom of the chart that the Democrats had a margin of victory of between 80% and 90% in DC and the Republicans of between 40% and 50% in Utah, and the skinniest bars, at the top represent the swing states, the ones with very narrow margins of victory. The height of the bars indicates the number of electoral votes they carry; DC is worth 3 electoral votes and Utah is worth 6, so the bar for Utah is twice as tall as the one for DC. The axes are labeled (X = margin of victory and Y = electoral votes), as are the states, and there are regularly spaced numbers on the axes for orientation, but no data labels with exact numbers of votes (raw or percentage, popular or electoral).
This particular graph was drawn in Inkscape, an SVG drawing application. If you view the
source, you can see the raw SVG, but it isn’t the sort of SVG you would want to create
yourself. In particular, it isn’t very legible because it uses the SVG
<path>
element; if we were generating this graph
by using XSLT to transform the raw XML data into SVG, we would have used
<rect>
instead, which is both easier to program
and easier to read.
You do not have to produce the chart discussed above! Your task is much simpler: you should write an XSLT program to generate an SVG bar chart of percentage of the popular vote cast for the Democratic party candidate in each state. We’ve posted some sample output at http://dh.obdurodon.org/election_democrat.xml (your results don’t have to look exactly like ours, of course, as long as you include the necessary information in a legible form).
Your XSLT must include meaningful comments that document what each part of the
code does. You don’t have to comment the obvious parts (for example, if you use
a variable called $bar-width
you don’t need
a comment that says the width of the bar
). But you should have comments
that label the major sections of your code and that explain anything that won’t
be self-explanatory should you look back at it six months from now.
Your output SVG must be valid. This means that you have to save the output to disk, open it in <oXygen/>, validate it there, and fix any issues in the XSLT that are impinging on the validity of the output.
Alternatively, if you are not able to fix a validity issue, your XSLT must include a comment explaining exactly what you think is wrong, exactly what you tried to do to fix it, and exactly how you understand the difference between what you expected and what you got. To a large extent this is rubber-duck debugging and is likely to lead you to recognize the source of the problem yourself, but it also helps us give you more meaningful feedback when that doesn’t happen.
You’ll need to create SVG elements for rectangles (to represent the bars), lines (axes, and perhaps orientation lines), and text.
While we usually favor push processing (using
<xsl:template>
and
<xsl:apply-templates>
), you may find it
easier with this type of transformation to use pull processing, with
<xsl:for-each>
and
<xsl:value-of>
. You can read more about
these at our XSLT, part 2:
conditionals and push and pull and, of course, in Michael Kay.
We find it easiest to plot the entire graph in the upper right quadrant and use
the @viewBox
attribute to make that part of
the coordinate system visible. To do this:
Stick a minus sign in front of all Y values. This will cause them to be plotted above the X axis, with larger negative values above smaller ones.
The default viewbox has the same coordinates as the viewport. That is,
without specifying a @viewBox
attribute value, we'll only see items drawn in the lower right quadrant.
@viewBox
takes four values,
separated by spaces or commas, as its value. These values represent the
minimum X value, minimum Y value, width, and height of the
viewbox, in that order. You can start by hard-coding those values.
Remember that since you drew everything in the upper right quadrant,
your Y values are negative, so you want the viewbox to reflect that:
@viewBox="0 -500 500 500"
, for
example.
A more elegant approach is to use XPath to calculate the height of the tallest bar and employ that calculation in setting the viewbox's minimum Y value and height. Similarly, you'll want to calculate the total width space occupied by all your bars and use that in the X value and width. This approach requires more effort, but it makes your code much more adaptable. You'll likely also need to add some padding to the dimensions of your viewbox to ensure that every label is also visible.
Alternatively, you can plot everything directly in the lower right quadrant, but we find that harder to manage. For this assignment you cannot have your bars grow downward! That would be easier to code, but, unfortunately, it isn’t the way humans expect a chart like this to look.
The XML data gives raw votes, so you have to calculate the percentages yourself. The values can range from 0 to 100, so if you’re getting negative values or values greater than 100, you need to check your arithmetic.
You can round non-integer numerical values by using the XPath
round()
function, which you can look up in
Michael Kay. If you want to round to something other than an integer (for
example, to tenths), you can use
format-number()
to control the lexical
shape
of the representation. SVG doesn’t care how far a number goes to
the right of the decimal point, so you don’t have to round for plotting
purposes. The only reason you have to think about rounding is that you may want
to display numbers in a way that human readers will expect.
Aligning text the way you want it aligned often requires setting the
@text-anchor
attribute, which you can read
about at https://developer.mozilla.org/en-US/docs/SVG/Attribute/text-anchor (we
find the value middle
very useful).
The XML data is organized alphabetically by state, and that’s what we’ve done in our sample solution, but it isn’t the most natural way to represent this data. If you’re feeling ambitious, you might want to sort the output from highest to lowest percentage of votes cast for the Democrats, so that DC will be on the far left and Utah on the far right—graphically as well as politically!
You’ll want to draw and label the X and Y axes, and you might want to use dashed lines (as we did in our sample solution) or faint horizontal lines (as we did in in http://pavlova.obdurodon.org/character_chart.xhtml) to make it easier for users to see the height values. You’ll also want to label the bars, so that your viewers can see which state is which, and you may or may not want to add data labels that give the percentage values of the votes.
You’ll have to decide how to space the bars along the X axis, and whether or how to use color.
Given the Democratic victory in both the popular and electoral voting, a representation of votes cast for the Democrats is probably the most important information, and you can stop there, if you’d like. You can, though, enhance the chart in several ways:
You can create a stacked bar chart, with the percentages of other candidates stacked on top of the Democrats, so that all bars top out at 100%. These representations are usually easiest to read if you think first about how to arrange the pieces. You probably want all of the parties in the same order in all of the bars, and one choice is to pile the Republicans on top of the Democrats, with the others above them in order of how large a part they played in the election. We found it more useful to have the Democratic vote grow up from the baseline and the Republican vote grow down from the top, with the other parties in the middle, in a consistent order. That makes it easier to see the curve for the two largest parties.
Once we add other parties, it seems natural to make the Democrats blue, the Republicans red, and the Greens … well … green. The other colors are less obvious, but http://en.wikipedia.org/wiki/United_States_presidential_election,_2012 used yellow for the Libertarian party, purple for the Constitution party, and blue for the Justice party. That page also lists, but does not assign color to, the Peace and Freedom party and America’s party, so if you choose to include those, you’ll have to choose your own colors.
The bar chart so far has represented only popular vote, but we can add another dimension by exploiting the X axis to make the bars different widths, with the width proportional to the electoral votes. For example, Utah, with 6 electoral votes, would be twice as wide as DC, with 3. Once you do this, though, you have to deal with questions of scale, and we can think of at least four possible strategies:
Let the bars get as wide as they need to be in order to make the differences perceptible, with the understanding that users will have to resize the image to make it all fit (which is what we did in the sample solution to the basic assignment, above).
Let the bars get as wide as they need to be in order to make the differences perceptible and implement a horizontal scroll bar (we can show you how to do that). Users don’t generally like horizontal scrolling, which doesn’t mean that it’s never the Right Answer, but we should be aware that it doesn’t feel as natural to most users as vertical scrolling.
Shrink the width of all bars, keeping it proportional, so that it fits across the screen without scrolling. This makes it easier to take in the chart at a glance, but harder to see the differences among small values. You can specify X positions as percentages, rather than pixels, which will cause the image to contract and shrink proportionally as the user changes the width of the window. We used this strategy at http://zatochnik.obdurodon.org/; if you view the source, you can see the percentage values.
Swap the axes, so that the bars run horizontally instead of vertically, exploiting the fact that users are generally more comfortable with vertical scrolling than with horizontal scrolling. Gabi did this for her fairy-tale speech chart (bottom chart, right column) at http://ft.obdurodon.org/reports/balance1.xhtml.
For an ambitious, JavaScript-enhanced presentation, see http://dh.obdurodon.org/election.xhtml.
You should turn in the single XSLT file that you wrote, that is, a file with the extension .xsl, which generates the desired SVG output. Do not turn in your SVG; we will run the XSLT transformation ourselves.