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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more