Public
Edited
Dec 4, 2023
Paused
Insert cell
radialTreew = {

const svg =
d3.select(DOM.svg(width, width))
.attr("viewbox", "0 0 1200 1200")
.attr("preserveAspectRatio","xMidYMid meet")
//.style("width", "100%")
//.style("height", "auto")
//.style("padding", "10px")
.style("box-sizing", "border-box")
.style("cursor", "grab");
svg.append('rect')
.attr('width', width)
.attr('height', width)
.attr('x', 0)
.attr('y', 0)
.attr('fill', 'black')
const root = tree(data)

const svgZoom = svg
.append('g')
const svgViz = svgZoom
.append('g')
.attr('transform', 'translate(' + width / 2 + ',' + width / 2 + ')')
.attr('id', 'viz')
svgViz
.append('g')
.attr('id', 'links')
.selectAll('path')
.data(root.links())
.join('path')
.attr(
'd',
d3
.linkRadial()
.angle((d) => d.x)
.radius((d) => d.y)
)
.attr('fill', 'none')
.attr('stroke', '#fff')
svgViz
.append('g')
.selectAll('circle')
.data(root.descendants())
.join('circle')
.attr(
'transform',
(d) => `
rotate(${(d.x * 180) / Math.PI - 90})
translate(${d.y},0)
`
)
.attr('fill', '#4ecb71')
.attr('r', (d) => {
return d.children ? 5 : sizeScale(d.value)
})

// add labels
const textGroups = svgViz.append('g').attr('id', 'labels')

textGroups
.selectAll('g')
.data(root.descendants())
.join('g')
//.filter((d) => (showHierarchyLabels ? true : !d.children)) // if showHierarchyLabels is false, hide non-leaf nodes
.attr(
'transform',
(d) => `
rotate(${(d.x * 180) / Math.PI - 90})
translate(${d.y},0)
rotate(${d.x >= Math.PI ? 180 : 0})
`
)
.append('text')
.attr('x', 0)
.attr('y', 0)
.attr('text-anchor', 'middle')
.attr('dominant-baseline', 'text-before-edge')
.selectAll('tspan')
.data((d) => {
// if the node has children
// pass just its name in hierarhcy
if (d.children) {
return [
{
string: d.data[0],
x: d.x < Math.PI === !d.children ? 6 : -6,
align: d.x < Math.PI === !d.children ? 'start' : 'end',
//style: styles['labelSecondary'],
hierarchy: true,
},
]
}
// else pass the mapped labels
else {
const xpos = sizeScale(d.value) + 5;
return [d.data[1].hashtag].map((e, i) => ({
string: e,
x: d.x < Math.PI === !d.children ? xpos : -xpos,
align: d.x < Math.PI === !d.children ? 'start' : 'end',
//style: styles[labelStyles[i]],
}))
}
})
.join('tspan')
.attr('x', (d) => d.x)
.attr('y', 0)
.attr('dy', (d, i) => i * 10)
.attr('text-anchor', (d) => d.align)
// .styles((d, i) => styles[labelStyles[i]])
//.styles((d) => d.style)
.attr('fill', 'white')
.style('font-family', 'Arial, sans-serif')
.style('font-size', (d)=>d.hierarchy?'14px':'7px')
.style('font-weight', 'bold')
.text((d) => d.string)

textGroups.selectAll('text').each(function () {
const sel = d3.select(this)
sel.attr('transform', function (d) {
return `translate(0,${d.children?-8:-4})`
})
})

svg.call(d3.zoom()
.extent([[0, 0], [width, width]])
.scaleExtent([1, 8])
.on("zoom", zoomed)
.on("start", ()=> svg.style("cursor", "grabbing"))
.on("end", ()=> svg.style("cursor", "grab")))

function zoomed({transform}) {
svgZoom.attr("transform", transform);
}

return svg.node();
}
Insert cell
radius = width / 1.8
Insert cell
tree = data =>d3.cluster().size([2 * Math.PI, radius-150]).separation((a, b) => {
return sizeScale(a.value) + sizeScale(b.value) + padding
})(hierarchy)
Insert cell
nest = d3.rollup(data,(v) => v[0],(d)=>d.macrotopic,(d)=>d.hashtag)
Insert cell
test = d3.groups(data,(d)=>d.macrotopic,(d)=>d.hashtag)
Insert cell
hierarchy = d3
.hierarchy(nest)
// since maps have also a .size porperty, sum only values for leaves, and not for Maps
.sum((d) => (d[1] instanceof Map ? 0 : d[1].degree))
// sort nodes according to options
.sort((a, b) => {
return d3.descending(a.value, b.value)
})
Insert cell
sizeScale = d3
.scaleSqrt()
.domain([0, d3.max(hierarchy.leaves(), (d) => d.value)])
.range([0, maxDiameter / 2])
Insert cell
maxDiameter = 25
Insert cell
padding = (circumference - totalValue) / (hierarchy.leaves().length - 1)
Insert cell
circumference = width * 2 * Math.PI
Insert cell
totalValue = d3.sum(hierarchy.leaves(), (d) => sizeScale(d.value) * 2)
Insert cell
data.csv
Type Table, then Shift-Enter. Ctrl-space for more options.

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