Exercise: Driving Shifts Into Reverse
In this exercise, you will transform a static chart into an interactive graphic. Our starting point is Hannah Fairfield’s “Driving Shifts Into Reverse”, published in the New York Times in 2010. The chart shows how miles driven and the cost of gasoline have changed over the years. The graphic is an example of a connected scatterplot, in which uses the x
and y
channels for variables that might move freely along the dimensions over time.
Dataset
The dataset consists of the average miles
driven per person and the cost of gas
($ per gallon) in each year
, ranging from 1956 to 2010.
const driving = FileAttachment('../data/driving.csv').csv({ typed: true });
In addition, the d3.extent()
function has been used to precompute [min, max]
arrays for each of these variables:
const milesExtent = d3.extent(driving, d => d.miles);
const gasExtent = d3.extent(driving, d => d.gas);
const yearExtent = d3.extent(driving, d => d.year);
Task 1: Use Reactive Updates
Below we’ve already created a Vega-Lite version of the “Driving Shifts Into Reverse” graphic. Your task is to make the chart interactive, using an external slider to filter the number of years shown. Dragging the slider back and forth should cause only those years with values less than or equal to the slider to be visible.
At first we will use Observable’s reactive runtime to drive the interaction. We’ve included a slider component for you below. Add a filter transform to the Vega-Lite chart to performs the desired filtering.
Once you’ve set up the filter, do you notice anything wrong? If you’ve made no other changes, you’ll see that as we filter the data, the axis scale domains also change. The chart in unstable, hampering comparison across updates. Interaction often forces us to think along additional design dimensions!
Update your code to make the x
and y
channels stable across updates. You may want to use the extents we precomputed earlier. Note: properly modifying the first layer (line mark) should be sufficient, as other layers will inherit settings.
Task 2: Use a Vega-Lite Param
Our example above works well for small data, but is inefficient. The Observable runtime tracks changes to the slider, and with each change completely re-evaluates dependent code blocks such as our chart. That means on every slider update we are recomputing the Vega-Lite chart from scratch. We’d like to take advantage of Vega-Lite’s interaction and efficient re-rendering mechanisms.
For this task, you should rewrite the interactive Vega-Lite chart in a completely standalone fashion. You should start by copying your code from above. Next, you should add a new param
to your Vega-Lite code, bind
it to a “range” (slider) input, and update the filter transform to use that param.
Task 3: Add Tooltips
You’ve turned a static chart interactive, but we’re not done yet! It’s often helpful to provide details-on-demand when selecting an item in a chart. So let’s show an informative tooltip when a user hovers their pointer over a data point.
First copy your code from Task 2 above. Then use the tooltip
channel to create a custom tooltip message. Your tooltips should match the image above, with custom names and formatting for the fields: format miles
as an integer, and format gas
with 2 decimal places.
Don’t forget to add
, commit
, and push
your exercises to your GitLab repo!