Kiran has a problem. He's working on a project and doesn't know how. Let's help
My solution š
How it works āļø
Kiran wants to build a "circle with arcs" chart, but he's having trouble. He asked for help so here we are :)
I livecoded this one from the Paris airport so there's no sound in the video. I was too shy to narrate my actions in the middle of a busy Starbucks. Maybe next time.
Anyway, to build an arc circle like this, we can take many cues from how you would build a piechart. Arcs are still arcs: They're round, have an inner and outer radius, and represent a datapoint. We can layer them on top of each other with a band scale feeding into radiuses.
Like this š
First you need a dataset
We fake the dataset because Kiran didn't provide one.
// 5 percentages represent our datasetconst data = d3.range(5).map(_ => ({name: Faker.hacker.verb(),percentage: 75 * Math.random(),}))
5 datapoints, fake name with faker, and a random chunk out of 75%. Tried going full 100 at first and it didn't look great at all.
Then you need a parent component
const CircleArcs = ({ data, maxR }) => {const rScale = d3.scaleBand().paddingInner(0.4).paddingOuter(1).domain(d3.range(data.length)).range([0, maxR])return (<g><Circle cx={0} cy={0} r={maxR} />{data.map((d, i) => (<Arc d={d} r={rScale(i)} width={rScale.bandwidth()} key={i} />))}</g>)}
A functional component will do. Create a band scale for the radiuses. Those cut up a given space into equal bands and let you define padding. Same scale you'd use for a barchart to position the bars.
The band scale is ordinal so our domain has to match the number of inputs, d3.range
takes care of that. For our dataset that sets the domain to [0,1,2,3,4]
.
Scale range goes from zero to max radius.
Render a <Circle>
which is a styled circle component, loop through the data and render an <Arc>
component for each entry. The arc takes data in the d
prop, call rScale
to get the radius, and use rScale.bandwidth()
to define the width. Band scales calculate optimal widths on their own.
We can use index for keys because we know arcs will never re-order.
The parent component needs arcs
That's what it's rendering. They look like this
const Arc = ({ d, r, width }) => {const arc = d3.arc().innerRadius(r).outerRadius(r + width).startAngle(0).endAngle((d.percentage / 100) * (Math.PI * 2))return (<g><Label y={-r} x={-10}>{d.name}</Label><ArcPath d={arc()} /></g>)}
A D3 arc generator defines the path shape of our arcs. Inner radius comes from the r
prop, outer radius is r+width
. Unlike a traditional pie chart, every arc starts at angle zero.
The end angle makes our arcs communicate their value. A percentage of full circle.
Each arc also comes with a label at its start. We position those at the beginning of the arc using the x
and y
props. Setting their anchor point as end
automatically makes them end at that point.
const ArcPath = styled.path``const Label = styled.text``
Styled components work great for setting pretty much any SVG prop š
And the result is a circle arc chart thing. Wonderful.
About the Author
Hi, Iām Swizec Teller. I help coders become software engineers.
Story time š
React+D3 started as a bet in April 2015. A friend wanted to learn React and challenged me to publish a book. A month later React+D3 launched with 79 pages of hard earned knowledge.
In April 2016 it became React+D3 ES6. 117 pages and growing beyond a single big project it was a huge success. I kept going, started live streaming, and publishing videos on YouTube.
In 2017, after 10 months of work, React + D3v4 became the best book I'd ever written. At 249 pages, many examples, and code to play with it was designed like a step-by-step course. But I felt something was missing.
So in late 2018 I rebuilt the entire thing as React for Data Visualization ā a proper video course. Designed for busy people with real lives like you. Over 8 hours of video material, split into chunks no longer than 5 minutes, a bunch of new chapters, and techniques I discovered along the way.
React for Data Visualization is the best way to learn how to build scalable dataviz components your whole team can understand.
Some of my work has been featured in š