Quickstart

This page gives some simple examples of how to use the major features of msprime, with links to more detailed documentation and tutorial content.

See the Installation page for instructions on installing msprime (short version: pip install msprime or conda install -c conda-forge msprime will work for most users).

Ancestry

Msprime simulates ancestral histories for a set of sample genomes using backwards-in-time population genetic models. Here we run a simple simulation of a short recombining sequence under human-like parameters:

    import msprime
    from IPython.display import SVG, display

    # Simulate an ancestral history for 3 diploid samples under the coalescent
    # with recombination on a 5kb region with human-like parameters.
    ts = msprime.sim_ancestry(
        samples=3,
        recombination_rate=1e-8,
        sequence_length=5_000,
        population_size=10_000,
        random_seed=123456)
    # Visualise the simulated ancestral history.
    SVG(ts.draw_svg())
_images/quickstart_1_0.svg

In this example we simulate the ancestral history of three diploid individuals (see Specifying samples and Ploidy) for a 5kb sequence with a recombination rate of \(10^{-8}\) (see Genome properties) from a population with a constant size of 10,000 (see the Demography section below) under the default coalescent ancestry model (see the Models for details on other available models). To ensure that the output of this example is predictable, we set a random seed (see Random seeds).

When recombination is present, the ancestry of a sample of DNA sequences cannot be represented by a single genealogical tree relating the samples to their genetic ancestors; there is instead a sequence of highly correlated trees along the genome. The result of our simulation is therefore a tree sequence object from the tskit library, which provides a rich suite of operations for analysing these genealogical histories: see the Getting started with tskit tutorial for help. In this example we show a visualisation of the four different trees along the 5kb region (see the Visualization tutorial for more examples). Because we have specified three diploid sample individuals, each of these trees has 6 “sample” nodes (the “leaves” or “tips”), because each diploid individual has two monoploid genomes (see Specifying samples).

See the Ancestry simulations section for more details on ancestry simulations.

Mutations

The sim_ancestry() function generates a simulated ancestral history for some samples. If we want genome sequence we must also simulate some mutations on these trees. However, it’s important to note that it’s not always necessary to simulate mutations in order to use the simulations; often, it’s better not to; see the Do you really need mutations? tutorial for more information.

Given an input tree sequence (which may be generated by msprime or any other simulator that supports tskit output), we can superimpose mutations on that ancestral history using the sim_mutations() function under a number of different models of sequence evolution. For example, here we generate some mutations for the tree sequence simulated in the previous section under the Jukes-Cantor model:

mutated_ts = msprime.sim_mutations(ts, rate=1e-8, random_seed=54321)
SVG(mutated_ts.draw_svg())
_images/quickstart_3_0.svg

This visualisation shows us where the mutations occurred both in terms of position along the genome (the tick marks with red chevrons on the x-axis) and the branches of trees that they occurred on (the red crosses). This information is stored in the tskit site and mutation tables:

mutated_ts.tables.sites
idpositionancestral_statemetadata
090.00000000T
1333.00000000G
2819.00000000T
33204.00000000A
mutated_ts.tables.mutations
idsitenodetimederived_stateparentmetadata
001012191.4064954057G-1
111044173.26473294006C-1
2299597.219523507081G-1
3331158.4291490099815C-1

The combination of sites and mutations on a given ancestry then defines the variants, which we can access using the variants() method:

for variant in mutated_ts.variants():
    print(variant)
{'site': {'id': 0, 'position': 90.0, 'ancestral_state': 'T', 'mutations': [{'id': 0, 'site': 0, 'node': 10, 'time': 12191.4064954057, 'derived_state': 'G', 'parent': -1, 'metadata': b''}], 'metadata': b''}, 'alleles': ('T', 'G'), 'has_missing_data': False, 'num_alleles': 2, 'genotypes': array([1, 1, 1, 0, 1, 1], dtype=int8), 'position': 90.0, 'index': 0}
{'site': {'id': 1, 'position': 333.0, 'ancestral_state': 'G', 'mutations': [{'id': 1, 'site': 1, 'node': 10, 'time': 44173.26473294006, 'derived_state': 'C', 'parent': -1, 'metadata': b''}], 'metadata': b''}, 'alleles': ('G', 'C'), 'has_missing_data': False, 'num_alleles': 2, 'genotypes': array([1, 1, 1, 0, 1, 1], dtype=int8), 'position': 333.0, 'index': 1}
{'site': {'id': 2, 'position': 819.0, 'ancestral_state': 'T', 'mutations': [{'id': 2, 'site': 2, 'node': 9, 'time': 9597.219523507081, 'derived_state': 'G', 'parent': -1, 'metadata': b''}], 'metadata': b''}, 'alleles': ('T', 'G'), 'has_missing_data': False, 'num_alleles': 2, 'genotypes': array([1, 0, 1, 0, 1, 0], dtype=int8), 'position': 819.0, 'index': 2}
{'site': {'id': 3, 'position': 3204.0, 'ancestral_state': 'A', 'mutations': [{'id': 3, 'site': 3, 'node': 3, 'time': 1158.4291490099815, 'derived_state': 'C', 'parent': -1, 'metadata': b''}], 'metadata': b''}, 'alleles': ('A', 'C'), 'has_missing_data': False, 'num_alleles': 2, 'genotypes': array([0, 0, 0, 1, 0, 0], dtype=int8), 'position': 3204.0, 'index': 3}

See also

See Getting started with tskit tutorial for more information on how to use tree sequences to efficiently store and analyse data.

Demography

By default ancestry simulations assume an extremely simple population structure in which a single randomly mating population of a fixed size exists for all time. For most simulations this is an unrealistic assumption, and so msprime provides a way to describe more complex demographic models using the demography API.

For example, here we define a simple three population model in which populations “A” and “B” split from “C” 500 generations ago:

demography = msprime.Demography()
demography.add_population(name="A", initial_size=10_000)
demography.add_population(name="B", initial_size=5_000)
demography.add_population(name="C", initial_size=1_000)
demography.add_population_split(time=500, derived=["A", "B"], ancestral="C")
demography
Populations (3)
idnamedescriptioninitial_sizegrowth_ratedefault_sampling_timeextra_metadata
0A10000.000{}
1B5000.000{}
2C1000.005e+02{}
Migration matrix (all zero)
Events (1)
timetypeparameterseffect
500Population Splitderived=[A, B], ancestral=CMoves all lineages from derived populations 'A' and 'B' to the ancestral 'C' population. Also set the derived populations to inactive, and all migration rates to and from the derived populations to zero.

The demography API provides debugging tools to help understand and visualise the demographic models we define, as well as some numerical methods to provide analytical predictions about these models.

We can then simulate ancestral histories conditioned on these models using sim_ancestry(). For example, here we simulate 5 diploid sample individuals from populations “A” and “B”:

ts = msprime.sim_ancestry({"A": 5, "B": 5}, demography=demography, random_seed=123)
ts
Tree Sequence
Trees1
Sequence Length1.0
Sample Nodes20
Total Size4.4 KiB
MetadataNo Metadata
Table Rows Size Has Metadata
Edges 38 1.0 KiB
Individuals 10 172 Bytes
Migrations 0 4 Bytes
Mutations 0 8 Bytes
Nodes 39 940 Bytes
Populations 3 278 Bytes
Provenances 1 1.6 KiB
Sites 0 8 Bytes

See the Demographic models section for more details on defining demographic models, and the Specifying samples section for more details on how to specify samples under these models in ancestry simulations.