Public
Edited
Jul 16, 2024
Insert cell
Insert cell
{
const root = tree;
const links = root.links();
const nodes = root.descendants();

const height =
rings_d[rings_d.length - 1] * 2 + rings[rings.length - 1].r + offset;
const width = height;

const svg = d3
.create("svg")
.attr("viewBox", [-width / 2, -height / 2, width, height])
.attr(
"style",
"max-width: 100%; height: auto; font: 10px sans-serif; background-color: #fff;"
);

svg
.append("g")
.selectAll("circle")
.data(rings)
.enter()
.append("circle")
.attr("cx", 0)
.attr("cy", 0)
.attr("fill", "none")
.attr("stroke", "#eee")
.attr("r", (d, i) => rings_d[i]);

const link = svg
.append("g")
.attr("stroke", "#999")
.attr("stroke-opacity", 0.6)
.selectAll("line")
.data(links)
.join("line")
.attr(
"x1",
(d) => rings_d[d.source.depth] * Math.cos(xy_polars(d.source.x))
)
.attr(
"y1",
(d) => rings_d[d.source.depth] * Math.sin(xy_polars(d.source.x))
)
.attr(
"x2",
(d) => rings_d[d.target.depth] * Math.cos(xy_polars(d.target.x))
)
.attr(
"y2",
(d) => rings_d[d.target.depth] * Math.sin(xy_polars(d.target.x))
);

const node = svg.append("g").selectAll("g").data(nodes).enter().append("g");

const circle = node
.append("circle")
.attr("fill", (d) => (d.children ? "white" : "black"))
.attr("stroke", (d) => (d.children ? "black" : "none"))
.attr("r", (d) => radius(d.data.descendants))
.attr("cx", (d) => rings_d[d.depth] * Math.cos(xy_polars(d.x)))
.attr("cy", (d) => rings_d[d.depth] * Math.sin(xy_polars(d.x)));

const labels = node
.append("g")
.append("text")
.attr("dy", "0.31em")
//.attr("x", (d) => (d.children ? -6 : 6))
.attr("x", (d) => rings_d[d.depth] * Math.cos(xy_polars(d.x)))
.attr("y", (d) => rings_d[d.depth] * Math.sin(xy_polars(d.x)))
.attr("text-anchor", "middle")
.text((d) => d.data.name)
.clone(true)
.lower()
.attr("stroke-width", 2.5)
.attr("stroke", "white");

return svg.node();
}
Insert cell
xy_polars = d3
.scaleLinear()
.domain([
d3.min(
d3
.tree()
.nodeSize([1, 1])(tree)
.descendants()
.map((d) => d.x)
),
d3.max(
d3
.tree()
.nodeSize([1, 1])(tree)
.descendants()
.map((d) => d.x)
)
])
.range([0, 2 * Math.PI])
Insert cell
offset = 100
Insert cell
rings_d = d3.range(tree.height + 1).map((depth) => {
const previous = d3.sum(
//d3.cumsum(
rings.filter((r, i) => i < depth && i > 0).map((r) => 2 * r.r + offset)
//)
);

return depth == 0 ? 0 : rings[0].r + offset + previous + rings[depth].r;
})
Insert cell
rings = {
return d3.range(tree.height + 1).map((depth) => {
const nodes = tree.descendants().filter((n) => n.depth == depth);
const r = d3.max(nodes.map((n) => radius(n.descendants().length)));
return {
r,
nodes
};
});
}
Insert cell
root = entreprises.filter((e) => e.parent == null)[0]
Insert cell
data = {
let graph = {
name: root.nom,
children: findSubsididiaries(root.nom),
descendants: d3.sum(
findSubsididiaries(root.nom).map((s) => s.descendants + 1)
)
};

return graph;
}
Insert cell
tree = d3.tree().nodeSize([1, 1])(d3.hierarchy(data))
Insert cell
radius = d3
.scaleSqrt()
.domain([0, d3.max(tree.descendants().map((n) => n.descendants().length))])
.range([10, 50])
Insert cell
entreprises = d3.csv(
getCsvUrl(
//https://docs.google.com/spreadsheets/d/1zmdPsrOou_hFo8g7Zf-3jC6sZ-omVE_j69MCP3L1dDg/edit?usp=sharing
"https://docs.google.com/spreadsheets/d/1zmdPsrOou_hFo8g7Zf-3jC6sZ-omVE_j69MCP3L1dDg/edit#gid=0"
),
d3.autoType
)
Insert cell
function findSubsididiaries(entreprise) {
return entreprises
.filter((x) => x.parent == entreprise)
.map((x) => {
const subsidiaries = findSubsididiaries(x.nom);
const descendants = d3.sum(subsidiaries.map((s) => s.descendants + 1));

return {
name: x.nom,
children: subsidiaries,
descendants
//radius: radius(descendants)
};
});
}
Insert cell
getCsvUrl = (url) => {
url = new URL(url);
const id = url.pathname.split("/")[3];
const gid = new URLSearchParams(url.hash.slice(1)).get("gid") || 0;
return `https://docs.google.com/spreadsheets/d/${id}/export?format=csv&gid=${gid}`;
}
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