Closed mbostock closed 1 month ago
Current status:
I’m now computing the number of waffle cell columns correctly, and rendering them as a pattern. But I need to replace the rect elements generated by BarY with a path element so that the top & bottom cells aren’t truncated (unless there’s a fractional value).
Now with fractional cell rendering!
Whew! 😅 That was a lot of work but I’m pretty happy with how this turned out.
I was wondering how to use this for ISOTYPE charts, and it appears that it's possible to use the render transform to edit the patterns’ contents:
render: (index, scales, values, dimensions, context, next) => {
const g = next(index, scales, values, dimensions, context);
const pattern = d3.select(g).selectAll("pattern");
pattern.selectAll("rect").remove();
pattern.append("text").attr("x", 10).attr("y", 15).text("🚀");
return g;
}
This gives two ideas for future enhancements:
The rendered pattern might also be easier to manipulate if it was centered on the origin with a viewBox rather than extending from it (in that case, the values for x and y above would essentially be zero).
@@ -62,10 +62,11 @@ function waffleRender(y) {
const basePattern = document.createElementNS(namespaces.svg, "pattern");
basePattern.setAttribute("width", cellsize);
basePattern.setAttribute("height", cellsize);
+ basePattern.setAttribute("viewBox", [-cellsize / 2, -cellsize / 2, cellsize, cellsize]);
basePattern.setAttribute("patternUnits", "userSpaceOnUse");
const basePatternRect = basePattern.appendChild(document.createElementNS(namespaces.svg, "rect"));
- basePatternRect.setAttribute("x", gap / 2);
- basePatternRect.setAttribute("y", gap / 2);
+ basePatternRect.setAttribute("x", (gap - cellsize) / 2);
+ basePatternRect.setAttribute("y", (gap - cellsize) / 2);
basePatternRect.setAttribute("width", cellsize - gap);
basePatternRect.setAttribute("height", cellsize - gap);
if (rx != null) basePatternRect.setAttribute("rx", rx);
It makes total sense that the number of rows/columns is completely automatic and not configurable, but it might be useful to call this out explicitly in the documentation? And give hints on how to alter the number of rows and columns (such as layering several marks like in the Syrian teenagers example, changing the chart's aspect ratio, using scale insets, etc).
It might be nice in the future to allow a configurable orientation (e.g. filling rows from the left instead of from the right). Not a blocker at all, I'm not even sure I would use it.
It makes total sense that the number of rows/columns is completely automatic and not configurable, but it might be useful to call this out explicitly in the documentation?
That’s already called out here:
The waffle mark automatically determines the appropriate number of cells per row or per column (depending on orientation) such that the cells are square, don’t overlap, and are consistent with position scales.
It would also be very easy to expose this as an option. In fact I had it as an option in the past. But it was a footgun: if you hard-code the value it’s easy to produce overlapping waffles. In practice, what I want is to guarantee that the rows/columns is either a factor or a multiple of the corresponding position scale. The waffle mark doesn’t have that information easily available at render time, though (since the axis could be rendered after the waffle, or there could be multiple axes)… maybe an option to limit it to a power of ten times 1, 2, 5? Anyway.
The number of rows/columns is also heavily affected by the values, so I’m not sure I have much useful hints. Maybe just, if you have narrower bands, you have fewer cells per row/column? Setting padding on the ordinal scale for example.
It might be nice in the future to allow a configurable orientation (e.g. filling rows from the left instead of from the right).
Sure… though I’m skeptical of adding such an obscure feature unless someone can explain why it’s worth adding. You could always do it with a custom mark or render transform.
The ISOTYPE chart idea is interesting, but I’m not sure how well the waffle would work for that since often the glyphs are non-square and can vary in size across series. There’s no meaningful position encoding in an ISOTYPE chart; you’re just responsible for counting glyphs to perceive the encoded value.
But for sure there are more extensions we could do here than square/rounded squares for the pattern! I don’t think we should implement these now, with the possible exception of non-square aspect ratios as previously mentioned.
Fixes #2029.