Adaptive Plots Using Epoch
Since my last post, things have been going well for Epoch, the real-time visualization library we launched in June. After the launch of the Github Pages project site, we saw a great deal of interest. The library reached #2 trending on the day of the launch and #10 over the course of the month. Even better, a number of great folks stepped up as collaborators and helped fix bugs and add features.
One of the features to come out of this creative frenzy was the idea of adaptive plots. As of the last version of Epoch (0.5.0), you could not go back and alter set options for a chart once you had set them. Take the “axes” option, for instance. If you were to create a chart that specified that only the left and bottom axes should be shown, then you’d have to recreate the plot and replace it if you decided later that you also wanted to show the right axis.
Introducing Adaptive Plots
After a lot of hard work, elbow grease, and some awesome advice from external contributor Tim Cooper, we are excited to introduce Epoch’s new suite of Adaptive Plots. Introduced in the most recent release (0.6.0), adaptive plots add a level of flexibility and interaction that was sorely missing in the library. In this post, we’ll talk about what this means, and how you can leverage the plots in your applications to create smooth, beautiful, and useful data visualizations.
First, it is important to note that in this post we are not referring to Adaptive Web Design but to the adaptability of components within those designs. To help guide us, as we often do in programming, let’s look at the right definition:
Adapt (n) - To adjust or modify fittingly.
Modern web applications are anything but cookiecutter. Responsive design dictates that pages must be visually fluid and perform well across multiple devices and platforms. To further complicate the issue, page elements must often change their visual properties based on asynchronous data and in reaction to chains of events.
From this perspective, a web application can be thought of as a kind of environment, containing an ecosystem of libraries and components. As the environment changes — sometimes rather quickly — components and libraries must be flexible and adapt to new circumstances. As the definition says, components must adjust or modify fittingly, otherwise it’s kaputz.
By building components, like Epoch’s charts, with adaptivity in mind, they become much more useful in various circumstances, and provide a level of interactivity that can add to the overall experience.
Our Approach To Making Components Adaptive
While there are many ways to go about making components adaptive, we took a three stage approach with Epoch:
There should be a plethora of options that change the structure of the chart.
Colors and styles for charts should follow a basic format, and the user should be guided through the use of themes and categories.
When a particular option or style is changed, charts should automatically transition into a new structure or style.
As of the last version, Epoch handled the first and second of these stages. Each of the charts had many individual and shared options that could change structural elements such as axes and ticks. Furthermore, styles for all of the charts (both Canvas and SVG) are controlled using CSS with a core theme of categorical colors to make the styles useful out of the box.
The third, handling transitions, are new with version 0.6.0. In the next section, we will detail the approach we took when implementing this functionality.
Handling Transitions
At the core of structural transition in Epoch is the .option
method. After the chart is constructed, it is used as a universal accessor/mutator for all chart options. The method has four overloaded variants based on call parameters, which are:
.option()
- Returns a deep copy of all the charts options.option(String key)
- Returns the options for a given key.option(String key, Object value)
- Sets the option with a given key and emits an option changed event.option(Object values)
- Given an object containing key-value pairs of option names to values this sets each individual chart option and emits option changed events for each.
The method is highly versatile and can be used in many contexts. The primary function, however, is to provide the application programmer with a good way of changing chart options and seeing the intended results. Per our definition above, this is covered by overload variants 3 and 4.
Since both of these methods emit events when an option is changed, subclasses can quickly and easily define listener callbacks to adjust the structure of the plot in response to changes. This is exactly how we go about implementing said transition in Epoch. It also has the added benefit of allowing the application using Epoch to listen in and react when the structural elements of a chart are mutated.
To get a feel for how this all comes together, let’s take a look at an example that uses the method to make a chart more interactive.
Example: Axes, Ticks, and Dimensions
Axes, ticks, and numbers are structural elements that guide viewers to a numerical understanding of a chart or plot. For example, the plot below shows the cache hit ratio over time for a fictional Fastly service:
While useful for seeing the overall trend of the ratio over time, it leaves out quite a few details. It is also hard to get a sense for where points on the right side of the chart fall in the range from 0% to 100% since the right axis is missing.
By making the chart adaptive with a small amount of interaction code, you can easily transition from a bird’s eye view to a more detailed view using the chart’s .option
method:
// 1. Define the chart
var chart = $('#my-chart').epoch({ ... });
// 2. Define the options we use to show the expanded plot
var expandOptions = {
height: 150,
axes: ['left', 'right', 'bottom'],
tickFormats: {
left: Epoch.Formats.percent,
right: Epoch.Formats.percent
},
ticks: { left: 5, right: 5 },
range: [0.75, 0.9]
};
// 3. Change the options in response to a click:
$('#expand-button').on('click', function(e) {
chart.option(expandOptions);
});
Fully implemented, it comes together like this:
By adding just a little bit of eventing, Epoch's option() function makes it pretty easy to adapt the chart depending on the context.
Just Getting Started
Epoch is still very young and there’s a lot of work to be done, but the immediate reaction and level of contribution from the community is a sign that we’re on to something really great.
For all of those who have starred the library on GitHub, thank you! For those who reached out to me personally with kind words and ideas, you’re great! But for those of you, like Tim, who’ve been in the trenches with me and actively contributing, you’re the best.
We’re just getting started, so keep checking in for new updates on the blog, new releases on GitHub, and new ideas in the issues.