Closing a Path

1,407 views
Skip to first unread message

iawilson

unread,
Jan 13, 2012, 1:03:24 PM1/13/12
to d3-js
This question should be pretty basic -

How do I tell a path not to link from the end of the series of data
points back to the beginning?

I had this problem very early on using d3, but it randomly went away
after I read more tutorials and started using "correct" pathing code.
Several weeks later, I tear the code down to essentials and am now
getting this problem again, but only in Chrome. The path looks
completely fine in Firefox, and is graphing correctly in Chrome, it
just wraps back to the beginning.

Code:

var path = d3.select("#graph").selectAll('path')
.data([newdata]);

path.enter().append("svg:path")
.attr("id","path"+selectedgraph)
.attr("stroke", c(selectedgraph))
.attr("d", d3.svg.line()
.interpolate("basis")
.x(function(d,i) { return x(d.Load) })
.y(function(d,i) { return charth - y(d.Percentile) })
);

path.exit().remove();

Mike Bostock

unread,
Jan 13, 2012, 1:27:23 PM1/13/12
to d3...@googlegroups.com
> How do I tell a path not to link from the end of the series of data
> points back to the beginning?

See this part of the spec on the Z command:

http://www.w3.org/TR/SVG/paths.html#PathDataClosePathCommand

And this part on filling paths:

http://www.w3.org/TR/SVG/painting.html#FillProperties

Specifically:

"""
The fill operation fills open subpaths by performing the fill
operation as if an additional "closepath" command were added to the
path to connect the last point of the subpath with the first point of
the subpath. Thus, fill operations apply to both open subpaths within
‘path’ elements (i.e., subpaths without a closepath command) and
‘polyline’ elements.
"""

So, if you use d3.svg.line to create an svg:path element, you probably
only want to apply a stroke style. If you apply a fill style, there's
that implicit closepath command that connects the first and last point
of the line. If you want a fill, you probably want to use d3.svg.area
instead, which defines an explicit baseline (which could be 0 for a
simple area chart, or another series of data for a stacked area
chart). Areas can also be stroked, in which case the entire path is
stroked. Often, you use an area for fill in conjunction with a line
for stroke, as here:

http://bl.ocks.org/1166403

Mike

iawilson

unread,
Jan 13, 2012, 2:45:51 PM1/13/12
to d3-js
Thanks for the reply Mike. I *am* applying a fill style in the css,
but it is "none", because without that, the path closes its shape back
to the first point and fills any created shapes black (in Firefox and
Chomre). This was the problem I was encountering originally that I
applied the css style fill:none to correct. It does seem to correct it
and was working fine, I'm just getting this weird Chrome 'bug' now
that I've heavily edited my code. I'm not dealing with the path or
applying any fills anywhere else. It's just those lines of code with
this CSS styling:

path {
stroke-width: 2;
fill: none;
}

Is there something I don't understand about the basic path code that
applies a fill or closepath? I'm just at a complete loss here.

Mike Bostock

unread,
Jan 13, 2012, 2:49:58 PM1/13/12
to d3...@googlegroups.com
> I *am* applying a fill style in the css, but it is "none",

Right, that's what I'd recommend. I should have also mentioned that
the default fill for paths is opaque black (with no stroke), which is
not what you want for a line.

> I'm just getting this weird Chrome 'bug' now

Have you used the element inspector to see what styles are being
applied to the path elements? Are you styling a containing svg:g or
svg:svg element? Can you include a screenshot or an example of the
problem so we can see exactly what the bug is?

Mike

iawilson

unread,
Jan 13, 2012, 3:13:48 PM1/13/12
to d3-js
http://oi44.tinypic.com/o8ezcm.jpg

The path ends "84L920,84L920,84L920,84L920,84", with no "z"s. Is it
possible it's a problem with the way my dataset is formatted? It's
ordered by the measure I'm using for the x-axis and is graphing
correctly otherwise.

Thanks for the help. I've avoided bringing trivial problems the last 3
weeks, but this one got me.

iawilson

unread,
Jan 13, 2012, 3:19:59 PM1/13/12
to d3-js
I don't think any of it is relevant, but the styling on the containing
elements going down the DOM tree is:

html {
height:100%;
}

body {
height:100%;
padding:5px;
}

