Zoom example with multiple lines

1,828 views
Skip to first unread message

Giorgos Eracleous

unread,
Feb 28, 2012, 3:20:49 PM2/28/12
to d3-js
Hey,

I am trying to extend the zoom example so that I can put multiple
lines on the plot. I managed to put
the lines but when I am selecting the are to zoom in only one of the
two lines is really affected.

Here's my code

<script src="d3/d3.v2.js"></script>
<script>

var margin = {top: 10, right: 10, bottom: 100, left: 40},
margin2 = {top: 430, right: 10, bottom: 20, left: 40},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom,
height2 = 500 - margin2.top - margin2.bottom;

var formatDate = d3.time.format("%b %Y");

var x = d3.time.scale().range([0, width]),
x2 = d3.time.scale().range([0, width]),
y = d3.scale.linear().range([height, 0]),
y2 = d3.scale.linear().range([height2, 0]);

var xAxis = d3.svg.axis().scale(x).orient("bottom"),
xAxis2 = d3.svg.axis().scale(x2).orient("bottom"),
yAxis = d3.svg.axis().scale(y).orient("left");

var brush = d3.svg.brush()
.x(x2)
.on("brush", brush);

var area = d3.svg.line()
.x(function(d) { return x(d.date); })
.y(function(d) { return y(d.price); })
.interpolate("monotone");

var area2 = d3.svg.line()
.x(function(d) { return x2(d.date); })
.y(function(d) { return y2(d.price); })
.interpolate("monotone");

var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom);

svg.append("defs").append("clipPath")
.attr("id", "clip")
.append("rect")
.attr("width", width)
.attr("height", height);

var focus = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top +
")");

var context = svg.append("g")
.attr("transform", "translate(" + margin2.left + "," + margin2.top
+ ")");

for (var i=5; i<7; i++){

d3.csv("sp"+i+"00.csv", function(data) {

data.forEach(function(d) {
d.date = formatDate.parse(d.date);
d.price = +d.price;
});

//Sets the x domain to be equal to the width of the extent
x.domain(d3.extent(data.map(function(d) { return d.date; })));
y.domain([0, d3.max(data.map(function(d) { return d.price; }))]);
x2.domain(x.domain());
y2.domain(y.domain());

//Appends the large chart
focus.append("svg:path")
.data([data])
.attr("clip-path", "url(#clip)")
.attr("d", area)
.attr("stroke", "red");

//Appends the x axis
focus.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height + ")")
.call(xAxis);

//Appends the y axis
focus.append("g")
.attr("class", "y axis")
.call(yAxis);

//Appends the small chart
context.append("path")
.data([data])
.attr("d", area2)
.attr("stroke", "red");

//Appends the x axis of the small chart
context.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height2 + ")")
.call(xAxis2);

//Appends the brush of the small chart
context.append("g")
.attr("class", "x brush")
.call(brush)
.selectAll("rect")
.attr("y", -6)
.attr("height", height2);
});
}

function brush() {
x.domain(brush.empty() ? x2.domain() : brush.extent());
focus.select("path").attr("d", area);
focus.select(".x.axis").call(xAxis);
}

</script>

Jason Davies

unread,
Mar 2, 2012, 6:57:56 PM3/2/12
to d3...@googlegroups.com
On Tue, Feb 28, 2012 at 12:20:49PM -0800, Giorgos Eracleous wrote:

> function brush() {
> x.domain(brush.empty() ? x2.domain() : brush.extent());
> focus.select("path").attr("d", area);

This is where your problem is. Firstly, focus.select("path") simply
selects the first <path> child of focus. You want to select more than
one path. However, focus.selectAll("path") will select all <path>
children, including those in the axes. So you'll want to restrict the
selection to the large line paths. To do this, simply give them a class
when they are added e.g.

// Appends the large chart
focus.append("path")
.data([data])
.attr("class", "large")
// …

Then updating the paths will be:

focus.selectAll("path.large").attr("d", area);

--
Jason Davies, http://www.jasondavies.com/

--

unread,
Mar 2, 2012, 7:30:54 PM3/2/12
to d3...@googlegroups.com
Great thanks a lot!!!

kaiji2012

unread,
Mar 6, 2012, 9:45:42 AM3/6/12
to d3...@googlegroups.com
Hello!

What do we need to do if we want do draw multiple lines using axis component?
Is that even possible? 

I tried Giorgios example but used 2 of the stocks(IBM and MSFT) from the stocks.csv instead....
and what I saw on the screen were 2 lines that were intersecting in X shape....:(

Does this happened because of the clipping path?

Thanks!

Mike Bostock

unread,
Mar 6, 2012, 9:47:56 PM3/6/12
to d3...@googlegroups.com
> What do we need to do if we want do draw multiple lines using axis
> component? Is that even possible?

The axis component doesn't draw lines; it draws axes. Are you trying
to draw multiple lines with the same axis? Or multiple lines with
different axes? If you want to draw multiple lines, create multiple
path elements. If you want to draw multiple axes, create multiple g
elements and create a d3.svg.axis for each (or reuse the same axis but
change the configuration, as in the ggplot2-style examples).

> I tried Giorgios example but used 2 of the stocks(IBM and MSFT) from the
> stocks.csv instead....
> and what I saw on the screen were 2 lines that were intersecting in X
> shape....:(

Without a link to your example I can't say what's going wrong. Are you
trying to draw small multiples? If you have multiple lines on the same
chart (and the same axis), it's normal for them to intersect.

Mike

Bob Monteverde

unread,
Mar 6, 2012, 11:19:44 PM3/6/12
to d3...@googlegroups.com
Is it bad form to provide negative length to axis ticks to generate lines?

I'm doing that currently, though I have one issue.  I always like to bold the line where y = 0, but there doesn't appear to be a  mechanism for this. (I'd really just like to be able to add a class to lines that meet a certain criteria.. maybe to the g, so I could style the text different as well).  I also like to add max and min values to the axis, though I usually don't draw a rule for the max and min.   I guess this may go a little beyond the simple axis (or I could add them myself), but just throwing the ball out there to see what people think.

I believe I have to branch d3 in oder to add month end dates to the axis component (optional of course), so maybe I'll do the additions to the axis while I'm working.

Bob

Mike Bostock

unread,
Mar 6, 2012, 11:23:34 PM3/6/12
to d3...@googlegroups.com
> Is it bad form to provide negative length to axis ticks to generate lines?

No, that's part of the API.

> I'm doing that currently, though I have one issue.  I always like to bold
> the line where y = 0, but there doesn't appear to be a  mechanism for this.

You can post select the created lines, use filter to select the
0-line, and then change the style. For example:

svg.append("g")


.attr("class", "x axis")

.call(xAxis)
.selectAll("line.tick")
.filter(function(d) { return !d; })
.style("stroke-width", "2px");

You could likewise add a class to the parent g element for that tick,
rather than selecting the line directly, which would let you then
apply stroke styles and font size changes via stylesheet.

> I believe I have to branch d3 in oder to add month end dates to the axis
> component (optional of course), so maybe I'll do the additions to the axis
> while I'm working.

You should be able to do that by overriding the tickFormat on the axis.

Mike

Ian Wren

unread,
Jun 28, 2012, 10:21:43 AM6/28/12
to d3...@googlegroups.com
Hi Giorgos,

I know this post is a bit old now but I'm trying to do a similar task but having some difficulty. Do you have a working example of the project you describe here?

Thanks,

Ian
Reply all
Reply to author
Forward
0 new messages