I am using d3.js, and I'm working on a brushed area chart by modifying this example. In addition to the x-axis changing based on the brush, I'd like chart's y-axis to be redrawn, based on the y-values of the data that fall within the brush (similar to the behavior of a Google Finance chart).
I have gotten the functionality working, but only in a way that enables the brush to be drawn in both x- and y-space. I did this by first adding a y scale to the brush
variable:
var brush = d3.svg.brush()
.x(x2)
.y(y2)
.on("brush", brush);
This makes brush.extent()
return the following multi-dimensional array: [ [x0, y0], [x1, y1] ]
. I then use this data in the brush()
function to redefine the x- and y- domain for the focus chart:
function brush() {
var extent = brush.extent();
x.domain(brush.empty() ? x2.domain() : [ extent[0][0], extent[1][0] ]);
y.domain(brush.empty() ? y2.domain() : [ extent[0][1], extent[1][1] ]);
focus.select("path").attr("d", area);
focus.select(".x.axis").call(xAxis);
focus.select(".y.axis").call(yAxis);
}
This works, but by defining the y scale in the brush variable, the user can now drag 'boxes' in the focus chart, rather than only being able to drag west to east, as in the original chart.
Essentially, my question is: how do I get the range of values that fall within a brush's area, rather than the range of the brush's area itself? Is this even possible?
d3's brush documentation is here.
I came up with a solution.
I used the brush-filtered x.domain to filter down my original data set. This new filtered data set has only the values that fall within the brush:
// Use x.domain to filter the data, then find the max and min duration of this new set, then set y.domain to that
x.domain(brush.empty() ? x2.domain() : brush.extent());
var dataFiltered = data.filter(function(d, i) {
if ( (d.date >= x.domain()[0]) && (d.date <= x.domain()[1]) ) {
return d.duration;
}
})
y.domain([0, d3.max(dataFiltered.map(function(d) { return d.duration; }))]);
Finally, be sure to redraw the y-axis as well as the x-axis:
focus.select("path").attr("d", area);
focus.select(".x.axis").call(xAxis);
focus.select(".y.axis").call(yAxis);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With