Public
Edited
Mar 24, 2024
Insert cell
Insert cell
<svg width=200 height="200" viewBox="0 0 200 200">
<style>
.ring {fill: none; stroke: black; stroke-width:10px; stroke-linecap:round;}
.textLabel {font-size: 12px; text-anchor: end;}
</style>

</svg>
Insert cell
data = ([
{around:53, value: 70, type: "a"},
{around:32, value: 83, type: "b"},
{around:64, value: 42, type: "c"},
{around:85, value: 50, type: "d"},
{around:16, value: 95, type: "e"},
{around:75, value: 15, type: "f"},
])
Insert cell
Insert cell
center = ({x:100,y:100})
Insert cell
ringPosition = ({"a":6,"b":5,"c":4,"d":3,"e":2,"f":1}) // 1 = innermost, closest to center
Insert cell
ringColors = ({"a":"steelblue","b":"limegreen","c":"magenta","d":"orange","e":"gray","f":"red"})
Insert cell
ringScale = 15
Insert cell
Insert cell
Insert cell
{
// create a group for the whole thing to sit in, and move the group to the "center" position
let ringsGroup = d3.select(ringsSVG).selectAll(".ringGroup")
.data([1])
.join("g")
.classed("ringGroup",true)
.attr("transform","translate(" + center.x + " " + center.y + ")");
// draw the rings as arcs. Arcs are one of the instuctions in the <path> element
let rings = ringsGroup.selectAll(".ring")
.data(data)
.join("path")
.classed("ring",true)
.style("stroke",d => ringColors[d.type])
.style("stroke-width",d => d.value/100 * 10 + "px") // optional stroke-width by data. Comment out to not use.
.attr("d", d => "M " + startPoint(d).x + " " + startPoint(d).y + // move to start point
" A " + arcRadius(d) + " " + arcRadius(d) + // draw Arc with x and y radii
" 0" + // rotation of the whole thing
" " + largeArcFlag(d) + // calculate Large Arc Flag (> 180 deg)
" 1 " + // clockwise drawing for the arc (0 or 1)
endPoint(d).x + " " + endPoint(d).y); // finish at the end point x,y

// draw label text, for convenience, from the same data
let labels = ringsGroup.selectAll(".textLabel")
.data(data)
.join("text")
.attr("x",-8)
.attr("y",d => startPoint(d).y + 3)
.classed("textLabel",true)
.text(d => d.type);
}
Insert cell
Insert cell
startPoint = d => {return {"x":0, "y":-arcRadius(d)}} // in this case x is always 0,radius but you could change this by data.
Insert cell
endPoint = d => {return polarXY(arcRadius(d),90-aroundAngle(d))} // start point could be set in a similar way.
Insert cell
arcRadius = d => {return ringPosition[d["type"]]*ringScale}
Insert cell
aroundAngle = d => {
let percent = Number(d["around"])/100; // from "around" data field out of 100, or calculate this however you need for your data
let angleAround = percent * 360; // degrees
return angleAround;
}
Insert cell
Insert cell
largeArcFlag = d => {if (aroundAngle(d) > 180) {return 1} else {return 0}}
Insert cell
polarXY = (magnitude,angle) => {
magnitude = Number(magnitude);
angle = Number(angle);
let x = magnitude * Math.cos(radiansFromDeg(angle));
let y = -magnitude * Math.sin(radiansFromDeg(angle)); // negative because 0 is at the top
return {"x":x, "y":y};
}
Insert cell
radiansFromDeg = (deg) => {
deg = Number(deg);
return deg * Math.PI / 180;
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more