So I created an error bar function for this, the value of isError in the array gives you the size of the error bar at each point:
<div id="chart2" style="height: 700px; width: 900px; margin-left:auto; margin-right:auto;">
<svg id="chart2" style="height: 700px; width: 900px;"></svg>
</div>
<script src="nv.d3.js"></script>
<script>
var charts;
nv.addGraph(Bodyweight(this));
//nv.addGraph(function() {
function Bodyweight(c) {
charts = nv.models.lineChart()
.forceY([0])
.options({
margin: {left: 100, bottom: 100},
x: function(d,i) { return i},
showXAxis: true,
showYAxis: true,
transitionDuration: 250
})
;
charts.useInteractiveGuideline(true);
var labelValues2 = ['20', '22', '24', '26', '28', '30', '32', '34', '36', '38', '40', '42', '44', '46', '48', '50'];
charts.xAxis
.axisLabel("Time (Weeks)")
//.axisLabelDistance(120)
.tickFormat(function(d){
return labelValues2[d];
});
charts.yAxis
.axisLabel('Bodyweight (g)')
.tickFormat(d3.format(',.1f'))
//.scale().domain([0, maxValue])
;
d3.select('#chart2 svg')
.datum(sinAndCos2())
.call(charts);
nv.utils.windowResize(function() { d3.select('#chart2 svg').call(charts) });
charts.dispatch.on('stateChange', function(e) { nv.log('New State:', JSON.stringify(e)); });
return charts;
};
function sinAndCos2() {
var wt_sd = [{x: 1, y: 29.7, isError: 0.8},{x: 2, y: 31.0, isError: 0.9},{x: 3, y: 30.7, isError: 1.0},{x: 4, y: 31.2, isError: 1.0},{x: 5, y: 32.3, isError: 1.2},{x: 6, y: 32.4, isError: 1.2},{x: 7, y: 33.3, isError: 1.3},{x: 8, y: 33.9, isError: 1.3},{x: 9, y: 35.3, isError: 1.3},{x: 10, y: 36.7, isError: 1.4},{x: 11, y: 36.2, isError: 1.4},{x: 12, y: 37.1, isError: 1.5},{x: 13, y: 38.3, isError: 1.6},{x: 14, y: 39.3, isError: 1.5},{x: 15, y: 40.0, isError: 1.6},{x: 16, y: 40.9, isError: 1.6}],
wt_hfd = [{x: 1, y: 29.7, isError: 0.6},{x: 2, y: 32.5, isError: 0.8},{x: 3, y: 34.8, isError: 0.9},{x: 4, y: 36.8, isError: 1.0},{x: 5, y: 38.7, isError: 1.1},{x: 6, y: 40.9, isError: 1.3},{x: 7, y: 43.0, isError: 1.5},{x: 8, y: 44.6, isError: 1.8},{x: 9, y: 46.2, isError: 1.7},{x: 10, y: 49.0, isError: 1.5},{x: 11, y: 50.3, isError: 1.5},{x: 12, y: 52.1, isError: 1.3},{x: 13, y: 52.2, isError: 1.3},{x: 14, y: 53.5, isError: 1.2},{x: 15, y: 53.8, isError: 1.2},{x: 16, y: 53.1, isError: 1.5}],
wt_cr = [{x: 1, y: 28.2, isError: 0.4},{x: 2, y: 25.5, isError: 0.3},{x: 3, y: 23.1, isError: 0.2},{x: 4, y: 23.2, isError: 0.2},{x: 5, y: 23.4, isError: 0.3},{x: 6, y: 22.5, isError: 0.3},{x: 7, y: 22.5, isError: 0.3},{x: 8, y: 23.0, isError: 0.3},{x: 9, y: 22.1, isError: 0.3},{x: 10, y: 22.4, isError: 0.3},{x: 11, y: 22.5, isError: 0.2},{x: 12, y: 23.1, isError: 0.3},{x: 13, y: 23.5, isError: 0.2},{x: 14, y: 23.6, isError: 0.3},{x: 15, y: 23.7, isError: 0.3},{x: 16, y: 23.8, isError: 0.2}],
wt_resv = [{x: 1, y: 27.6, isError: 0.3},{x: 2, y: 28.0, isError: 0.4},{x: 3, y: 27.8, isError: 0.4},{x: 4, y: 28.6, isError: 0.5},{x: 5, y: 29.2, isError: 0.5},{x: 6, y: 29.3, isError: 0.6},{x: 7, y: 29.8, isError: 0.6},{x: 8, y: 30.3, isError: 0.6},{x: 9, y: 31.3, isError: 0.8},{x: 10, y: 32.5, isError: 0.9},{x: 11, y: 32.5, isError: 1.0},{x: 12, y: 33.7, isError: 1.1},{x: 13, y: 34.5, isError: 1.1},{x: 14, y: 34.8, isError: 1.1},{x: 15, y: 34.9, isError: 1.2},{x: 16, y: 34.8, isError: 1.2}],
csb_sd = [{x: 1, y: 27.1, isError: 0.8},{x: 2, y: 27.1, isError: 0.6},{x: 3, y: 26.9, isError: 0.6},{x: 4, y: 27.7, isError: 0.8},{x: 5, y: 29.0, isError: 1.2},{x: 6, y: 29.1, isError: 1.0},{x: 7, y: 29.4, isError: 1.1},{x: 8, y: 30.0, isError: 1.2},{x: 9, y: 30.8, isError: 1.3},{x: 10, y: 31.7, isError: 1.5},{x: 11, y: 32.2, isError: 1.6},{x: 12, y: 31.9, isError: 1.4},{x: 13, y: 32.1, isError: 1.3},{x: 14, y: 31.9, isError: 1.3},{x: 15, y: 31.8, isError: 1.5},{x: 16, y: 31.8, isError: 1.5}],
csb_hfd = [{x: 1, y: 28.1, isError: 0.9},{x: 2, y: 29.4, isError: 1.1},{x: 3, y: 31.6, isError: 1.3},{x: 4, y: 34.1, isError: 1.6},{x: 5, y: 34.2, isError: 1.4},{x: 6, y: 36.3, isError: 1.5},{x: 7, y: 37.7, isError: 1.6},{x: 8, y: 40.1, isError: 1.6},{x: 9, y: 41.0, isError: 1.6},{x: 10, y: 42.8, isError: 1.6},{x: 11, y: 44.1, isError: 1.5},{x: 12, y: 44.2, isError: 1.6},{x: 13, y: 44.9, isError: 1.6},{x: 14, y: 44.8, isError: 1.6},{x: 15, y: 43.8, isError: 1.6},{x: 16, y: 44.0, isError: 1.7}],
csb_cr = [{x: 1, y: 26.1, isError: 0.8},{x: 2, y: 22.3, isError: 0.6},{x: 3, y: 20.3, isError: 0.3},{x: 4, y: 20.3, isError: 0.3},{x: 5, y: 19.8, isError: 0.3},{x: 6, y: 20.3, isError: 0.4},{x: 7, y: 19.8, isError: 0.3},{x: 8, y: 20.2, isError: 0.2},{x: 9, y: 20.3, isError: 0.2},{x: 10, y: 19.8, isError: 0.3},{x: 11, y: 20.1, isError: 0.3},{x: 12, y: 19.9, isError: 0.2},{x: 13, y: 19.7, isError: 0.4},{x: 14, y: 20.0, isError: 0.3},{x: 15, y: 20.0, isError: 0.3},{x: 16, y: 19.2, isError: 0.3}],
csb_resv = [{x: 1, y: 25.4, isError: 0.4},{x: 2, y: 26.2, isError: 1.0},{x: 3, y: 25.3, isError: 0.5},{x: 4, y: 25.8, isError: 0.6},{x: 5, y: 26.6, isError: 0.7},{x: 6, y: 27.5, isError: 0.8},{x: 7, y: 28.3, isError: 0.9},{x: 8, y: 29.3, isError: 1.1},{x: 9, y: 29.6, isError: 1.1},{x: 10, y: 30.6, isError: 1.3},{x: 11, y: 31.2, isError: 1.3},{x: 12, y: 31.9, isError: 1.2},{x: 13, y: 31.5, isError: 1.2},{x: 14, y: 31.7, isError: 1.2},{x: 15, y: 31.3, isError: 1.1},{x: 16, y: 31.4, isError: 1.2}]
;
return [
{
//area: true,
values: wt_sd,
key: "WT SD",
color: "#FF0000",
isError: true,
isFull: true
},
{
values: wt_hfd,
key: "WT HFD",
color: "#0066FF",
isError: true,
isFull: true
},
{
values: wt_cr,
key: "WT CR",
color: "#33CC33",
isError: true,
isFull: true
},
{
values: wt_resv,
key: "WT Resv",
color: "#CC00FF",
isError: true,
isFull: true
},
{
//area: true,
values: csb_sd,
key: "Csb SD",
color: "#FF0000",
isDashed: true,
isError: true,
isFull: false
},
{
values: csb_hfd,
key: "Csb HFD",
color: "#0066FF",
isDashed: true,
isError: true,
isFull: false
},
{
values: csb_cr,
key: "Csb CR",
color: "#33CC33",
isDashed: true,
isError: true,
isFull: false
},
{
values: csb_resv,
key: "Csb Resv",
color: "#CC00FF",
isDashed: true,
isError: true,
isFull: false
}
];
}
</script>
And here is the updated chart() function from nv.d3.js that you can copy paste on top of the old chart(). It also adds the option of using dashed lines if you have multiple groups that needs to be better separated;
function chart(selection) {
selection.each(function(data) {
var availableWidth = width - margin.left - margin.right,
availableHeight = height - margin.top - margin.bottom,
container = d3.select(this);
//------------------------------------------------------------
// Setup Scales
x = scatter.xScale();
y = scatter.yScale();
x0 = x0 || x;
y0 = y0 || y;
//------------------------------------------------------------
//alert(y0);
//------------------------------------------------------------
// Setup containers and skeleton of chart
var wrap = container.selectAll('g.nv-wrap.nv-line').data([data]);
var wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-line');
var defsEnter = wrapEnter.append('defs');
var gEnter = wrapEnter.append('g');
var g = wrap.select('g')
gEnter.append('g').attr('class', 'nv-groups');
gEnter.append('g').attr('class', 'nv-scatterWrap');
wrap.attr('transform', 'translate(' + margin.left + ',' + margin.top + ')');
//------------------------------------------------------------
scatter
.width(availableWidth)
.height(availableHeight)
//alert(scatter.height(availableHeight));
var scatterWrap = wrap.select('.nv-scatterWrap');
//.datum(data); // Data automatically trickles down from the wrap
scatterWrap.transition().call(scatter);
defsEnter.append('clipPath')
.attr('id', 'nv-edge-clip-' + scatter.id())
.append('rect');
wrap.select('#nv-edge-clip-' + scatter.id() + ' rect')
.attr('width', availableWidth)
.attr('height', availableHeight);
g .attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : '');
scatterWrap
.attr('clip-path', clipEdge ? 'url(#nv-edge-clip-' + scatter.id() + ')' : '');
var groups = wrap.select('.nv-groups').selectAll('.nv-group')
.data(function(d) { return d }, function(d) { return d.key });
groups.enter().append('g')
.style('stroke-opacity', 1e-6)
.style('fill-opacity', 1e-6);
groups.exit()
.transition()
.style('stroke-opacity', 1e-6)
.style('fill-opacity', 1e-6)
.remove();
groups
.attr('class', function(d,i) { return 'nv-group nv-series-' + i })
.classed('hover', function(d) { return d.hover })
.style('fill', function(d,i){ return color(d, i) })
.style('stroke', function(d,i){ return color(d, i)});
groups
.transition()
.style('stroke-opacity', 1)
.style('fill-opacity', .5);
var areaPaths = groups.selectAll('path.nv-area').data(function(d) { return d.isArea ? [d] : [] }); // this is done differently than lines because I need to check if series is an area
areaPaths.enter().append('path')
.attr('class', 'nv-area')
.attr('d', function(d) {
return d3.svg.area()
.interpolate(interpolate)
.defined(defined)
.x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) })
.y0(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) })
.y1(function(d,i) { return y0( y.domain()[0] <= 0 ? y.domain()[1] >= 0 ? 0 : y.domain()[1] : y.domain()[0] ) })
//.y1(function(d,i) { return y0(0) }) //assuming 0 is within y domain.. may need to tweak this
.apply(this, [d.values])
});
groups.exit().selectAll('path.nv-area')
.remove();
areaPaths
.transition()
.attr('d', function(d) {
return d3.svg.area()
.interpolate(interpolate)
.defined(defined)
.x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
.y0(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) })
.y1(function(d,i) { return y( y.domain()[0] <= 0 ? y.domain()[1] >= 0 ? 0 : y.domain()[1] : y.domain()[0] ) })
//.y1(function(d,i) { return y0(0) }) //assuming 0 is within y domain.. may need to tweak this
.apply(this, [d.values])
});
var YcorMax=y.domain()[1];
var errorPaths = groups.selectAll('path.nv-error').data(function(d) { return d.isError ? [d] : [] });
errorPaths.enter().append('path')
.attr('class', 'nv-error')
.attr('d', function(d) {
return d3.svg.area()
.interpolate(interpolate)
.defined(defined)
.x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) })
.y0(function(d,i) {
var ez=Getez(d,i);
var z=nv.utils.NaNtoZero(y(getY(d,i)));
return z-((ez/YcorMax)*height);})
.y1(function(d,i) {
var ez=Getez(d,i);
var z=nv.utils.NaNtoZero(y(getY(d,i)));
return z+((ez/YcorMax)*height);})
.apply(this, [d.values])
}).style("stroke-width", ("1px")).style('fill-opacity', .2).style('stroke-opacity', .5);
groups.exit().selectAll('path.nv-error')
.remove();
errorPaths
.transition()
.attr('d', function(d) {
return d3.svg.area()
.interpolate(interpolate)
.defined(defined)
.x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
.y0(function(d,i) {
var ez=Getez(d,i);
var z=nv.utils.NaNtoZero(y(getY(d,i)));
return z-((ez/YcorMax)*height);})
.y1(function(d,i) {
var ez=Getez(d,i);
var z=nv.utils.NaNtoZero(y(getY(d,i)));
return z+((ez/YcorMax)*height);})
.apply(this, [d.values])
});
/////
var linePaths = groups.selectAll('path.nv-line')
// .data(function(d) { return [d.values] });
.data(function (d) { return d.isDashed ? [] : [d.values] });
linePaths.enter().append('path')
.attr('class', 'nv-line')
.attr('d',
d3.svg.line()
.interpolate(interpolate)
.defined(defined)
.x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) })
.y(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) })
).style("stroke-width", ("4px"));
// );
groups.exit().selectAll('path.nv-line')
.transition()
.attr('d',
d3.svg.line()
.interpolate(interpolate)
.defined(defined)
.x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
.y(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) })
);
linePaths
.transition()
.attr('d',
d3.svg.line()
.interpolate(interpolate)
.defined(defined)
.x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
.y(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) })
);
var dashedLinePaths = groups.selectAll('path.nv-line')
.data(function (d) { return d.isDashed ? [d.values] : [] });
dashedLinePaths.enter().append('path')
.attr('class', 'nv-line')
.attr('d',
d3.svg.line()
.interpolate(interpolate)
.defined(defined)
.x(function(d,i) { return nv.utils.NaNtoZero(x0(getX(d,i))) })
.y(function(d,i) { return nv.utils.NaNtoZero(y0(getY(d,i))) })
).style("stroke-dasharray", ("10, 10")).style("stroke-width", ("4px"));
//).style("stroke-dasharray", ("10, 10"));
dashedLinePaths
.transition()
.attr('d',
d3.svg.line()
.interpolate(interpolate)
.defined(defined)
.x(function(d,i) { return nv.utils.NaNtoZero(x(getX(d,i))) })
.y(function(d,i) { return nv.utils.NaNtoZero(y(getY(d,i))) })
);
//store old scales for use in transitions on update
x0 = x.copy();
y0 = y.copy();
});
return chart;
}