{"spec_id":"tree-phylogenetic","library":"plotly","language":"python","code":"\"\"\" anyplot.ai\ntree-phylogenetic: Phylogenetic Tree Diagram\nLibrary: plotly 6.7.0 | Python 3.13.13\nQuality: 91/100 | Updated: 2026-05-15\n\"\"\"\n\nimport os\nimport sys\n\n# Fix import conflict: remove current directory from sys.path\n_script_dir = os.path.dirname(os.path.abspath(__file__))\nsys.path = [p for p in sys.path if os.path.abspath(p) != _script_dir]\n\nimport plotly.graph_objects as go\n\n\n# Theme tokens\nTHEME = os.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG = \"#FAF8F1\" if THEME == \"light\" else \"#1A1A17\"\nINK = \"#1A1A17\" if THEME == \"light\" else \"#F0EFE8\"\nINK_SOFT = \"#4A4A44\" if THEME == \"light\" else \"#B8B7B0\"\nGRID = \"rgba(26,26,23,0.10)\" if THEME == \"light\" else \"rgba(240,239,232,0.10)\"\nBRAND = \"#009E73\"  # Okabe-Ito position 1\n\n# Old World monkeys phylogenetic tree based on mitochondrial DNA\n# Diverse group showing 8 species with varying evolutionary distances\n\nspecies = [\"Macaque\", \"Baboon\", \"Mandrill\", \"Gelada\", \"Langur\", \"Patas\", \"Guenon\", \"Talapoin\"]\n\n# Cumulative distances from root for rectangular phylogram\ndistances_from_root = {\n    \"Macaque\": 0.5,\n    \"Baboon\": 0.52,\n    \"Mandrill\": 0.54,\n    \"Gelada\": 0.53,\n    \"Langur\": 0.48,\n    \"Patas\": 0.51,\n    \"Guenon\": 0.49,\n    \"Talapoin\": 0.42,\n}\n\n# Internal node positions\ninternal_x = {\n    \"Root\": 0.0,\n    \"Cercopithecinae\": 0.18,\n    \"Papionini\": 0.28,\n    \"Macaque_group\": 0.38,\n    \"Baboon_group\": 0.42,\n    \"Colobinae\": 0.15,\n    \"Guenon_group\": 0.25,\n}\n\n# Y positions for species (leaf nodes)\nspecies_y = {\"Macaque\": 8, \"Baboon\": 7, \"Mandrill\": 6, \"Gelada\": 5, \"Langur\": 4, \"Patas\": 3, \"Guenon\": 2, \"Talapoin\": 1}\n\n# Y positions for internal nodes\ninternal_y = {\n    \"Macaque_group\": (species_y[\"Macaque\"] + species_y[\"Baboon\"]) / 2,\n    \"Papionini\": (species_y[\"Macaque\"] + species_y[\"Baboon\"] + species_y[\"Mandrill\"] + species_y[\"Gelada\"]) / 4,\n    \"Cercopithecinae\": (\n        (species_y[\"Macaque\"] + species_y[\"Baboon\"] + species_y[\"Mandrill\"] + species_y[\"Gelada\"]) / 4\n        + (species_y[\"Langur\"] + species_y[\"Patas\"] + species_y[\"Guenon\"] + species_y[\"Talapoin\"]) / 4\n    )\n    / 2,\n    \"Colobinae\": (species_y[\"Langur\"] + species_y[\"Patas\"]) / 2,\n    \"Guenon_group\": (species_y[\"Guenon\"] + species_y[\"Talapoin\"]) / 2,\n    \"Root\": 4.5,\n}\n\n# Tree structure connections\nconnections = [\n    (\"Macaque\", \"Macaque_group\"),\n    (\"Baboon\", \"Papionini\"),\n    (\"Mandrill\", \"Papionini\"),\n    (\"Gelada\", \"Papionini\"),\n    (\"Macaque_group\", \"Papionini\"),\n    (\"Langur\", \"Colobinae\"),\n    (\"Patas\", \"Cercopithecinae\"),\n    (\"Guenon\", \"Guenon_group\"),\n    (\"Talapoin\", \"Guenon_group\"),\n    (\"Colobinae\", \"Cercopithecinae\"),\n    (\"Guenon_group\", \"Cercopithecinae\"),\n    (\"Papionini\", \"Cercopithecinae\"),\n    (\"Cercopithecinae\", \"Root\"),\n]\n\n# Create edge traces for rectangular phylogram\nedge_x = []\nedge_y = []\n\nfor child, parent in connections:\n    child_x = distances_from_root[child] if child in species else internal_x[child]\n    child_y = species_y[child] if child in species else internal_y[child]\n\n    parent_x = internal_x[parent]\n    parent_y = internal_y[parent]\n\n    # Horizontal line\n    edge_x.extend([child_x, parent_x, None])\n    edge_y.extend([child_y, child_y, None])\n\n    # Vertical line\n    edge_x.extend([parent_x, parent_x, None])\n    edge_y.extend([child_y, parent_y, None])\n\n# Create figure\nfig = go.Figure()\n\n# Add branch lines\nfig.add_trace(\n    go.Scatter(\n        x=edge_x, y=edge_y, mode=\"lines\", line={\"color\": INK_SOFT, \"width\": 3}, hoverinfo=\"skip\", showlegend=False\n    )\n)\n\n# Add leaf nodes (species)\nleaf_x = [distances_from_root[s] for s in species]\nleaf_y = [species_y[s] for s in species]\n\nfig.add_trace(\n    go.Scatter(\n        x=leaf_x,\n        y=leaf_y,\n        mode=\"markers+text\",\n        marker={\"size\": 18, \"color\": BRAND, \"line\": {\"width\": 2, \"color\": INK_SOFT}},\n        text=species,\n        textposition=\"middle right\",\n        textfont={\"size\": 20, \"color\": INK},\n        hovertemplate=\"%{text}<br>Distance: %{x:.2f}<extra></extra>\",\n        showlegend=False,\n    )\n)\n\n# Add internal nodes\ninternal_nodes_x = list(internal_x.values())\ninternal_nodes_y = [internal_y.get(n, 4.5) for n in internal_x.keys()]\ninternal_labels = list(internal_x.keys())\n\nfig.add_trace(\n    go.Scatter(\n        x=internal_nodes_x,\n        y=internal_nodes_y,\n        mode=\"markers\",\n        marker={\"size\": 12, \"color\": INK_SOFT, \"symbol\": \"circle\"},\n        hovertemplate=\"%{text}<br>Distance: %{x:.2f}<extra></extra>\",\n        text=internal_labels,\n        showlegend=False,\n    )\n)\n\n# Add scale bar\nscale_bar_y = 0.3\nscale_bar_length = 0.1\nfig.add_trace(\n    go.Scatter(\n        x=[0, scale_bar_length],\n        y=[scale_bar_y, scale_bar_y],\n        mode=\"lines\",\n        line={\"color\": INK, \"width\": 3},\n        showlegend=False,\n        hoverinfo=\"skip\",\n    )\n)\n\n# Scale bar label\nfig.add_annotation(\n    x=scale_bar_length / 2,\n    y=scale_bar_y - 0.15,\n    text=\"0.1 substitutions/site\",\n    showarrow=False,\n    font={\"size\": 16, \"color\": INK_SOFT},\n)\n\n# Update layout\nfig.update_layout(\n    title={\n        \"text\": \"Old World Monkeys · tree-phylogenetic · plotly · anyplot.ai\",\n        \"font\": {\"size\": 28, \"color\": INK},\n        \"x\": 0.5,\n        \"xanchor\": \"center\",\n    },\n    xaxis={\n        \"title\": {\"text\": \"Evolutionary Distance (substitutions per site)\", \"font\": {\"size\": 22, \"color\": INK}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"range\": [-0.05, 0.60],\n        \"showgrid\": False,\n        \"zeroline\": False,\n        \"linecolor\": INK_SOFT,\n    },\n    yaxis={\n        \"title\": {\"text\": \"\", \"font\": {\"size\": 22}},\n        \"tickfont\": {\"size\": 18, \"color\": INK_SOFT},\n        \"range\": [0, 9],\n        \"showticklabels\": False,\n        \"showgrid\": False,\n        \"zeroline\": False,\n    },\n    plot_bgcolor=PAGE_BG,\n    paper_bgcolor=PAGE_BG,\n    margin={\"l\": 80, \"r\": 150, \"t\": 100, \"b\": 100},\n    showlegend=False,\n)\n\n# Save outputs\nfig.write_image(f\"plot-{THEME}.png\", width=1600, height=900, scale=3)\nfig.write_html(f\"plot-{THEME}.html\", include_plotlyjs=\"cdn\")\n"}