An SVG group is a <g> element that contains related SVG children. The group has no visible shape or bounded area of its own, but a transform on it affects every descendant. This lets a rectangle and its labels, or any other small visual unit, move together while each child keeps coordinates relative to the group. section 3.5 section 3.6
Use groups to give a chart meaningful structure. Bind one data item to each group, then append the marks and text that belong to that item. Child elements can use the parent’s bound datum, avoiding separate bindings for a bar, its technology label, and its count label. section 3.5 section 5.1.4
Groups are especially useful when a visualization needs shared positioning:
- Wrap an inner chart in a translated group to reserve margins and work from a coordinate system offset from the SVG container. section 4.1.1
- Place each donut’s arcs in a group translated to that donut’s center, so the arcs draw around the intended position. section 5.1.1
- Create one group per grid item and calculate its translation from the item index, column count, and item dimensions. section 14.4.2
- Combine a tooltip background rectangle and text in one group so opacity and position apply to the complete tooltip. section 7.3.1
Bar and label unit
For a horizontal bar chart, join the dataset to g elements rather than rect elements. Translate each group vertically with the band scale. Append a rect at y=0, then append text for the category and count. Because the group already supplies the vertical position, the children need only their positions within one bar row. section 3.5
Listing 5.5 Adding labels on the centroids (donut-charts.js)
const arcs = donutContainer
.selectAll(`.arc-${year}`)
.data(annotatedData)
.join("g") #1
.attr("class", `arc-${year}`);
arcs #2
.append("path")
.attr("d", arcGenerator)
.attr("fill", d => colorScale(d.data.format));
arcs
.append("text") #3
.text(d => {
d["percentage"] = (d.endAngle - d.startAngle) #4
/ (2 * Math.PI);
return d3.format(".0%")(d.percentage);
})
.attr("x", d => { #5
d["centroid"] = arcGenerator
.startAngle(d.startAngle)
.endAngle(d.endAngle)
.centroid();
return d.centroid[0];
})
.attr("y", d => d.centroid[1])
.attr("text-anchor", "middle")
.attr("dominant-baseline", "middle")
.attr("fill", "#f6fafc")
.attr("fill-opacity", d => d.percentage #6
< 0.05 ? 0 : 1)
.style("font-size", "16px")
.style("font-weight", 500);
This listing shows the same pattern for donut segments: bind data to groups first, then append a path and its percentage label as children that share the datum. section 5.1.4
