Creating Bulletcharts – getting serious
As you may have guessed from some previous posts I am very interested in bullet graphs. 🙂
Source : Stephen Few, perceptualedge.com
The reason is that this graph type does very well in giving more information and context to a single number. You see how it does versus another period, how well versus the target. And you can define ranges of good, average and bad.
This time around I wanted to tackle another challenge. Previously you needed a datasource or dataselection for each bullet graph. I wanted to automatically create a bullet graph for each row in the data source :
As you can see this worked out nicely. Also if you change the datasource the height of the charts will be recalculated and a new graph inserted (or an old one will be removed)
Getting the information
To really get going with the chart I first looked at d3js.org. There I found a great example to start with
http://bl.ocks.org/mbostock/4061961 from Mike Bostock.
a lot of the techniques I used in the Bullet Chart directly came from this source. Always as a first step with d3 go look for exampels. People have posted a lot of great visualizations.
Creating a graph per row
For each row in the dataset the SDK component creates a new SVG element
bulletgraphs.enter()
.append("svg")
.attr("height", chartHeight)
.attr("width", chartWidth)
The chart height is calculated by dividing the component height by the number of rows :
chartHeight = height / dataset.length;
If the number of graphs change the graphs that remain have to be resized. I do this with a transition. The effect is that you see the grapsh ‘making room’ for the new member:
bulletgraphs
.transition()
.delay(375)
.duration(375)
.attr("height", chartHeight)
.attr("width", chartWidth)
chartHeight is re-calculated. The .transition() method will create the transition from the old to the new settings.
Drawing each graph
To get to draw a chart with a single row I add a .each method to the bulletgraphs.enter();
.each(function(d, i) {
currentBulletRange = bulletRange.call(this, d, i).slice().sort(d3.descending);
currentBulletMeasure = bulletMeasure.call(this, d, i).slice().sort(d3.descending);
currentBulletMarker = bulletMarker.call(this, d, i).slice().sort(d3.descending);
d and I are references to the current row in the data. This relates to the current SVG element
using var thisGraph = d3.select(this);
you can continue drawing a graph using thisGraph as main variable and the above variables for data references with for example the scales :
var xScale = d3.scale.linear()
.domain([0, Math.max(currentBulletRange[0], currentBulletMeasure[0], currentBulletMarker[0])])
.range([0, 500]);
Conclusion
Using these techniques I was able to create a group of bullet graphs bases on one datasource. It is data bound but if you don’t have data assigned it will create fake data for prototyping purposes.
Next step for me is to dive deeper into the json data coming from the datasource. Working with the tuples.
On the 14th and 15th of april I will be attending the SDK course in Walldorf. Perhaps I will meet you there!
Say hello to Mustafa for me when you get to Walldorf! Wish I could go. Great post, also.
Hi Jeroen,
Yes, I'll be attending the same workshop. See you there.
Mustafa.
nice, see you there.
Hi Jeroen, thanks for sharing. It would be great if you could share the source code/files ?
Ryan