Skip to content

Instantly share code, notes, and snippets.

@chrisbrich
Forked from natemiller/error.data.json
Last active December 14, 2015 10:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chrisbrich/0759cd5d7cab4db4610b to your computer and use it in GitHub Desktop.
Save chrisbrich/0759cd5d7cab4db4610b to your computer and use it in GitHub Desktop.
[
{
"x": 10,
"y": 50,
"s": 6
},
{
"x": 10,
"y": 35,
"s": 4
},
{
"x": 15,
"y": 70,
"s": 10
},
{
"x": 20,
"y": 20,
"s": 8
},
{
"x": 25,
"y": 55,
"s": 10
},
{
"x": 30,
"y": 30,
"s": 2
}
]
function errorBar(){
//TODO
//- Think of an additional way to represent error bars, maybe just the orthognal case (i.e. use width not height)
//- Does ordinal scale even make sense here? May need to remove.
var size = 5,
xError = function(d) {return exists(d[0].s);},
yError = function(d) {return exists(d[1].s);},
errormarker = null, //points will inherit from g.dataset
xValue = function(d) {return (d[0].x === undefined)?d[0]:d[0].x;},
yValue = function(d) {return (d[1].x === undefined)?d[1]:d[1].x;},
oldXScale, //probably can give these smarter defaults
oldYScale,
xScale,
yScale;
function marks(datapoints){
datapoints.each(function(d,i) {
var g = d3.select(this),
//Use color/errormarker defined.
errormarker = errormarker || exists(g.datum().errormarker);
//Error
var err = g.selectAll(".err")
.data(function(d){return (!(xError(d) === null) || !(yError(d) === null))?[d]:[]},xValue),
errEnter,
errExit,
errUpdate;
switch (errormarker) {
case null: {
errEnter = err.enter().append("path").attr("class","err")
errExit = d3.transition(err.exit()).remove(),
errUpdate = d3.transition(err),
errTransform = function(selection,a,b){
selection.attr("d", function(d){
var h = (yError(d) === null)?[-size,size]:[(b(yValue(d) - yError(d)) - b(yValue(d))),(b(yValue(d) + yError(d)) - b(yValue(d)))],
w = (xError(d) === null)?[-size,size]:[(a(xValue(d) - xError(d)) - a(xValue(d))),(a(xValue(d) + xError(d)) - a(xValue(d)))];
return "M 0," + h[0] +
" L 0," + h[1] +
" M " + w[0] + "," + h[1] +
" L " + w[1] + "," + h[1] +
" M " + w[0] + "," + h[0] +
" L " + w[1] + "," + h[0]
})};;
break;
}
case errormarker: { //Normalize custom errors to 1px in their definition. Will be scaled back up here by size.
err.append("use").attr("class",marker + " err");
err.selectAll("use").attr("xlink:href","#" + marker)
.attr("transform",function(d){return "scale(" + xError(d) + "," + yError(d) + ")"});
break;
}
};
// For quantitative scales:
// - enter new ticks from the old scale
// - exit old ticks to the new scale
if (xScale.ticks) {
errEnter.call(errTransform, oldXScale, oldYScale);
errUpdate.call(errTransform, xScale, yScale);
errExit.call(errTransform, xScale, yScale);
}
// For ordinal scales:
// - any entering ticks are undefined in the old scale
// - any exiting ticks are undefined in the new scale
// Therefore, we only need to transition updating ticks.
else {
var dx = xScale.rangeBand() / 2, x = function(d) { return xScale(d) + dx; };
var dy = yScale.rangeBand() / 2, y = function(d) { return yScale(d) + dy; };
errEnter.call(errTransform, x, y);
errUpdate.call(errTransform, x, y);
}
});
}
marks.size = function(_) {
if (!arguments.length) return size;
size = _;
return marks;
};
marks.xError = function(_) {
if (!arguments.length) return xError;
xError = _;
return marks;
};
marks.yError = function(_) {
if (!arguments.length) return yError;
yError = _;
return marks;
};
marks.oldXScale = function(_) {
if (!arguments.length) return oldXScale;
oldXScale = _;
return marks;
};
marks.oldYScale = function(_) {
if (!arguments.length) return oldYScale;
oldYScale = _;
return marks;
};
marks.xScale = function(_) {
if (!arguments.length) return xScale;
xScale = _;
return marks;
};
marks.yScale = function(_) {
if (!arguments.length) return yScale;
yScale = _;
return marks;
};
marks.xValue = function(_) {
if (!arguments.length) return xValue;
xValue = _;
return marks;
};
marks.yValue = function(_) {
if (!arguments.length) return yValue;
yValue = _;
return marks;
};
marks.errormarker = function(_) {
if (!arguments.length) return errormarker;
errormarker = _;
return marks;
};
return marks;
};
function exists(a){
return (a === undefined)?null:a;
};
<!DOCTYPE html>
<meta charset="utf-8">
<style>
svg {
font: 10px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
path {
stroke-width: 1.5px;
stroke: blue;
}
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script src="errorbar.js"></script>
<script>
var margin = {top: 10, right: 150, bottom: 100, left: 40},
size = 5,
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
x = d3.scale.linear().range([0, width]),
y = d3.scale.linear().range([height, 0]),
xAxis = d3.svg.axis().scale(x).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left"),
eb = errorBar()
.oldXScale(x)
.xScale(x)
.oldYScale(y)
.yScale(y)
.yValue(function(d){return d.y})
.xValue(function(d){return d.x})
.xError(function(d){return null})
.yError(function(d){return d.s});
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("class","container")
.attr("transform", "translate(" + margin.bottom + "," + margin.top + ")");
d3.json("error.data.json", function(error,data) {
x.domain([0,d3.max(data.map(function(d) { return d.x; }))]);
y.domain([0,d3.max(data.map(function(d) { return d.y; }))]);
var d = svg.selectAll("g")
.data(data),
dEnter = d.enter()
.append("g")
.attr("transform", function(d) {return "translate("+ x(d.x) +","+ y(d.y) +")"})
.attr("fill","blue");
dEnter.append("circle")
.attr("r",5);
dEnter.call(eb);
svg.append("g")
.attr("class","x axis")
.attr("transform","translate(0," + y.range()[0] + ")")
.call(xAxis);
svg.append("g")
.attr("class","y axis")
.attr("transform","translate(" + x.range()[0] + ",0)")
.call(yAxis);
});
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment