{"spec_id":"tree-phylogenetic","library":"highcharts","language":"javascript","code":"// anyplot.ai\n// tree-phylogenetic: Phylogenetic Tree Diagram\n// Library: highcharts 12.6.0 | JavaScript 22.23.2\n// Quality: 93/100 | Created: 2026-09-09\n\nconst t = window.ANYPLOT_TOKENS;\n\n// --- Data --------------------------------------------------------------------\n// Simplified primate phylogeny (mitochondrial DNA), ultrametric so every tip\n// lands at the same evolutionary distance from the root. Each node carries its\n// cumulative x (substitutions per site from the root); the \"hominid\" flag\n// marks the great-ape clade (Hominidae) for the color highlight, and the\n// \"innerClade\" flag marks the tighter Human/Chimp/Bonobo split (Hominini) for\n// a second, bolder layer of emphasis nested inside it.\nconst tree = {\n  name: \"Anthropoidea\",\n  x: 0,\n  children: [\n    {\n      name: \"Catarrhini\",\n      x: 0.025,\n      children: [\n        {\n          name: \"Hominoidea\",\n          x: 0.045,\n          children: [\n            {\n              name: \"Hominidae\",\n              x: 0.06,\n              hominid: true,\n              children: [\n                {\n                  name: \"Homininae\",\n                  x: 0.072,\n                  children: [\n                    {\n                      name: \"Hominini\",\n                      x: 0.082,\n                      innerClade: true,\n                      children: [\n                        { name: \"Human\", x: 0.1 },\n                        {\n                          name: \"Pan\",\n                          x: 0.09,\n                          children: [\n                            { name: \"Chimpanzee\", x: 0.1 },\n                            { name: \"Bonobo\", x: 0.1 },\n                          ],\n                        },\n                      ],\n                    },\n                    { name: \"Gorilla\", x: 0.1 },\n                  ],\n                },\n                { name: \"Orangutan\", x: 0.1 },\n              ],\n            },\n            { name: \"Gibbon\", x: 0.1 },\n          ],\n        },\n        { name: \"Rhesus Macaque\", x: 0.1 },\n      ],\n    },\n    { name: \"Marmoset\", x: 0.1 },\n  ],\n};\n\n// --- Layout ------------------------------------------------------------------\n// y = leaf order (assigned depth-first), internal nodes take the midpoint of\n// their children's y. x is already fixed above (evolutionary distance).\nlet nextY = 0;\nconst assignY = (node) => {\n  if (!node.children) {\n    node.y = nextY;\n    nextY += 1;\n    return node.y;\n  }\n  const ys = node.children.map(assignY);\n  node.y = (ys[0] + ys[ys.length - 1]) / 2;\n  return node.y;\n};\nassignY(tree);\n\nconst branches = [];\nconst leaves = [];\nconst collect = (node, inheritedClade, inheritedInner) => {\n  const clade = node.hominid ? \"hominid\" : inheritedClade;\n  const inner = inheritedInner || Boolean(node.innerClade);\n  if (node.children) {\n    node.children.forEach((child) => {\n      const childClade = child.hominid ? \"hominid\" : clade;\n      const childInner = inner || Boolean(child.innerClade);\n      branches.push({\n        clade: childClade,\n        inner: childInner,\n        points: [\n          [node.x, node.y],\n          [node.x, child.y],\n          [child.x, child.y],\n        ],\n      });\n      collect(child, clade, inner);\n    });\n  } else {\n    leaves.push({ x: node.x, y: node.y, name: node.name, clade, inner });\n  }\n};\ncollect(tree, \"other\", false);\n\n// Hominini leaves (Human/Chimpanzee/Bonobo) sit at the low end of the y-axis;\n// used to place the in-plot clade labels below.\nconst innerLeafYs = leaves.filter((leaf) => leaf.inner).map((leaf) => leaf.y);\nconst hominidLeafYs = leaves.filter((leaf) => leaf.clade === \"hominid\").map((leaf) => leaf.y);\n\n// The JS harness tokens don't expose the \"muted\" semantic anchor — apply it\n// directly from the style guide (theme-adaptive: #6B6A63 light / #A8A79F dark).\nconst MUTED = t.theme === \"dark\" ? \"#A8A79F\" : \"#6B6A63\";\nconst cladeColor = { hominid: t.palette[0], other: MUTED };\n\n// --- Chart -------------------------------------------------------------------\nconst branchSeries = branches.map((branch) => ({\n  type: \"line\",\n  data: branch.points,\n  color: cladeColor[branch.clade],\n  lineWidth: branch.inner ? 3.5 : 2.5,\n  marker: { enabled: false },\n  enableMouseTracking: false,\n  showInLegend: false,\n}));\n\nconst leafSeries = {\n  type: \"scatter\",\n  name: \"Species\",\n  data: leaves.map((leaf) => ({\n    x: leaf.x,\n    y: leaf.y,\n    name: leaf.name,\n    color: cladeColor[leaf.clade],\n    marker: { radius: leaf.inner ? 6.5 : 5 },\n  })),\n  marker: { radius: 5, symbol: \"circle\", lineColor: t.pageBg, lineWidth: 1 },\n  dataLabels: {\n    enabled: true,\n    format: \"{point.name}\",\n    align: \"left\",\n    x: 10,\n    crop: false,\n    overflow: \"allow\",\n    style: { color: t.ink, fontSize: \"14px\", fontWeight: \"500\", textOutline: \"none\" },\n  },\n  tooltip: {\n    pointFormat: \"<b>{point.name}</b><br/>Distance from root: {point.x}\",\n  },\n  showInLegend: false,\n};\n\nHighcharts.chart(\"container\", {\n  chart: {\n    type: \"line\",\n    backgroundColor: \"transparent\",\n    animation: false,\n    style: { fontFamily: \"inherit\" },\n    spacingRight: 30,\n  },\n  credits: { enabled: false },\n  colors: t.palette,\n  title: {\n    text: \"tree-phylogenetic · javascript · highcharts · anyplot.ai\",\n    style: { color: t.ink, fontSize: \"22px\", fontWeight: \"600\" },\n  },\n  subtitle: {\n    text: \"Brand green marks the great-ape clade (Hominidae); muted grey marks the other primates\",\n    style: { color: t.inkSoft, fontSize: \"14px\" },\n  },\n  xAxis: {\n    min: 0,\n    max: 0.16,\n    title: {\n      text: \"Evolutionary distance (substitutions per site)\",\n      style: { color: t.inkSoft, fontSize: \"16px\" },\n    },\n    lineColor: t.inkSoft,\n    tickColor: t.inkSoft,\n    gridLineWidth: 0,\n    labels: { style: { color: t.inkSoft, fontSize: \"14px\" } },\n  },\n  yAxis: {\n    min: -0.8,\n    max: nextY - 0.2,\n    title: null,\n    labels: { enabled: false },\n    gridLineWidth: 0,\n    lineWidth: 0,\n    tickLength: 0,\n    // In-plot clade callouts (core plotBands, no add-on module) so the\n    // clade highlight reads without relying solely on the subtitle text,\n    // and so the tighter Hominini split shows as a nested second layer.\n    plotBands: [\n      {\n        from: Math.min(...hominidLeafYs) - 0.5,\n        to: Math.max(...hominidLeafYs) + 0.5,\n        color: Highcharts.color(t.palette[0]).setOpacity(0.06).get(),\n        label: {\n          text: \"Hominidae\",\n          align: \"left\",\n          x: 8,\n          verticalAlign: \"top\",\n          y: 16,\n          style: { color: t.palette[0], fontSize: \"12px\", fontWeight: \"600\" },\n        },\n      },\n      {\n        from: Math.min(...innerLeafYs) - 0.5,\n        to: Math.max(...innerLeafYs) + 0.5,\n        color: Highcharts.color(t.palette[0]).setOpacity(0.14).get(),\n        label: {\n          text: \"Human / Chimpanzee / Bonobo\",\n          align: \"left\",\n          x: 8,\n          verticalAlign: \"top\",\n          y: 16,\n          style: { color: t.palette[0], fontSize: \"12px\", fontWeight: \"600\" },\n        },\n      },\n    ],\n  },\n  legend: { enabled: false },\n  tooltip: { enabled: true },\n  plotOptions: { series: { animation: false } },\n  series: [...branchSeries, leafSeries],\n});\n"}