Comparison charts, as their name suggests, are great for comparing the percentage price change of multiple stocks in time. In this post, we’ll make one using D3.
This post continues a series of posts on making financial charts using D3. We’ve seen how to use the pattern of reusable components to make simple OHLC and candlestick charts with annotations, technical studies and interactive navigators, as well as how to boost performance when panning and zooming.
Here’s what we’ll be making.
Comparison Series Component
First, a word about data. We’ll assume that our chart data is an array of objects, each with
data properties. The
data property will be an array of price objects with
close properties, sorted by
date. Our component will plot the percentage change of the
close prices for each named series.
We’ll take Mike Bostock’s Multi-Series Line Chart as a starting point. It plots a line for each data series, each with a colour given from a
d3.scale.category10 ordinal scale that maps series names to colours. We’ll package the line drawing and colour mapping into a component using the usual D3 component convention. Our component will also need to calculate the percentage change of prices from an initial date (the leftmost date on the x axis), and update the y scale to reflect the minimum and maximum visible percentage changes.
Below is an outline of the comparison series component. We’ll create/update the lines and update the yScale domain in the
comparison function. The lines themselves will be drawn using the
The standard way to draw gridlines with D3 is by obtaining ticks from a scale using
scale.ticks(), and drawing lines using the tick values. Guess what? We can encapsulate this as a component!
Putting it Together
One of the biggest strengths of the component pattern is the ease in which we can add new components to an existing chart, or swap out components of an existing chart to make a new one. Suppose we had a chart set up with margins, scales, axes, a plot area, and a series (like the OHLC chart from this post). Then we can build a comparison chart with gridlines using our new components very easily.
First we make instances of our components.
Then we add them to the preexisting plot area:
We’ll get zooming and panning working by using a D3 zoom behaviour. We’ll implement semantic zooming, and we’ll use Andy Aiken’s trick of limiting the panning extent by compensating for any overshoot of the zoom behaviour’s x translation. Our
zoomed listener looks like this:
Finally, we need to format the y axis to show a percentage.
In an earlier post, we discussed the differences between semantic zooming (redraw an element to reflect new scale domains) and geometric zooming (transform the element to where it should be given the new scale domains). We saw that geometric zooming generally performed better, with some caveats.
A disadvantage of geometric zooming was the relative complexity of the implementation compared to semantic zooming with features like an automatically updating y scale. This is true for our comparison series component as well. On zoom, we can’t just apply a single transformation to the comparison series element - the series lines need to be moved independently to their new positions.
A solution is to have the component itself implement geometric zooming of the series lines, by internally computing a transformation for each line. Each transformation is the composition of 2 transformations - one to move the line to reflect the new initial date on the x axis, and one to reflect the updated y scale domain.