lezan
lezan

Reputation: 787

Create a radial (circular) grouped bar chart with d3.js

I am trying to create a radial (circular) grouped bar chart with d3.js, something like that. enter image description here To do it, I started from three examples:

To make it simple, I am using the same data of the first example and I deleted labels and axis, I left only scales's function and arc generator. I think I am not to far from the final solution, but I can not figure out what I am missing/doing wrong, but I think it could be x0's function or the translate of each bar in the same group. As you can see, no one bar or group is correctly positioned.

I prepare an example here.

Some code here:

X scale function, to position each group:

x0 = d3.scaleBand()
    .domain(data.map(d => d.State))
    .range([0, 2 * Math.PI])
    .align(0)

X scale function, to position each bar in group:

x1 = d3.scaleBand()
    .domain(keys)
    .range([0, x0.bandwidth()])
    .align(0)

Y scale function, to position height of bar:

y = d3.scaleLinear()
  .domain([0, d3.max(data, d => d.total)])
  .range([innerRadius, outerRadius]);

Arc generator:

arc = d3.arc()
    .innerRadius(innerRadius)
    .outerRadius((d) => y(d.value))
    .startAngle(d => x1(d.key))
    .endAngle(d => x1(d.key) + x1.bandwidth())
    .padAngle(0.01)
    .padRadius(innerRadius)

Main chain:

svg.append("g")
    .selectAll("g")
    .data(data)
    .join("g")
      .attr("transform", d => `translate(${x0(d[groupKey])},0)`)
    .selectAll("path")
    .data(d => keys.map(key => ({key, value: d[key]})))
    .join("path")
      .attr('fill', '#69b3a2')
      .attr("d", arc);

Upvotes: 1

Views: 2913

Answers (1)

Codesmith
Codesmith

Reputation: 6792

Yep, you were close. I changed a couple things on your observable that seemed to fix it.

First, in your main graph function, you're using translate instead of rotate:

  // ...

  svg.append("g")
    .selectAll("g")
    .data(data)
    .join("g")
      // .attr("transform", d => `translate(${x0(d[groupKey])},0)`)
      .attr("transform", d => `rotate(${x0(d[groupKey])})`)   // use rotate (also remove ',0')
    .selectAll("path")
    .data(d => keys.map(key => ({key, value: d[key]})))
    .join("path")
      .attr('fill', '#69b3a2')
      .attr("d", arc);

  // ...

Second, rotate as a transform requires degrees, but x0 returns radians since that's what d3.arc needs. The simplest fix I could find for this is just adding a conversion from rads to degs in the rotate transform:

  // ...

  svg.append("g")
    .selectAll("g")
    .data(data)
    .join("g")
      // .attr("transform", d => `translate(${x0(d[groupKey])},0)`)
      // .attr("transform", d => `rotate(${x0(d[groupKey])})`)
      .attr("transform", d => `rotate(${x0(d[groupKey]) * 180 / Math.PI})`)
    .selectAll("path")
    .data(d => keys.map(key => ({key, value: d[key]})))
    .join("path")
      .attr('fill', '#69b3a2')
      .attr("d", arc);

  // ...

This gives what I imagine starts to be the correct results:

Grouped Radial Bar Chart

Upvotes: 2

Related Questions