{"spec_id":"tree-phylogenetic","library":"ggplot2","language":"r","code":"#' anyplot.ai\n#' tree-phylogenetic: Phylogenetic Tree Diagram\n#' Library: ggplot2 3.5.1 | R 4.4.1\n#' Quality: 92/100 | Created: 2026-09-09\n\nlibrary(ggplot2)\nlibrary(dplyr)\nlibrary(ragg)\n\nset.seed(42)\n\n# --- Theme tokens -----------------------------------------------------------\nTHEME       <- Sys.getenv(\"ANYPLOT_THEME\", \"light\")\nPAGE_BG     <- if (THEME == \"light\") \"#FAF8F1\" else \"#1A1A17\"\nINK         <- if (THEME == \"light\") \"#1A1A17\" else \"#F0EFE8\"\nINK_SOFT    <- if (THEME == \"light\") \"#4A4A44\" else \"#B8B7B0\"\nINK_MUTED   <- if (THEME == \"light\") \"#6B6A63\" else \"#A8A79F\"\nIMPRINT_PALETTE <- c(\"#009E73\", \"#C475FD\", \"#4467A3\", \"#BD8233\",\n                     \"#AE3030\", \"#2ABCCD\", \"#954477\", \"#99B314\")\nBRAND       <- IMPRINT_PALETTE[1]\n\n# --- Data ---------------------------------------------------------------\n# Primate phylogeny with divergence times (millions of years ago, mtDNA-based\n# estimates). Ultrametric time tree: every tip sits at the present (age 0);\n# internal-node x is its divergence age. Plotted as x = -age so tips align at\n# x = 0 and the tree grows leftward into the past, with species labels\n# readable to the right of the tips.\ntips <- tibble::tibble(\n  label = c(\"Human\", \"Chimpanzee\", \"Gorilla\", \"Orangutan\",\n            \"Gibbon\", \"Rhesus Macaque\", \"Common Marmoset\"),\n  y     = c(7, 6, 5, 4, 3, 2, 1),\n  clade = c(\"Great apes (Hominidae)\", \"Great apes (Hominidae)\",\n            \"Great apes (Hominidae)\", \"Great apes (Hominidae)\",\n            \"Other primates\", \"Other primates\", \"Other primates\")\n) %>%\n  mutate(x = 0)\n\n# Internal nodes: age = divergence time (Mya), y = midpoint of children\nnodes <- tibble::tibble(\n  node  = c(\"human_chimp\", \"homini\", \"hominid\", \"hominoid\", \"catarrhini\"),\n  age   = c(6, 8, 15, 18, 29),\n  y     = c((7 + 6) / 2, ((7 + 6) / 2 + 5) / 2,\n            (((7 + 6) / 2 + 5) / 2 + 4) / 2,\n            ((((7 + 6) / 2 + 5) / 2 + 4) / 2 + 3) / 2,\n            (((((7 + 6) / 2 + 5) / 2 + 4) / 2 + 3) / 2 + 2) / 2)\n) %>%\n  mutate(x = -age)\nroot_age <- 43\nroot_y   <- (nodes$y[nodes$node == \"catarrhini\"] + 1) / 2\n\n# Horizontal branches: x = ancestor age, xend = descendant age, at descendant y\nbranches <- tibble::tibble(\n  x     = c(nodes$x[nodes$node == \"human_chimp\"],\n            nodes$x[nodes$node == \"human_chimp\"],\n            nodes$x[nodes$node == \"homini\"],\n            nodes$x[nodes$node == \"homini\"],\n            nodes$x[nodes$node == \"hominid\"],\n            nodes$x[nodes$node == \"hominid\"],\n            nodes$x[nodes$node == \"hominoid\"],\n            nodes$x[nodes$node == \"hominoid\"],\n            nodes$x[nodes$node == \"catarrhini\"],\n            nodes$x[nodes$node == \"catarrhini\"],\n            -root_age,\n            -root_age),\n  xend  = c(0, 0,\n            nodes$x[nodes$node == \"human_chimp\"],\n            0,\n            nodes$x[nodes$node == \"homini\"],\n            0,\n            nodes$x[nodes$node == \"hominid\"],\n            0,\n            nodes$x[nodes$node == \"hominoid\"],\n            0,\n            nodes$x[nodes$node == \"catarrhini\"],\n            0),\n  y     = c(7, 6,\n            nodes$y[nodes$node == \"human_chimp\"],\n            5,\n            nodes$y[nodes$node == \"homini\"],\n            4,\n            nodes$y[nodes$node == \"hominid\"],\n            3,\n            nodes$y[nodes$node == \"hominoid\"],\n            2,\n            nodes$y[nodes$node == \"catarrhini\"],\n            1),\n  clade = c(\"Great apes (Hominidae)\", \"Great apes (Hominidae)\",\n            \"Great apes (Hominidae)\",\n            \"Great apes (Hominidae)\",\n            \"Great apes (Hominidae)\",\n            \"Great apes (Hominidae)\",\n            \"Great apes (Hominidae)\",\n            \"Other primates\",\n            \"Other primates\",\n            \"Other primates\",\n            \"Other primates\",\n            \"Other primates\")\n) %>%\n  mutate(yend = y)\n\n# Vertical connectors at each internal node, spanning its two children\nconnectors <- tibble::tibble(\n  x     = c(nodes$x[nodes$node == \"human_chimp\"],\n            nodes$x[nodes$node == \"homini\"],\n            nodes$x[nodes$node == \"hominid\"],\n            nodes$x[nodes$node == \"hominoid\"],\n            nodes$x[nodes$node == \"catarrhini\"],\n            -root_age),\n  y     = c(6, 5, 4, 3, 2, 1),\n  yend  = c(7,\n            nodes$y[nodes$node == \"human_chimp\"],\n            nodes$y[nodes$node == \"homini\"],\n            nodes$y[nodes$node == \"hominid\"],\n            nodes$y[nodes$node == \"hominoid\"],\n            nodes$y[nodes$node == \"catarrhini\"]),\n  clade = c(\"Great apes (Hominidae)\", \"Great apes (Hominidae)\",\n            \"Great apes (Hominidae)\", \"Other primates\", \"Other primates\",\n            \"Other primates\")\n) %>%\n  mutate(xend = x)\n\nbranch_lines <- bind_rows(branches, connectors)\n\n# --- Plot -----------------------------------------------------------------\np <- ggplot() +\n  geom_segment(\n    data = branch_lines,\n    aes(x = x, xend = xend, y = y, yend = yend, color = clade),\n    linewidth = 1.4, lineend = \"round\"\n  ) +\n  geom_point(data = tips, aes(x = x, y = y, color = clade), size = 3.4) +\n  geom_text(\n    data = tips, aes(x = x, y = y, label = label, color = clade),\n    hjust = 0, nudge_x = 1, size = 3.5, fontface = \"italic\",\n    show.legend = FALSE\n  ) +\n  scale_color_manual(values = c(\"Great apes (Hominidae)\" = BRAND,\n                                 \"Other primates\" = INK_MUTED)) +\n  scale_x_continuous(\n    breaks = seq(-40, 0, by = 10),\n    labels = abs(seq(-40, 0, by = 10)),\n    limits = c(-root_age - 2, 14)\n  ) +\n  scale_y_continuous(limits = c(0.3, 7.7)) +\n  labs(\n    title = \"Primate Phylogeny · tree-phylogenetic · r · ggplot2 · anyplot.ai\",\n    x = \"Divergence time (millions of years ago)\",\n    color = \"Clade\"\n  ) +\n  theme_minimal(base_size = 8) +\n  theme(\n    plot.background     = element_rect(fill = PAGE_BG, color = PAGE_BG),\n    panel.background    = element_rect(fill = PAGE_BG, color = NA),\n    panel.grid.major.x  = element_line(color = INK, linewidth = 0.25),\n    panel.grid.minor.x  = element_blank(),\n    panel.grid.major.y  = element_blank(),\n    panel.grid.minor.y  = element_blank(),\n    axis.title.x        = element_text(color = INK, size = 10),\n    axis.title.y        = element_blank(),\n    axis.text.x         = element_text(color = INK_SOFT, size = 8),\n    axis.text.y         = element_blank(),\n    axis.ticks          = element_blank(),\n    plot.title          = element_text(color = INK, size = 12),\n    legend.position     = \"bottom\",\n    legend.title        = element_text(color = INK, size = 10),\n    legend.text         = element_text(color = INK_SOFT, size = 8),\n    legend.background   = element_rect(fill = PAGE_BG, color = NA),\n    legend.key          = element_rect(fill = PAGE_BG, color = NA),\n    plot.margin         = margin(t = 10, r = 20, b = 5, l = 5)\n  )\n\n# --- Save -------------------------------------------------------------------\nggsave(\n  filename = sprintf(\"plot-%s.png\", THEME),\n  plot     = p,\n  device   = ragg::agg_png,\n  width    = 8,\n  height   = 4.5,\n  units    = \"in\",\n  dpi      = 400\n)\n"}