2. Creating the interactive graph - rochiecuevas/Data_Journalism GitHub Wiki
The SVG object serves as the container of the graph. Hence, it is important to create one of an ample size; i.e., the data points (e.g., circles with text labels) do not look crowded. In this case, the SVG object is a horizontal rectangle, slightly wider than it is long. The bottom and the left margins are also bigger to ensure that the three x-axis labels and the three y-axis labels can be positioned outside the axes and their tick marks, and that there is enough breathing space between labels.
The SVG object is added to the HTML tag which has an id of "svg-scatter". Within the SVG object, a graph element ("g") is added. The attribute "transform", translate(x,y)
offsets the graph element such that it is positioned along the left and the top margins rather than the actual borders of the SVG object.
Poverty and obesity are the default x- and y-axes labels when the landing page is launched.
Several functions are defined in preparation for transitions among the axis labels. These actions include adjusting the scale of the axis; placing the adjusted axes and circles in their rightful positions; and to display the right information in the tooltips.
FunctionName | Action upon click |
---|---|
xScale, yScale | Update the scale of the axis based on the extent (min, max) of the variables |
renderXAxes, renderYAxes | Update the axis, with the x-axis at the bottom of the graph and the y-axis on the left |
renderCircles | Update the positions of the individual data points (depicted by green circles) and their labels (state abbreviations |
updateToolTip | Update the tooltip of each data point based on the axes selected (e.g., poverty and obesity data) |
These functions are created before calling the data file so that they can be executed within the d3.csv function when called.
The axis scale function (e.g., yScale) returns the linear scale, which is basically an instruction to overlay the range of a variable (e.g., obesity) onto the full height within the margins of the SVG object. In the case of xScale, the range of the variable (e.g., poverty) is overlaid onto the full width within the margins of the SVG object.
Once the axis scale has been returned (yScale or xScale), it can be used to assign the axis onto its rightful position (either at the bottom or the left side) in the SVG object using the renderYAxes (or renderXAxes) function. A transition (duration = 1s) is added so that the reader can see the axes change values.
But it is not only the axes that move; the circles (and their labels) also move to different positions based on the axes selected using the renderCircles function. This function returns circlesGroup, which contains information about the circles and their labels. Hence, the function does two things: (1) move the circles and (2) move the text within the circles (in this case, state abbreviations).
To move the circles of circlesGroup during transition, all of them have to be selected (selectAll("circle")
) and assigned to the new coordinates (as referred to by "cx" and "cy"). If they are not selected, the circles will remain in place (even if the axes move) because the new "cx" and "cy" values will be assigned to circlesGroup (i.e., the "g" element), rather than to the individual circles.
For instance, in the DOM inspector, the default coordinates of each circle is as follows (note "cx" and "cy" values):
<g class = "element-group">
<circle cx="394.9783080260304" cy="132.44239631336404" r="10" fill="green" opacity=".5"></circle>
</g>
Choosing different x- and y-axis labels then change the circle coordinates. For example, if age and smokes are chosen, respectively:
<g class = "element-group">
<circle cx="303.7166900420757" cy="162.20757825370674" r="10" fill="green" opacity=".5"></circle>
</g>
To move the state abbreviations together with the circles, instead of calling "cx" and "cy", which are coordinate points for circles, "x" and "y" are specified as their coordinates. Hence, the DOM inspector shows the resulting <text>
HTML tag for the Alabama circle (as an example):
<g class = "element-group">
<circle cx="303.7166900420757" cy="162.20757825370674" r="10" fill="green" opacity=".5"></circle>
<text style="text-anchor: middle;" x="303.7166900420757" y="162.20757825370674" dy=".3em" class="circle-text">AL</text>
</g>
UpdateToolTip, on the other hand, changes the content of the tooltip depending on the chosen axes. This requires the use of if and else if statements that return labels that correspond to the axis (e.g., "Poverty (%)"). Note that to ensure that the changes in one axis is independent of the other, the if/else if statements for the x-axis variables are siblings of the if/else if statement of y-axis variables.
The labels then get assigned to the tooltip, which is positioned not directly on top of the circle (hence the offset). But since tooltips are only present either when the mouse is hovered over the circle or the circle is clicked, the tooltip is shown on click and hidden on mouseout.
The contents of data.csv are derived from the 2014 ACS 1-year estimates by state. data.csv contains six variables and their margins of error. Three variables can be classified as sociodemographic (age, income, poverty) while the other three are related to health risks (obesity, smokes, without health insurance). Sociodemographic variables are assigned to the x-axis and the health variables to the y-axis.
d3.csv() outputs to an array containing objects that correspond to the rows of data.csv. For example, the row containing data from Alabama is converted to the object containing the following keys and values, as can be seen in the DOM console:
0: {…}
abbr: "AL"
age: "38.6"
ageMoe: "0.2"
id: "1"
income: "42830"
incomeMoe: "598"
noHealthInsurance: "13.9"
obesity: "33.5"
poverty: "19.3"
povertyMoe: "0.5"
smokes: "21.1"
state: "Alabama"
Numerical variables are strings. Hence, the first step to using the data is to convert the numerical variables from string to float.
The x- and the y-scales are then defined using xScale and yScale functions, followed by positioning and then appending (to the "g") these scales either at the bottom (x-axis) or on the left side (y-axis) of the graph.
With the axes in place, the circles can be added onto the plot. A group of circles is created and in it, circles (for each row in data.csv) and state abbreviations are appended.
The axes are established and the circles are on the graph. However, the axes do not have labels yet. Hence, xLabels and yLabels, which are added to "g", are defined. For example, poverty values are placed in the povertyLabel var, which is appended to xLabels. Since there are three x-axis labels, their positions on the graph are offset (using .attr("y", <insert number>)
) by trial and error so that there is enough breathing space between labels.
For the yLabels, the label assignments for health risk metrics are similarly assigned. Obesity values, for example, are called in the obesityLabel, which is appended to yLabels. However, the offset per variable is dependent to the margins.left value. The code thus reads:
Note that for both xLabels and yLabels, the variable labels each has an attribute that assigns a value for the event listener (on "click").
When the axis labels are clicked and the axis is not the default, the tooltip of each circle is updated (through the function UpdateToolTip), the axis ticks change to reflect the scale of the selected variable (through the functions xScale and renderXAxes, or yScale and renderYAxes), and the positions of the circles are changed (through the renderCircles function). Hence, the code that renders the transitions in the x-axis reads thus:
But it is also important to indicate which axes have been selected. Therefore, if/else if statements are added to assign active/inactive classes to the axis labels. For example, if age is selected through a mouse click, it is classed as active and the other two x-axis labels are classed as inactive. Though the code below is for the x-axis label event listener, a similar code is written for the y-axis label event listener.
To ensure that the y-axis label event listener is independent of the x-axis label event listener, the two event listeners are coded as siblings rather than nesting one in the other.
The text indicating possible interpretations of the data is assigned to the HTML tag with the "insights" id. Using the ".html()" allows the writing of text in the innerHTML of the <p id = "insights"></p>
HTML tags. Also, it allows specifying formatting elements within the text (e.g., <b></b>
, <br>
, and <i></i>
.
The code connected to the interactive graph is about formatting the tooltip and defining the appearance of active and inactive axis labels. As a result, the tooltip is a rounded rectangle with a dark background and white font. The active axis label, meanwhile, is in bold, green font. The inactive axis label is not emphasised by font and is greyed out.