Public
Edited
May 3, 2024
1 fork
1 star
Also listed in…
Hierarchies
D3
Insert cell
Insert cell
tree = {
const {pad, plot, M} = Grid(greyGrid).sketch();
pad.call(title("Tree Layout"));
const root = d3
.tree()
.size([M(4), M(2)])
(d3.hierarchy(data))
;
pad
.selectAll("line.link")
.data(root.links())
.join("line")
.classed("link", true)
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y)
.style("stroke", "grey")
;
const nodes = pad
.selectAll("#tree g.nodes")
.data(root.descendants())
.join("g")
.classed("node", true)
.call(handleEvents)
;
nodes.append("circle")
.classed("the-node solid", true)
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", d => 14)
.style("fill", primer)
;
nodes.append("text")
.attr("class", "label")
.attr("dx", d => d.x)
.attr("dy", d => d.y)
.text(d => d.data.name)
;
return plot();
}
Insert cell
cluster = {

const {pad, plot, M} = Grid(greyGrid).sketch();

pad.call(title("Cluster Layout"));
const root = d3
.cluster()
.size([M(4), M(2)])
(d3.hierarchy(data))
;
pad
.selectAll("line.link")
.data(root.links())
.join("line")
.classed("link", true)
.attr("x1", d => d.source.x)
.attr("y1", d => d.source.y)
.attr("x2", d => d.target.x)
.attr("y2", d => d.target.y)
.style("stroke", "darkgray")
;
const nodes = pad
.selectAll("g.node")
.data(root.descendants())
.join("g")
.classed("node", true)
.call(handleEvents)
;
nodes
.append("circle")
.classed("the-node solid", true)
.attr("cx", d => d.x)
.attr("cy", d => d.y)
.attr("r", 14)
.style("fill", primer)
;
nodes
.append("text")
.attr("class", "label")
.attr("dx", d => d.x)
.attr("dy", d => d.y)
.text( d => d.data.name)
;
return plot();
}
Insert cell
treemap = {

// https://observablehq.com/@d3/treemap

const {pad, plot, M} = Grid(greyGrid).sketch();

pad.call(title("Treemap Layout"));
const root =
d3
.treemap()
.paddingOuter(20)
.tile(d3.treemapSquarify.ratio(2))
.size([M(4), M(2)])
(d3.hierarchy(data).sum(d => d.value))
;
const nodes = pad
.selectAll("g.node")
.data(root.descendants())
.join("g")
.classed("node", true)
.attr("transform", d => `translate(${[d.x0, d.y0]})`)
.call(handleEvents)
;
nodes
.append("rect")
.classed("the-node", true)
.attr("width", d => d.x1 - d.x0)
.attr("height", d => d.y1 - d.y0)
.style("fill", primer)
.style("stroke", "#2f2f2f")
;
nodes
.append("text")
.attr("class", "label")
.attr("dx", d => 12)
.attr("dy", d => 7)
.text( d => d.data.name)
;
return plot();
}
Insert cell
pack = {

const {pad, plot, M} = Grid(greyGrid).sketch();

pad.call(title("Pack Layout"));
const root = d3
.pack()
.size([M(4), M(2)])
.padding(3)
(d3.hierarchy(data).sum(d => d.value))
;
const nodes = pad
.selectAll("#pack g")
.data(root.descendants())
.enter()
.append("g")
.classed("node", true)
.attr("transform", d => `translate(${[d.x, d.y]})`)
.call(handleEvents)
;
nodes
.append("circle")
.classed("the-node", true)
.attr("r", d => d.r)
.style("fill", primer)
.style("stroke", "#2f2f2f")
;
nodes
.append("text")
.attr("class", "label")
.text(d => d.children === undefined ? d.data.name : "")
;
return plot();
}
Insert cell
partition = {

const {pad, plot, M} = Grid(greyGrid).sketch();

pad.call(title("Partition Layout"));
const root = d3
.partition()
.size([M(4), M(2)])
(d3.hierarchy(data).sum(d => d.value))
;
const nodes = pad
.selectAll("#partition g")
.data(root.descendants())
.enter()
.append("g")
.classed("node", true)
.attr("transform", d => `translate(${[d.x0, d.y0]})`)
.call(handleEvents)
;
nodes
.append("rect")
.classed("the-node", true)
.attr("width", d => d.x1 - d.x0)
.attr("height", d => d.y1 - d.y0)
.style("fill", primer)
.style("stroke", "#2f2f2f")
;
nodes
.append("text")
.attr("class", "label")
.attr("dx", 12)
.attr("dy", 14)
.text( d => d.data.name)
;
return plot();
}
Insert cell
sunburst = {

const {pad, plot, M, µ} = Grid(greyGrid).sketch();

pad.call(title("Sunburst Layout"));
const radius = M(1);
const root = d3
.partition()
.size([2 * Math.PI, radius])
(d3.hierarchy(data).sum(d => d.value))
;
const arc = d3.arc()
.startAngle(d => d.x0)
.endAngle(d => d.x1)
.innerRadius(d => d.y0)
.outerRadius(d => d.y1)
;
// shift it down and right because center is at (0, 0)
// would overlap title if not shifted
const paper = pad
.append("svg")
.attr("x", radius)
.attr("y", radius)
.attr("overflow", "visible")
;
const nodes = paper
.selectAll("#partition-sunburst g")
.data(root.descendants())
.join("g")
.classed("node", true)
.call(handleEvents)
;
nodes
.append("path")
.attr("d", arc)
.classed("the-node", true)
.style("fill", primer)
.style("stroke", "#2f2f2f")
;
nodes
.append("text")
.attr("class", "label")
.attr("transform", d => `translate(${arc.centroid(d)})`)
.text(d => d.parent ? d.data.name : "")
;
return plot();
}
Insert cell
data = ({
"name": "A1",
"children": [
{
"name": "B1",
"children": [
{
"name": "C1",
"value": 100
},
{
"name": "C2",
"value": 300
},
{
"name": "C3",
"value": 200
}
]
},
{
"name": "B2",
"value": 200
}
]
});
Insert cell
primer = "grey"
Insert cell
handleEvents = function(selection) {
selection
.on("mouseover", function() {

const g = d3.select(this);
const n = g.select(".the-node");

if(n.classed("solid")) {
n.transition().duration(400)
.style("fill", "rgba(211,0,0,0.8)" )
.attr("r", 18);
} else {
n.transition().duration(400)
.style("fill", "rgba(211,0,0,0.8)" )
;
}

g.select(".label")
.transition().duration(200)
.style("opacity", 1)
.style("font-weight", 900)
;
})
.on("mouseout", function() {

const g = d3.select(this);
const n = g.select(".the-node");

if(n.classed("solid")) {
n.transition().duration(400)
.style("fill", primer )
.attr("r",14);
} else {
n.transition().duration(400)
.style("fill", primer )
}
g.select(".label")
.transition().duration(200)
.style("opacity", .5)
.style("font-weight", 400)
;
});
}

Insert cell
<style>

.label {
text-anchor: middle;
alignment-baseline: central;
font-family: sans-serif;
font-size: .7rem;
fill: white;
opacity: .5;
pointer-events : none;
}

.node {
cursor : pointer;
}

</style>
Insert cell
greyGrid = ({
background: "#32333A",
pan: {h: -.1, v: -.3},
aspect: {wide: 5, tall: 4},
wide: width/2,
divisions: 4,
// showGrid,
// position,
stroke: "grey",
opacity: 1/4,
})
Insert cell
µ = (n = 1) => 3 * n
Insert cell
title = (text) => (node) => {
node
.append("text")
.text(text)
.style("font-size", "18pt")
.style("font-family", "sans-serif")
.style("font-weight", 900)
.style("fill", "red")
.attr("x", µ(-6))
.attr("y", µ(-18))
;
}
Insert cell
import {Grid} from "@martien/gridder"
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