Click any figure for the code that produces it. Every example simulates with ZOMBI2 and plots with Phylustrator, a separate package — so to run one you need both:
pip install zombi2 phylustrator
Forward birth–death trees — the whole history, survivors and extinctions, with the diversification model made visible.
Pure birth, no extinction — a forward tree of 100 lineages.
pure birth (Yule)The full history behind 100 survivors — their branches solid, extinct lineages dashed.
birth–deathA pulse at t = 3 culls 75% of lineages — the skyline drops sharply at the dashed line, then recovers.
mass extinction · + skylineSpeciation runs slow, then fast, then slow — the burst packs branches between the two dashed regime lines.
time-varying birthSpeciation slows as diversity fills up; the skyline rises and plateaus at the cap of 100.
birth–death · + skylineGenes on chromosomes — a genome as a ring, synteny between genomes, and gene-family events and copy number read against the species tree.
A genome as a ring — genes evenly spaced by rank, coloured by family, arrows by strand. plot(g, layout="circular") + genes().
Two genomes, one per row; ribbons link same-family genes and cross where the order was rearranged. stack([a,b]) + synteny().
One family's history on the species tree: duplications (squares), losses (crosses) and transfers (arrows, donor→recipient). plot(tree) + branch_events(…).
A family × genome copy-number heatmap, its rows locked to the tips. beside(tree, heatmap(profiles)).
A real bacterium — Mycoplasma genitalium, 546 genes at their true base positions, coloured by strand; the forward/reverse switch marks the replication origin. read_gff(…).
The dated tree the sequences evolve down, and an alignment lined up row-for-row with its tips.
The clock tree the sequences evolve down — branch lengths are substitutions/site under an uncorrelated relaxed clock, so the tips are not level.
phylustrator · phylogramA single-copy family across 20 species, residues coloured (with a nucleotide key), each row locked to its tip. beside(tree, alignment(aln)).
A trait evolving down the tree — branches coloured by its value; some paired with a companion panel.
Free diffusion — sister lineages drift apart with time.
continuousPulled to an optimum: a high start (yellow) converges to blue.
continuousA two-state trait hops between habitats; each branch is painted by its state history.
discrete · MkTwo traits evolve together (r = 0.9) — two trees, coloured by each trait, and the tip scatter.
continuous · + scatterTwo binary characters where one's flip rate depends on the other's state — the model as a 2×2 chain (arrow width = rate), and a run: the tree painted by compound state, beside the presence/absence tips. simulate_discrete(states=("00",…), switch={…}).
One level drives another through one mechanism: a trait drives diversification so its state shapes the tree, or a trait conditions the genome — driving gene loss — so its state shapes genome size.
A two-state trait drives speciation — the fast state's clades take over; the inset is the state Markov chain.
trait → speciationOne state dies far faster; the doomed lineages (dashed) drop out.
trait → extinctionThree graded speciation rates with constant death — the fastest state fills the tree, extinct lineages dashed.
trait → speciationThe same coupling, aimed at the genome instead of the tree: an irreversible endosymbiont lifestyle drives fast gene loss and near-zero gene gain, so those lineages' genomes collapse. Tree coloured by lifestyle; bars are per-tip genome size.
trait → genome