Bonus chart! Sunburst radial partition joy!

Oh, you thought we were done? Let's squeeze one more chart out of d3-hierarchy before moving on.

If you remember, the partition chart was a bit funky, largely because it's mainly used in datasets where only the leaf nodes (that is, the outermost nodes without children) have a value. Since some of the parents in our dataset have screentime values, this sort of distorts it and makes it look odd. We will re-render that, but make it all cool and circular this time.

You know the drill. main.js:

westerosChart.init('radialPartition', 'data/GoT-lineages-screentimes.json');

In chapter6/index.js:

westerosChart.radialPartition = function RadialPartition(_data) { 
const data = getMajorHouses(_data)
.map((d, i, a) => Object.assign(d, {
screentime: a.filter(v =>
v.fatherLabel === d.itemLabel).length ? 0 : d.screentime,
}) );
const radius = Math.min(this.innerWidth, this.innerHeight) / 2;
};

We start by creating a radius that's half of the smallest dimension and mapping our data so that any nodes that are ancestors get their screentime set to zero.

Continue by creating our root and house color scale as per before:

  const stratify = d3.stratify() 
.parentId(d => d.fatherLabel)
.id(d => d.itemLabel);

const root = stratify(data)
.sum(d => d.screentime)
.sort(null);

const houseColors = color.copy().domain(root.ancestors().shift()
.children.map(d => d.id.split(' ')[d.id.split(' ').length - 1])
);

Next, we create our partition layout, but set it to half the width and height of parent chart. This is because we're calculating it radially, so the output will be double whatever value we set here:

  const layout = d3.partition() 
.size([
this.innerWidth / 2,
this.innerHeight / 2,
])
.padding(1)
.round(true);

Next, we create an x-scale and an arc generator:

  const x = d3.scaleLinear() 
.domain([0, radius])
.range([0, Math.PI * 2]);

const arc = d3.arc()
.startAngle(d => x(d.x0))
.endAngle(d => x(d.x1))
.innerRadius(d => d.y0)
.outerRadius(d => d.y1);

We set our domain to our radius and our range to double the value of PI. Again, this is a standard circle stuff.

Populate the layout and create your data join:

  layout(root); 

const nodes = this.container
.append('g')
.attr('class', 'nodes')
.attr('transform',
`translate(${this.innerWidth / 2}, ${this.innerHeight / 2}))
.selectAll('.node')
.data(root.descendants().slice(1))
.enter()
.append('g')
.attr('class', 'node');

Next, append paths, supplying the arc generator for the d value:

  nodes.append('path') 
.attr('d', arc)
.attr('fill', d => descendantsDarker(d, color, false));

Lastly, we set up the legend and tooltip:

  this.container 
.append('g')
.attr('id', 'legend')
.attr('transform', `translate(${this.innerWidth - 100}, 0)`)
.call(legend.legendColor().scale(houseColors));

nodes.call(tooltip(d => d.data.itemLabel, this.container));

Finally! Let's see how it looks:

Must say, that's definitely an improvement over the rectangular version.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset