chart = {
const width = 1080;
const height = width;
const innerRadius = Math.min (width,height) * 0.5 - 90;
const outerRadius = innerRadius + 10;
// Compute a dense matrix from the weighted links in data.
const names = d3.sort (d3.union (data.map (d â d.source),data.map (d â d.target)));
const index = new Map (names.map ((name,i) â [name,i]));
const matrix = Array.from (index,() â new Array (names.length).fill (0));
for (const { source,target,value } of data) matrix [index.get (source)] [index.get (target)] += value;
const chord = d3.chordDirected ()
.padAngle (10 / innerRadius)
.sortSubgroups (d3.descending)
.sortChords (d3.descending);
const arc = d3.arc ()
.innerRadius (innerRadius)
.outerRadius (outerRadius);
const ribbon = d3.ribbonArrow ()
.radius (innerRadius - 1)
.padAngle (1 / innerRadius);
const colors = d3.quantize (d3.interpolateRainbow,names.length);
const svg = d3.create (âsvgâ)
.attr (âwidthâ,width)
.attr (âheightâ,height)
.attr (âviewBoxâ,[- width / 2,- height / 2,width,height])
.attr (âstyleâ,âwidth: 100%; height: auto; font: 10px sans-serif;â);
const chords = chord (matrix);
const group = svg.append (âgâ)
.selectAll ()
.data (chords.groups)
.join (âgâ);
group.append (âpathâ)
.attr (âfillâ,d â colors [d.index])
.attr (âdâ,arc);
group.append (âtextâ)
.each (d â (d.angle = (d.startAngle + d.endAngle) / 2))
.attr (âdyâ,â0.35emâ)
.attr (âtransformâ,d â `
rotate(${ (d.angle * 180 / Math.PI - 90) })
translate(${ outerRadius + 5 })
${ d.angle > Math.PI?ârotate(180)â:"" }
`)
.attr (âtext-anchorâ,d â d.angle > Math.PI?âendâ:null)
.text (d â names [d.index]);
group.append (âtitleâ)
.text (d â `${ names [d.index] }
${ d3.sum (chords,c â (c.source.index === d.index) * c.source.value) } outgoing â
${ d3.sum (chords,c â (c.target.index === d.index) * c.source.value) } incoming â`);
svg.append (âgâ)
.attr (âfill-opacityâ,0.75)
.selectAll ()
.data (chords)
.join (âpathâ)
.style (âmix-blend-modeâ,âmultiplyâ)
.attr (âfillâ,d â colors [d.target.index])
.attr (âdâ,ribbon)
.append (âtitleâ)
.text (d â `{ names \[d.source.index\] } â { names [d.target.index] } ${ d.source.value }`);
return svg.node ();
}
data = FileAttachment (âflare-imports.csvâ).csv ({ typed:true })