Data storytelling D3 workshop
Workshop given at AAAS data storytelling conference by John Muyskens on Friday July 14, 2017.
1. Intro to this workshop
- goal is for you to get a feel for library and get comfortable reading docs
- also learn some conventions - not the only way to do things!
- d3 is a toolkit, not a 3D printer
- what to use it for + what not to use it for
d3 is a powerful, low level toolkit for creating data-driven documents. It is overkill for basic charts, but if you need custom chart types, interaction, or you want to build your own charting library d3 is good to know. It can produce HTML and SVG documents or draw on a Javascript canvas.
We will make an animated chart together that shows the relationship between health spending and life expectancy using data from the OECD. This chart was inspired by Peter Aldhous (you can view his implementation in R here).
Each step involves reading some documentation, then writing a few lines of code. If you get stuck, there is a link at the end of each step to a working implementation.
We will be using Blockbuilder to write code. Blockbuilder is a code editor that runs in your browser and shows you the results which refresh as you write. If you have a GitHub account, you can log in and save your code as Gists. Here's a link to the starting point for our workshop.
2. Intro to SVG
Scalable Vector Graphics is a vector image format. It can be viewed with modern browsers and edited with programs like Adobe Illustrator or Inkscape (open source).
Demo: create an SVG
Task: create an SVG with a rect, circle, text and path.
EXTRA CREDIT: draw a snowman
3. Creating SVG with D3
TASK: draw the same shape with d3
4. SVG grouping and transforming
Task: group some elements together and transform them.
Extra credit: rotate your group.
5. The margin convention
Demo: setting up a basic chart, my first steps with any D3 work
6. Functional programming and data analysis
First, lets load our data: Docs: d3.csv.
d3.csv(‘oecd.csv’, function(data) { // do things with the data });
Take a look at your data using console.log(data)
or console.table(data)
if you are fancy.
Now let’s play with the data, using built in Array functions:
TASK: filter out values where one or both are NA. Then create an Array of life expectancies.
Finally, lets play with some helpful d3-array functions:
d3.max, d3.min, d3.mean, d3.median, d3.extent
http://blockbuilder.org/jmuyskens/4fec60116f5eb5f81edd4380786f8fca
7. Scales
First, choose what variable goes on each axis. We will be doing spending on x and life expectancy on y
var xScale = d3.scaleLinear()
.domain([0, d3.max(healthExpenditures)])
.range([0, width]);
Task: write the y scale, using the extent of the life expectancy for the domain. Note that zero in SVG is at the top of the image, so you’ll want to flip your range.
8. Basic enter pattern
Live coding: add circles
Task: add some text following the same enter pattern. Note: Use a class in your selection (like ‘text.label’) to differentiate your labels from the text in the axes. Remember to add the class to the text. I would suggest using transform
for placement so you can use dx
and dy
for tweaking placement.
There are a ton of labels! Filter out some so we can annotate just a few countries of interest.
http://blockbuilder.org/jmuyskens/9831944f2ccc77f86e627df0c28c9815
9. Axes
Demo: create an x axis
Task: create a y axis
The backbone of the axis is a <path>
while the ticks are <line>
s so you can easily style them separately with CSS.
We can make a dashed line with stroke-dasharray: TKpx TKpx;
.
Task: reduce the number of ticks, make the y axis ticks extend across the chart
Use a transform
to move your axis around.
Play with the following:
.tickSize
to specify length of ticks. Try making your axes as wide and tall as your chart.
.ticks
to specify number of ticks
.tickFormat
format the tick
http://blockbuilder.org/jmuyskens/4d7467f86e731a58848947118923e6f8
10. Grouping data
Goal is to structure your data the way you want your DOM to look.
Nest
is like "groupBy" in other functional programming languages
.entries
returns an array
.map
returns an object which is useful for creating lookup tables. There's also .object
which you can use if you are sure your data doesn't collide with js reserved words. JS objects not equal to hash tables like python dicts but can be used in much the same way.
Try it out with Mr. Nester.
create an object called dataByYear
and use it with your circle selection. Try different years
Now repeat the excercise using .entries
. Note that the structure changes.
http://blockbuilder.org/jmuyskens/4a0e5f282699b88082bf426b10ee1d21
11. Advanced update pattern
docs: enter pattern example
Demo: create an update function
timer function:
var i = 0;
d3.interval(function() {
if (i < dataByYear.length) update(dataByYear[i++].values);
}, 500);
12. Label your data
Task extend your update pattern to the labels labels so they also update
13. Interaction
When entering or adding elements chain .on(EVENTNAME, callback)
. Similar to jQuery, this calls a function when an event happens.
D3 will call your callback function with the datum like you get in other accessor functions. Use d3.select(this)
to select the element that was triggered.
Some events:
- mouseenter
- mouseleave
- mouseover
- click
Demo: create a mouseover function for the circles
Task: make a replay “button” that triggers when you ’click’
it.
14. Add a path
Task: nest your data by country, then create a d3.line generator
Extra credit: animate the line into view
15. Transitions
Live coding: add transition to circles for position and radius
Task: add transition to text. Try out different easing patterns.
what's in the advanced class
- Voronoi
- Layouts (force, hierarchy)
- Geo tools
- Modules
- Behaviors (drag and zoom)
- Canvas
libraries and tools you may find useful
crowbar to download your chart as an SVG. You can then edit it using vector graphics software such as Adobe Illustrator.
d3-jetpack for convenience functions that will save you a lot of repetitive typing.
d3-legend to make convenient legends based on your scales.
Textures.js to use patterns in your visualizations.
Swoopy drag for interactive annotations.