The last two weeks we built up a few charts with Uber’s open-source library, React-vis, drawing on the City of New York’s Popular Baby Names data set. This week we’ll look at adding some animation to the charts to give users visual cues about changes in the data over time. By the end of this post, we’ll have a set of charts that can be filtered by ethnicity with animated transitions.
Before we get into any animations, we’ll first need to refactor the way we massage the CSV data into the format we expect for our charts. Currently, that all happens within the component constructor. Because we’ll need to call a lot of that same logic later when we want to filter values out, the first thing we’ll want to do is abstract the processing out to methods. We’ll still call those methods in the constructor, but we’ll also be able to call them when the filter changes without having to repeat the implementation.
We’ll also have to make some of our processing code a bit more dynamic. We’ve got some hard-coded values relating to the most popular baby names, but we’ll want to dynamically calculate those values based on a data set we pre-filter for ethnicity and pass in. In the spirit of wishful thinking, we can sketch out how we would ideally process the data:
calculateChartData(data) {
const totalBabiesByYear = this.getTotalBabiesByYear(data);
const top10BabyNames = this.getTopBabyNames(data, 10);
const namesWithData = this.getYearlyDataForNames(data, top10BabyNames);
return {
ethnicityFilter,
totalBabiesByYear,
namesWithData,
};
}
// We can then use this method in our constructor….
const newData = this.calculateChartData(data);
// … or later on when we want to filter
const newData = this.calculateChartData(data.filter((d) => d.ethnicity === someValue))
It doesn’t matter that these methods don’t yet exist—in fact, that’s the point. By imagining a clear way of interacting with data we can determine which abstractions need to be created. For example, we imagined a getTopBabyNames
function that takes a set of data and a number and will return that number of the most popular names. This imaginary API guides our actual implementation. I won’t go through the refactoring and implementation step-by-step, but you can see all the code on GitHub.
Now that we know we can filter data and regenerate data in the shape our charts expect, we can start to think about how we go about animating the charts. Luckily, the React-vis library has a consistent API that lets us add a single property to any series to enable animated transitions: animation
. We can add the animation
property to each of our LineMarkSeries
components and to our VerticalBarSeries
component as well:
<LineMarkSeries
animation
onValueMouseOver={(d) => this.setState({hoverData: d})}
key={name}
data={data}
/>
// ...and
<VerticalBarSeries
animation
data={totalBabiesByYear}
/>
When the data we pass in changes, React-vis will automatically take care of the animations for us using the React-motion animation library. The animations can be enabled in their simplest form using the animation
attribute as shown above, but two other uses are available as well, both of which customize the animation.
Instead of simply including the animation
attribute, you can set it to a string value that is one of the following values: noWobble
, gentle
, wobbly
, or stiff
. These values act as presets for the animation; the best way to understand them is to see them in action. The React-vis documentation site has a live demo that demonstrates each of these presets.
The third way of enabling animations involves setting the animation
attribute to an object with damping
and stiffness
properties and an optional nonAnimatedProps
key. This method of enabling animations gives you direct access to React-motion and requires a deeper dive into understanding how changes in those values impact the animation.
Simply adding the animation
attribute provided most everything we needed for adding some action to our charts. There is some unexpected behavior when certain transitions in the data occur, which results in the effect of no animation at all. The underlying cause is that the data before and the data after the transition have no overlapping values, which means we can’t interpolate between them. This makes sense from a data perspective, but it looks strange from the user’s perspective.
Little issues here and there with React-vis are vastly overshadowed by the ease with which you can create interactive, animated charts. I’ve used the library on heavy-duty interactive dashboards in the past and I will likely reach for it again in the future. Do you know of any tricks or tips when using React-vis? Do you have a killer alternative? Continue the conversation on Twitter: @freethejazz