Skip to main content
100%

D3 Nested & Independent General Update Pattern

✓ Published0🌍 Public
Vvaporpin
Last edited Oct 23, 2020
Created on Oct 23, 2020

This example demonstrates an animated fruit bowl where apples and lemons are added, removed, and resized, showing how nested groups of rectangles update independently within each fruit group. The code uses D3’s General Update Pattern twice: first to manage the outer `<g>` elements for each fruit, then, inside a `selection.each` callback, to handle the inner rectangles per group via `selectAll('rect')` and `.data()`. The inner rectangles’ width is driven by `radiusScale(d.type)`, while their quantity is set by `d3.range(d.num)`.

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