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

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