Skip to main content
100%

D3 Nested & Independent General Update Pattern

✓ Published3🌍 Public
CCurran Kelleher
Last edited Oct 21, 2020
Created on Oct 21, 2020

D3’s nested General Update Pattern manages a variable number of rectangles inside each fruit group, responding to changes in fruit type and count. Apples appear as red circles with wider bars, lemons as yellow with narrower ones; removing a fruit deletes its entire group. The implementation uses `selection.each` to isolate each `<g>` element, then applies the inner update pattern with `selectAll` and `data`, merging enter and update selections via `merge`. SVG rendering handles all visual output, with `scaleOrdinal` mapping fruit types to colors and sizes.

AI-generated description

A response to a question in the D3 Slack about different numbers of nested rectangles.

Original question by May Tan:

What i'm trying to do is add varying number of rectangles based on "num" in the data. The size of rectangle depends on the type of fruit. I realise that the rect size did update when the apple is changed into a lemon. However rect size didn't update on the last update when apple was eaten. My question is how do I write the selections when the data join is not based on number of array items, but range of some data. I am also sure i'm writing the update part wrongly as the size of rect did not get updated. Thanks for your help!

Answer:

Ahh I see what you mean. You want to essentially "break out" into a new update pattern, within each <g> element, so that each has its own unique data driven collection of rectangles. Here's a solution for it:

const groups = groupsEnter.merge(groupsUpdate);

groups.each(function (d) {
  const innerGroup = select(this);
  const rects = innerGroup
    .selectAll('rect')
    .data((d) => d3.range(d.num).map(() => d));

  rects
    .enter()
    .append('rect')
    .attr('height', '30px')
    .attr('stroke', 'black')
    .merge(rects)
    .attr('y', (d, i) => -40 * (i + 1))
    .attr('width', (d) => radiusScale(d.type));

  rects.exit().remove();
});

The trick is to use selection.each (and the old school function notation to access this) to isolate the DOM nodes for the groups (exposed by D3 as this), then use select to create a new D3 selection for each individual <g> element. With this in hand, we can have another nested but totally independent General Update Pattern, allowing us to make a different number of rectangles for each group.

MIT Licensed

Similar vizzes