#wrapper {
width:1200px;
display:block;
float:left;
}

#svgwrapper {
float:left;
}

svg {
border:2px solid grey;
margin:5px;
padding:10px;
}

#chart {
padding:30px;

Mike Bostock

unread,
Jan 13, 2012, 3:22:12 PM1/13/12
to d3...@googlegroups.com
> The path ends "84L920,84L920,84L920,84L920,84", with no "z"s.

That does look a little suspicious. Why so many repeated data points
"L920,84"? My guess is somewhere in your line you have a spurious L0,0
that causes it to go back to the origin. I'd try simplifying the line
geometry until the problem goes away, and then figure out where the
bogus point is coming from.

Mike

iawilson

unread,
Jan 13, 2012, 3:50:00 PM1/13/12
to d3-js
The dataset was 1000 items, binned down to 25 x coordinate positions.
I cut it down to 100 items and the problem persisted but it became
apparent (you can sort of see it in the picture I posted between the
1500 and 2000 x position) that it's not doubling back from the end
point but from somewhere in the middle, so this would seem to be a
data issue, not a path drawing issue.

I'm confused though, because those 100 items are in order, with a Load
between 0 and 3000 for the x, and a calculated percentile between 0
and 100 for the y. It all looks fine, data-wise, as far as I
understand it. I can't imagine that the fact that my dataset has extra
objects is affecting it, right? My earlier "test" dataset had only the
2 values I was graphing. This has several extra objects, but they're
not referenced by the path in any way.

Should I be binning those duplicate Xes up and only graphing each
point once? I didn't take this approach because the extra objects for
each datapoint define different categories, which will slice the data
various ways later on, so it seemed like a mis-step.

Why would having many duplicate datapoints cause this problem to
present?

Daniel W

unread,
Jan 13, 2012, 3:52:02 PM1/13/12
to d3-js
FWIW, I was this issue about one hour ago, and it ended up being a CSS
issue - I was accidentally telling the path to fill.

iawilson

unread,
Jan 13, 2012, 3:59:27 PM1/13/12
to d3-js
Yeah, I wish I could change the title of this thread now, as it is
fairly misleading compared to what the issue seems to actually be.

Mike Bostock

unread,
Jan 13, 2012, 4:10:55 PM1/13/12
to d3...@googlegroups.com
> Why would having many duplicate datapoints cause this problem to
> present?

I don't think it's duplicate datapoints that are causing the problem,
but it was suspicious and suggested to me there could perhaps be
another problem related to the line construction.

Mike

iawilson

unread,
Jan 13, 2012, 5:03:39 PM1/13/12
to d3-js
Thanks for the assistance and suggestions for further exploration.
I'll update if I figure it out or if it's a recurring problem with
other data.

Steven Endres

unread,
Jan 13, 2012, 11:48:46 PM1/13/12
to d3...@googlegroups.com

I think Mike is correct. What I'd recommend is using only three points to ensure you get the most simple case working. Then add 25, another 25, then 50 and so on to see at what point in your data where the path fills. You may find that you have an off-by-one error creating x[0],y[0],x[1],y[1],x[2],0 or something like that. Either that or a rounding error is creating a 0,0 somewhere. The best practice here is to start with the most trivial case that works and then add more data until something breaks. Once you break it, go back and run the last test that worked, and then add half of the data that broke the plot to find which half of the set contains the error. Divide and conquer. It's tedious, but reliable. -Steve

Jack Wang

unread,
Jan 19, 2013, 10:59:21 AM1/19/13
to d3...@googlegroups.com, mbos...@cs.stanford.edu
Mike,
I have another problem. The dataset I append to the area has two data values, say values and values_2.

I have visualized values as one path and values_2 as another path. Now I want to fill the gap between them, and if the path for values is above values_2, I want to fill the gap by blue, else if its below path for values_2, I want to fill the gap by green. Here is my current code:

t.select(".area").attr("d", area(data_union))
                    .style("fill",function(d) { 
                    return d.values > d.values_2 ? "blue" : "green";
                    }); 

Obviously it's not working and I don't know why. It works if I fill by a single color instead of function:
t.select(".area").attr("d", area(data_union))
                    .style("fill","red);

Could you please help me out? How should I change the function?

Thanks!
Reply all
Reply to author
Forward
Message has been deleted
0 new messages