Public
Edited
Feb 1
Fork of Tree of Life
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
// Add a scroll listener to the window object and rotate the selected text according to the scroll
// we used * 0.15 to make the rotation looks smoother
// window.addEventListener("scroll", function () {
// chart.style.transform = `rotate(${window.scrollY * 0.15}deg)`;
// })
Insert cell
Insert cell
// pythotheca = Promise.all(
// (await FileAttachment("phytotheca-species-checked@1.json").json()).map(async (n) => {
// try {
// const imgblob =
// embedImages.length > 0
// ? await loadXHR(n.img.replace("http:", "https:"))
// : undefined;
// const sci_name = n.sci_name.trim();
// return { ...n, sci_name, imgblob };
// } catch (e) {}
// })
// )
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
update = chart.update(false)
Insert cell
cluster = d3
.cluster()
.size([360, innerRadius])
.separation((a, b) => 1)
Insert cell
// playCluster = {
// const root = d3
// .hierarchy(data, (d) => d.branchset)
// .sum((d) => (d.branchset ? 0 : 1))
// .sort(
// (a, b) => a.value - b.value || d3.ascending(a.data.length, b.data.length)
// );

// return cluster(root);
// }
Insert cell
color = d3
.scaleOrdinal()
.domain(["Opisthokonta", "Liliopsida", "eudicotyledons", "Magnoliidae"])
.range(d3.schemeCategory10)
Insert cell
// Compute the maximum cumulative length of any node in the tree.
function maxLength(d) {
return d.data.length + (d.children ? d3.max(d.children, maxLength) : 0);
}
Insert cell
// Set the radius of each node by recursively summing and scaling the distance from the root.
function setRadius(d, y0, k) {
d.radius = (y0 += d.data.length) * k;
if (d.children) d.children.forEach(d => setRadius(d, y0, k));
}
Insert cell
// Set the color of each node by recursively inheriting.
function setColor(d) {
var name = d.data.sci_name;
d.color =
color.domain().indexOf(name) >= 0
? color(name)
: d.parent
? d.parent.color
: null;
if (d.children) d.children.forEach(setColor);
// console.log("test", d.data, d.color);
}
Insert cell
function linkVariable(d) {
return linkStep(d.source.x, d.source.radius, d.target.x, d.target.radius);
}
Insert cell
function linkConstant(d) {
return linkStep(d.source.x, d.source.y, d.target.x, d.target.y);
}
Insert cell
function linkExtensionVariable(d) {
return linkStep(d.target.x, d.target.radius, d.target.x, innerRadius);
}
Insert cell
function linkExtensionConstant(d) {
return linkStep(d.target.x, d.target.y, d.target.x, innerRadius);
}
Insert cell
function linkStep(startAngle, startRadius, endAngle, endRadius) {
const c0 = Math.cos(startAngle = (startAngle - 90) / 180 * Math.PI);
const s0 = Math.sin(startAngle);
const c1 = Math.cos(endAngle = (endAngle - 90) / 180 * Math.PI);
const s1 = Math.sin(endAngle);
return "M" + startRadius * c0 + "," + startRadius * s0
+ (endAngle === startAngle ? "" : "A" + startRadius + "," + startRadius + " 0 0 " + (endAngle > startAngle ? 1 : 0) + " " + startRadius * c1 + "," + startRadius * s1)
+ "L" + endRadius * c1 + "," + endRadius * s1;
}
Insert cell
legend = (svg) => {
const g = svg
.selectAll("g")
.data(color.domain())
.join("g")
.attr(
"transform",
(d, i) => `translate(${-outerRadius},${-outerRadius + i * 20})`
);

g.append("rect").attr("width", 18).attr("height", 18).attr("fill", color);

const familiarName = {
Opisthokonta: "Fungi (Opisthokonta)",
Liliopsida: "Monocots (Liliopsida)",
eudicotyledons: "Dicots (eudicotyledons)",
Magnoliidae: "Magnolias, nutmeg, cinnamon, avocado… (Magnoliidae)"
};

g.append("text")
.attr("x", 24)
.attr("y", 9)
.attr("dy", "0.35em")
.text((d) => familiarName[d]);
}
Insert cell
data = parseNewick(example)
Insert cell
outerRadius = width / 2
Insert cell
innerRadius = outerRadius - 170
Insert cell
// https://github.com/jasondavies/newick.js
function parseNewick(a) {
for (
var e = [], r = {}, s = a.split(/\s*(;|\(|\)|,|:)\s*/), t = 0;
t < s.length;
t++
) {
var n = s[t];
switch (n) {
case "(":
var c = {};
(r.branchset = [c]), e.push(r), (r = c);
break;
case ",":
var c = {};
e[e.length - 1].branchset.push(c), (r = c);
break;
case ")":
r = e.pop();
break;
case ":":
break;
default:
var h = s[t - 1];
")" == h || "(" == h || "," == h
? (r.name = n)
: (r[n.match(/.*(sci_name)=(.*)/)?.[1]] =
n.match(/.*(sci_name)=(.*)/)?.[2]);
}
}
return r;
}
Insert cell
d3 = require("d3@6")
Insert cell
d3_annotation = require("https://cdnjs.cloudflare.com/ajax/libs/d3-annotation/2.3.2/d3-annotation.min.js")
Insert cell
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