Centroid issue with D3 map text

1,586 views
Skip to first unread message

marc fawzi

unread,
Mar 21, 2013, 6:11:35 PM3/21/13
to d3...@googlegroups.com
Please refer to the attached image showing the problem

I'm labeling the individual states in a map of the US

I'm using the "us-atlas" json per Mike's advise for higher resolution
(pretty nice actually)

The problem is that using path.centroid(d...) the labels for FL and LA
are awkwardly positioned on the border of those states.

Questions for SVG magicians:

What would be a good fix for this? I could make a manual adjustment
for FL and LA and move them a little so they look centered but I'd
rather have a generic function that can adjust for text height and
width and offset the text so that it is centered around the centroid
point (x,y)


g.selectAll("text")
.data(topojson.object(us, us.objects.states).geometries)
.enter()
.append("text")
.text(function(d){
return d.properties.code;
})
.attr("x", function(d){
return path.centroid(d)[0];
})
.attr("y", function(d){
return path.centroid(d)[1];
})
.attr("text-anchor","middle")
.attr("font-family", "Arial")
.attr('font-size','7px');
Screen Shot 2013-03-21 at 2.56.05 PM.png

Jason Davies

unread,
Mar 21, 2013, 7:09:09 PM3/21/13
to d3...@googlegroups.com
On Thu, Mar 21, 2013 at 03:11:35PM -0700, marc fawzi wrote:
> The problem is that using path.centroid(d...) the labels for FL and LA
> are awkwardly positioned on the border of those states.

I'd recommend manually positioning labels that are awkwardly positioned
when using the centroid of a polygon. The problem with polygon
centroids is that they're not guaranteed to lie within the polygon (at
least for our definition of centroid: barycenter).

You should already correct the y-position slightly using the "dy"
attribute on your text, and use text-anchor="middle". But if the
polygon is a strange shape, e.g. L-shaped, it's quite likely the
centroid will be too close to a border, or might even lie outside of the
polygon.

Related: D3's polygon centroids are currently weighted by the lengths of
their line segments, not areas. The difference will not be noticeable
in most scenarios. Area-weighted centroids will arrive in a future
release:

https://github.com/mbostock/d3/pull/1011

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

marc fawzi

unread,
Mar 21, 2013, 7:36:51 PM3/21/13
to d3...@googlegroups.com
That helped a lot! thank you!

It was my initial idea to do that but then I saw this solution by @nrabinowitz
http://stackoverflow.com/questions/12062561/calculate-svg-path-centroid-with-d3-js?rq=1

and unfortunately I spent time trying it out not thinking of situations where the center of the BBox for the path is outside the polygon of the state drawn by that path ...

Attached is the updated image with dy/dyx tweaks

As for RI, CT, DC, MD etc I'll have to draw a line from centroid to outside the map and put the state code there
> --
> You received this message because you are subscribed to the Google Groups "d3-js" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to d3-js+un...@googlegroups.com.
> For more options, visit https://groups.google.com/groups/opt_out.
>
>
Screen Shot 2013-03-21 at 4.33.45 PM.png

marc fawzi

unread,
Mar 22, 2013, 2:40:31 PM3/22/13
to d3...@googlegroups.com
Hi Jason

When do you expect the area based centroid calculation to be released?

And will it help reduce the edge cases below?

 .attr("dy", function(d){

                    // edge cases due to centroid calculation issue
                    // see: https://github.com/mbostock/d3/pull/1011
                    // deviations adjusted to test case at map height = 166px
                    function dy(n) {
                        return (n * projection.translate()[1]) / 166
                    }

                    switch (d.properties.code)
                    {
                        case "LA":
                            return dy(-8)
                        case "NH":
                            return dy(3)
                        case "MA":
                            return dy(1)
                        case "DE":
                            return dy(5)
                        case "MD":
                            return dy(9)
                        case "RI":
                            return dy(4)
                        case "CT":
                            return dy(2)
                        case "NJ":
                            return dy(-3)
                        case "DC":
                            return dy(-3)
                        default:
                            return 0
                    }

                })

?



On Thu, Mar 21, 2013 at 4:09 PM, Jason Davies <ja...@jasondavies.com> wrote:

Jason Davies

unread,
Mar 22, 2013, 3:16:38 PM3/22/13
to d3...@googlegroups.com
On Fri, Mar 22, 2013 at 11:40:31AM -0700, marc fawzi wrote:
> And will it help reduce the edge cases below?

Area-weighting as opposed to length-weighting won't make much difference
for you; this is more for theoretical interest. For instance, it will
correctly weight towards the region with the most area if you have a
polygon containing several holes, whereas length-weighting doesn't know
anything about holes, and in fact will weight towards the holes.

The centroid is not guaranteed to lie within the polygon, or away from
borders. So I'd still advise manual intervention for label placement if
the centroid is not appropriate.

marc fawzi

unread,
Mar 22, 2013, 3:31:26 PM3/22/13
to d3...@googlegroups.com
ha!

"The centroid is not guaranteed to lie within the polygon"

Could be a great spoken sample for an industrial dub piece but ... for polygons that are states and counties (not an arbitrary polygon that can cross itself, whatever you call that) I've got to believe that the centroid lies within the polygon


marc fawzi

unread,
Mar 23, 2013, 4:47:31 PM3/23/13
to d3...@googlegroups.com
k, so some states (none in the US, afaik) have a shape that puts the centroid outside their polygon

In that case, I wonder why it's called a centroid.. is that like factoid? i.e. sounds like a fact but is not? ')

Maybe a better thing to do would be to publish a D3 extension that is an object map like this {"DC": lon, lat, "MD": lon, lat, etc} that would contain the human picked "visual center" for all the states in the US, and one can be made for each country
Reply all
Reply to author
Forward
0 new messages