d3 / d3-shape

Graphical primitives for visualization, such as lines and areas.
https://d3js.org/d3-shape
ISC License
2.48k stars 308 forks source link

When do we need accessors? #47

Closed mbostock closed 8 years ago

mbostock commented 8 years ago

The pie layout benefits significantly from accessors because the returned objects retain their links to the original data, so you can then bind these objects to the DOM, use them to render arcs, and then access other fields to apply other encodings (e.g., color). This argument applies to any layout.

But what about shapes? Shapes don’t return objects: they render them, either to a 2D context or by returning a path data string. If there’s no returned object, there’s no concept of retaining the association with the input data.

So, should arc, line, area et al. use accessors? It certainly feels more convenient than using array.map. And it’s probably more efficient since you don’t need to materialize the copies (especially now that line and area stream). But in other cases, like the new hull in d3-polygon, it seemed superfluous to retain the x- and y-accessors. After all, we don’t support x- and y-accessors for computing polygon area or centroid, so why do that for the hulls? On the other hand, because of the benefit of retaining association with input data, it is useful to have accessors for computing a Voronoi diagram.

I guess it’d be nice to articulate some guidelines about what things should have accessors, and why.

mbostock commented 8 years ago

Maybe part of the answer is distinguishing between “higher level” and “lower level” operators. The curves, for instance, are considered low-level and do not have accessors: the x and y values are passed as-is.

This confusion seems evident in the quadtree from D3 3.x: there used to be a static d3.geom.quadtree(points) method which would just compute the quadtree from an array of [x, y] points, but then it was replaced with a d3.geom.quadtree() constructor for a quadtree generator, which you could then customize with x- and y-accessors before invoking.

mbostock commented 8 years ago

It might also be worth thinking about d3-arrays. Most of the functions there support optional accessors, and there’s also bisector which is kind of an interesting case where the accessor is captured with a closure because it would be a pain to support it as an optional argument.

(Also, it feels a bit strange that quantile doesn’t take an accessor.)

mbostock commented 8 years ago

Closing because I’m not sure what else to add here other than a hand-wavy distinction between high-level and low-level operators.