Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding Error Bars to Grouped Bar Chart with D3.js

First I would like to find out if anyone knows of a D3 example showing grouped bar charts with error bars? The closest things I have found are:

http://tenxer.github.io/xcharts/examples/ (Example Custom Vis Type: Error Bars) http://bl.ocks.org/chrisbrich/5044999 (error bars for points)

I have a working example of a grouped bar chart and I would like to add an error bar to each bar in the graph showing the MOE. What steps would I need to take to accomplish this? How would I calculate the position of the line? This is what I think needs to be done, please help me fill in the steps I need to take.

  1. Create a SVG line

  2. Calculate the ymin and ymax of the line by taking d3.max of d.value + the MOE and d3.max of d.value - MOE

  3. Append

This doesn't work but is it on the right track?

var line = d3.svg.line()
    .x(function(d) {return x(d.state); })
    .y0(function(d) {return y(d.value - d.moe); })
    .y1(function(d) {return y(d.value + d.moe); })
    .interpolate("linear");

var errorBarSVG = d3.select("body").append("svg")

var errorBar = errorBarSVG.append("path")
    .attr("d", line(data))
    .attr("stroke", "red")
    .attr("stroke-width", 1.5);
like image 425
bailey Avatar asked Mar 24 '14 20:03

bailey


1 Answers

If you just want straight-line error bars (without top and bottom horizontal lines), yes, you could use an area or line generator (only area generators have y0/y1 methods).

However, you wouldn't call the path generator on all the data at once, you would have to create a selection of paths joined to the data, and then pass the data object as a one (area generator) or two-point (line generator) array to the generator function.

This should work:

var errorBarArea = d3.svg.area()
    .x(function(d) {return x(d.state); })
    .y0(function(d) {return y(d.value - d.moe); })
    .y1(function(d) {return y(d.value + d.moe); })
    .interpolate("linear");

var errorBarSVG = d3.select("body").append("svg")

var errorBars = errorBarSVG.selectAll("path")
         .data(data);

errorBars.enter().append("path");

errorBars.attr("d", function(d){return errorBarArea([d]);}) 
             //turn the data into a one-element array 
             //and pass it to the area function
    .attr("stroke", "red")
    .attr("stroke-width", 1.5);

This will create a zero-width area path for each bar, connecting the +/- points in a straight line.

If you used a line generator function, you would have to calculate the top and bottom Y-values when you turned the data into an array:

errorBars.attr("d", function(d){
                  return errorBarLine([{x:d.x, y:d.value - d.moe},
                                       {x:d.x, y:d.value + d.moe}]);
               })

Alternately, you could use d3.svg.diagonal to create straight-line error bars. A diagonal function is specifically designed to take a single data object and extract start and end line points from it; you would then have to customize the source and target accessor functions to create objects like the ones in the code sample above.

However, if you want a custom-shaped error bar with horizontal top and bottom lines, you'll need to write your own function to create the path "d" attribute based on a data object. I discuss doing that in this answer, for an error bar the shape would actually be much simpler, since it's all just straight lines. You might find this tutorial on the path directions syntax a useful reference.

Finally, you might also want to re-write your bar chart code so that each bar is represented by a <g> element joined to the data, and then you append both the rectangle and the error bar path within it without calculating separate data joins.

like image 192
AmeliaBR Avatar answered Sep 25 '22 01:09

AmeliaBR