Data Storytelling with Muze
By: Charts.Com Engineering
Tags: Data Vizualisation, Muze, D3js, Data Analysis, Data Stories

“Numbers have an important story to tell. They rely on you to give them a clear and convincing voice.”- Stephen Few

Often data is analyzed using spreadsheets or dashboards which gives an understanding of what the data is all about, but sometimes these methods fail to provide a relevant context as to why the data is the way it is. This is when concepts like storytelling help us to answer such contextual questions.

As an experiment, we tried to replicate a Data Story published by the Wall Street Journal which tracks the National Unemployment, job gains, and losses over the years. This data story also gives a detailed view of the job changes in various sectors through the periods of recession.

We had the following objectives while replicating the said story.

1. To replicate it as far as possible.

2. To write a developer-friendly reusable code with minimal complexity.

Check our version of story built using Muze here.

Obstacles faced:

Data Manipulation:

On selecting a filter (which in itself is a part of a broader category ie. gender, age, ethnicity, and education), the visualization that is generated has these actions/tasks.

- Calculate the y-axis range, considering the min and the max range of all the data fields

- Giving them color categorizations ie. black for Overall, blue for the Active filter and using grey to otherize all other filters from the same category.

These filters and conditions, aggregate and manipulate the data for every listed filter and its category. Emulating the same filter and applying changes to the chart can be a heavy task that can result in a laggy-jittery experience.

2. Layering the various charts component:

If we divide the chart into small components, we see colored bars(chart2) and colored points(chart1). When we hover over chart1, there is another set of black dots for depicting the recession and similarly on the chart2 when we click the Show recession checkbox, these tiny black squares appear on the blocks.

It was found out that implementing the exact same behavior ( ie. layering on top of one another ) is something very tedious and a majority of the available viz. libraries don’t support this in a very generic way. Either they provide definite charts types or pre-defined viz. to some extent.

3. Cross-interaction:

Since both the charts have the same data-source, hence selecting any active filter from the category-panel , triggers a change in the heatmap (chart2) and also adds an overlay comparison line to the trend (chart3).

Also, hovering on any data point in chart2 highlights the corresponding point on chart3 and vice versa. Creating such a smooth cross-interaction requires a lot of developer overhead that triggers complex calculations, data manipulations which can complicate any code.

How Muze overcomes these obstacles?

Data Handling: Muze recognizes DataModel as the first-class source of data. DataModel is a minimalistic, in-browser representation of tabular data, that supports relational algebra operators which enables you to run selection, projection, group, bin, join (and many more) operations on the data.

For example:

From the data, if we wanted to select the data points during a recession and then sort it based on the unemployment rates. All we need to do is:

let rootData= new DataModel(data, schema); // schema is a definition of the data fields /**

* selecting rows that satisfy the given condition and sorting them

* in ascending order of their unemployment rates

*/

let selectedData = rootData

.select(d => d.recession.value)

.sort([['unemp', 'ASC']]); /**

* Adding datamodel instance to our canvas

*/

canvas.data(selectedData);

2. Layering the various charts component: Muze provides an out of the box feature of atomic marks and composable layers. These can be used to create complex constructs. Each layer can be developed to house a different geometry or chart type coupled with the data source. Multiple layers can then be composed into a single view to create insightful visualizations. Taking the example below:

Composition Of Layers: Bar Layer and Point Layer

The visualization is added to the Muze canvas using simple steps as follows:

/**

* Adding two layers to our canvas: bar layer and point layer

*/ canvas.layers([{

mark: 'bar', // adding bars

encoding: {

y: 'month' // the field to be plotted in y axis

}

}, {

mark: 'point', // the point layer showing the recession data

encoding: {

y: 'month' // the field to be plotted in y axis

},

source: 'recessionDataModel' /* the datamodel instance that filters out the data, to show points only for recession and not the whole data */

}])

That’s how easy it is to compose different layers into one using Muze.

3. Cross-Interaction: An amazing feature provided by Muze is its cross-interactivity. Muze enables the user to develop almost any interaction between two charts and above all its as easy as:

/**

* canvasHeatmap is the muze canvas instance for chart2 and

* canvasLine is the muze canvas instance for chart3

*/

muze.ActionModel

.for(canvasHeatmap, canvasLine)

.enableCrossInteractivity();

The snippet above allowed us to interact between the chart2’s and chart3’s canvas instances, enabling smooth cross-interaction on hover.

You can find the final Data Story build with Muze here:

Other Features of Muze:

Muze can dynamically bind reactions to any kind of event to invoke elements like tooltips, selection box or to add layers dynamically (side-effects).

Muze provides APIs for changing almost anything and everything, the way you want, whether its the axes labels or the legend title , the padding between the layers, the stroke-width of the layer( eg: the selected line layer in the sample above).

or the , the padding between the layers, the of the layer( eg: the selected line layer in the sample above). Everything in Muze is javascript and CSS. All the APIs have simple js syntax and you can use the range of default themes or over-ride the CSS classes to create your own.

Lastly, any person with a basic knowledge of javascript cant just start with Muze, following the docs, and can create any visualization.

Wrapping it up:

Starting with the sample, using no libraries, made us understand the real-time problems. Hence, while implementing it using Muze, we realized how well it handles those problems. The experience is almost effortless and the result was an amazing viz with smooth interactions and very maintainable, easy to understand code.

Resources: