Skip to content

Commit

Permalink
Merge pull request #1792 from grahamgower/demes-docs
Browse files Browse the repository at this point in the history
Fill out demes docs in demography chapter.
  • Loading branch information
mergify[bot] authored Jul 29, 2021
2 parents cfb10e0 + 55242c6 commit 2e756ad
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 8 deletions.
1 change: 1 addition & 0 deletions docs/_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ sphinx:
pyslim: ["https://tskit.dev/pyslim/docs/latest/", null]
numpy: ["https://numpy.org/doc/stable/", null]
demes: ["https://popsim-consortium.github.io/demes-docs/main/", null]
demes-spec: ["https://popsim-consortium.github.io/demes-spec-docs/main/", null]
nitpicky: true

autodoc_member_order: bysource
Expand Down
4 changes: 3 additions & 1 deletion docs/ancestry.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ kernelspec:
:tags: [remove-cell]
import msprime
from IPython.display import SVG
from IPython.display import SVG, set_matplotlib_formats
from matplotlib import pyplot as plt
import numpy as np
set_matplotlib_formats("svg")
```

(sec_ancestry)=
Expand Down
25 changes: 25 additions & 0 deletions docs/demes_example_01.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Comments start with a hash.
description:
Asymmetric migration between two extant demes.
time_units: generations
defaults:
epoch:
start_size: 5000
demes:
- name: X
epochs:
- end_time: 1000
- name: A
ancestors: [X]
- name: B
ancestors: [X]
epochs:
- start_size: 2000
end_time: 500
- start_size: 400
end_size: 10000
end_time: 0
migrations:
- source: A
dest: B
rate: 1e-4
114 changes: 109 additions & 5 deletions docs/demography.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ kernelspec:
import msprime
import numpy as np
import matplotlib.pyplot as plt
from IPython.display import SVG
from IPython.display import SVG, set_matplotlib_formats
set_matplotlib_formats("svg")
plt.rcParams["figure.figsize"] = (10,7)
```

Expand Down Expand Up @@ -1390,7 +1391,7 @@ into a "trunk" population. We illustrate this with a slightly different
version of the {ref}`example<sec_demography_examples_population_tree>` above,
this time defining only
four populations, as in this illustration of the model using
the [demography package](https://github.com/apragsdale/demography>)
the [demography package](https://github.com/apragsdale/demography)
(see also [Figure 2B](http://dx.doi.org/10.1371/journal.pgen.1000695.g002)
of the Gutenkunst et. al paper):

Expand Down Expand Up @@ -1514,16 +1515,119 @@ modelled in the oldest epochs.

(sec_demography_importing)=

## Importing model definitions
## Importing/exporting model definitions

(sec_demography_importing_demes)=

### Demes

```{eval-rst}
.. todo:: Details of how we import Demes models.
The [Demes format](https://popsim-consortium.github.io/demes-spec-docs/)
is intended to become a standard for writing demographic models,
to facilitate interchange between simulators, as well as between
demographic inference software and simulators.
Demes models are typically written as a YAML file (see the
[Demes tutorial](demes-spec:sec_tutorial) for details), and loaded into Python
using the [demes](demes:sec_introduction) library.
The {meth}`.Demography.from_demes` method converts a {class}`demes.Graph`
object into a {class}`.Demography` object, and the {meth}`.Demography.to_demes`
method does the opposite conversion.

```{warning}
Demes uses similar terminology to msprime, but uses different conventions.
In particular, Demes uses forwards-time conventions as opposed to the
{ref}`backwards-time <sec_demography_direction_of_time>` conventions used
in msprime
```

Demes models have time in units of "time ago", and when using generations as
the time units, the times will directly correspond to msprime's notion of time:
time 0 is "now" and time values increase towards the past.
However, in contrast to msprime, Demes uses forwards-time conventions.
Noteworthy differences between Demes and msprime include:

* Each deme has its own list of epochs, whereas in msprime's
{class}`.DemographyDebugger`, epochs are time intervals that apply across
the entire demography.
* Demes uses `start_time` and `end_time` to indicate time intervals,
but the `start_time` has a value which is larger (more ancient)
than the `end_time`.
* For migrations and pulses, `source` indicates the deme in which a migrant
is born and the `dest` indicates the deme in which a migrant has offspring.
This is opposite to the
{ref}`convention used in msprime <sec_demography_direction_of_time>`.

Consider the following Demes model that describes two extant demes `A` and `B`,
which have a common ancestor `X`.

```{literalinclude} demes_example_01.yaml
:language: yaml
```

When visualised using [demesdraw](https://github.com/grahamgower/demesdraw),
the demographic model looks like this (where arrows indicate movement of
individuals as time proceeds from the past to the present):

```{code-cell}
:tags: [remove-input]
import demes
import demesdraw
import matplotlib.pyplot as plt
graph = demes.load("demes_example_01.yaml")
w = 1.5 * demesdraw.utils.size_max(graph)
positions = dict(X=0, A=-w, B=w)
fig, ax = plt.subplots() # use plt.rcParams["figure.figsize"]
demesdraw.tubes(graph, ax=ax, positions=positions, seed=1)
plt.show()
```

Let's load this model using {func}`demes.load`, convert it to
a {class}`.Demography` object with {meth}`.Demography.from_demes`
and then look at the {class}`.DemographyDebugger` output.

```{code-cell}
import demes
graph = demes.load("demes_example_01.yaml")
demography = msprime.Demography.from_demes(graph)
demography.debug()
```

The demography debugger output shows three epochs. `Epoch[0]`
corresponds to the time interval [0, 500) generations ago, in which
deme `B` has an initial size of 10000 at time 0 and backwards in time,
shrinks in size to 400 individuals at time 500. Lineages sampled
from deme `B` migrate into deme `A` at a rate of 0.0001 per generation.
In `Epoch[1]`, [500, 1000) generations ago, both `A` and `B` have constant
sizes, and migration is the same as in `Epoch[0]`.
At the end of `Epoch[1]`, at generation 1000, lineages in demes `A` and `B`
are moved into deme `X` and migrations are turned off.
Finally, `Epoch[2]` shows that only deme `X` remains.

A {class}`.Demography` object can also be exported to a {class}`demes.Graph`,
using the {meth}`.Demography.to_demes` method. We'll use this to make a visual
representation of a modified {meth}`.Demography.island_model` using
[demesdraw](https://github.com/grahamgower/demesdraw).

```{code-cell}
import demesdraw
import matplotlib.pyplot as plt
demography = msprime.Demography.island_model([300] * 3, 1e-5)
demography.add_population(name="ancestral", initial_size=1000)
demography.add_population_split(time=500, derived=[0, 1, 2], ancestral="ancestral")
graph = msprime.Demography.to_demes(demography)
fig, ax = plt.subplots() # use plt.rcParams["figure.figsize"]
demesdraw.tubes(graph, ax=ax, seed=1)
plt.show()
```

The {class}`demes.Graph` can also be written to a YAML file,
e.g. for use with other simulation software.

```{code-cell}
demes.dump(graph, "/tmp/my-island-model.yaml")
```

(sec_demography_importing_species_trees)=

Expand Down
4 changes: 3 additions & 1 deletion docs/rate_maps.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ kernelspec:
import msprime
import numpy as np
from IPython.display import SVG
from IPython.display import SVG, set_matplotlib_formats
from matplotlib import pyplot as plt
set_matplotlib_formats("svg")
```

(sec_rate_maps)=
Expand Down
1 change: 0 additions & 1 deletion docs/replication.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ kernelspec:
import msprime
import numpy as np
from IPython.display import SVG
from matplotlib import pyplot as plt
```

(sec_randomness)=
Expand Down
4 changes: 4 additions & 0 deletions msprime/demography.py
Original file line number Diff line number Diff line change
Expand Up @@ -1843,6 +1843,9 @@ def from_demes(graph: demes.Graph) -> Demography:
"""
Creates a :class:`.Demography` object from the specified
:ref:`demes graph <demes:sec_introduction>`.
Time values in the demes graph may be specified in any units,
but the returned object has units converted into generations.
See the :ref:`sec_demography_importing_demes` section for details.
.. code::
Expand Down Expand Up @@ -2486,6 +2489,7 @@ def _american_admixture_model():
def to_demes(self) -> demes.Graph:
"""
Creates a :class:`demes.Graph` object from the demography.
See the :ref:`sec_demography_importing_demes` section for details.
.. note::
Expand Down
1 change: 1 addition & 0 deletions requirements/CI-docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
daiquiri==3.0.0
demes==0.1.2
demesdraw==0.1.4
jupyter-book==0.11.2
matplotlib==3.4.2
newick==1.3.0
Expand Down
1 change: 1 addition & 0 deletions requirements/development.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ codecov
coverage
daiquiri
demes>=0.1.2
demesdraw
flake8
hypothesis
matplotlib>=3.4.0
Expand Down

0 comments on commit 2e756ad

Please sign in to comment.