Quickstart

import numpy as np
import matplotlib.pyplot as plt
import bdms

Birth, death, and mutation processes

We define a simple binary process.

birth = bdms.poisson.DiscreteProcess([1.0, 2.0])
death = bdms.poisson.ConstantProcess(1.0)
mutation = bdms.poisson.ConstantProcess(1.0)
mutator = bdms.mutators.DiscreteMutator((0, 1), np.array([[0, 1], [1, 0]]))

Simulation

Initialize random number generator

rng = np.random.default_rng(seed=0)

Initialize a tree with a root node in state 0

tree = bdms.Tree(state=0)

Simulate for a specified time

time_to_sampling = 10.0

tree.evolve(
    time_to_sampling,
    birth_process=birth,
    death_process=death,
    mutation_process=mutation,
    mutator=mutator,
    seed=rng,
)

Randomly sample survivor tips

tree.sample_survivors(p=0.5, seed=rng)

Visualization

Define keyword arguments that we’ll use repeatedly for tree visualization

viz_kwargs = dict(
    color_map={0: "red", 1: "blue"},
    units="in",
    h=5,
    scale=20,
)

Render the full simulated tree

tree.render("%%inline", **viz_kwargs)
../_images/6e52dceb7a84c28d9b1de49434f15894135b2bcbf38758b9099896283f3e3511.png

Partially observed trees

Prune the tree to only include the ancestry of the sampled leaves

tree.prune_unsampled()
tree.render("%%inline", **viz_kwargs)
../_images/cac214c705cf34756c142a1d0cb7f8b6c4b678f32d72d85486ce8fa2f410420e.png

Also remove the mutation event unifurcations

tree.remove_mutation_events()
tree.render("%%inline", **viz_kwargs)
../_images/75d435d7ba9241d4549881ac03442e0f589ffcb816cc6784ae1fb814d23114ab.png

Inhomogeneous processes

We subclass the abstract class bdms.poisson.InhomogeneousProcess. To concretize, we must override its abstract method bdms.poisson.InhomogeneousProcess.λ_inhomogeneous(). We’ll use this for a death rate that linearly increases over time, and is independent of state.

class RampingProcess(bdms.poisson.InhomogeneousProcess):
    def __init__(self, intercept, slope, *args, **kwargs):
        self.intercept = intercept
        self.slope = slope
        super().__init__(*args, **kwargs)

    def λ_inhomogeneous(self, x, t):
        return self.intercept + self.slope * t
death = RampingProcess(0.5, 0.06)

Initialize tree as before

tree = bdms.Tree()
tree.state = 0

Simulate, sample, and visualize

tree.evolve(
    time_to_sampling,
    birth_process=birth,
    death_process=death,
    mutation_process=mutation,
    mutator=mutator,
    seed=rng,
)
tree.sample_survivors(p=0.1, seed=rng)
tree.render("%%inline", **viz_kwargs)
../_images/3e5f46c29bbec711b17cb704de1d8d4b41c70e87b25682086f1e5d772e94ea2d.png

Prune and visualize

tree.prune_unsampled()
tree.render("%%inline", **viz_kwargs)
../_images/061b01172ddf0b72d4c89cc59119af76b97a2f53dfc97ba525aa7469ac644c60.png
tree.remove_mutation_events()
tree.render("%%inline", **viz_kwargs)
../_images/83b2469a2ba7bb4a49e8fd1c66eee5b592e9b3a82ff0a50d26b23ec89ba5f2dc.png