Skip to content

Commit d635c19

Browse files
duncanMRmergify[bot]
authored andcommitted
Add method to impute unknown mutation times
1 parent 3bc7e9b commit d635c19

File tree

3 files changed

+68
-0
lines changed

3 files changed

+68
-0
lines changed

python/CHANGELOG.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
--------------------
2+
[0.5.X] - 2023-XX-XX
3+
--------------------
4+
5+
**Features**
6+
7+
- Add ``TreeSequence.impute_unknown_mutations_time`` method to return an array of mutation times based on the times of associated nodes (:user:`duncanMR`, :pr:`2760`, :issue:`2758`)
8+
19
--------------------
210
[0.5.5] - 2023-05-17
311
--------------------

python/tests/test_highlevel.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2596,6 +2596,35 @@ def test_arrays_equal_to_tables(self, ts_fixture):
25962596
ts.indexes_edge_removal_order, tables.indexes.edge_removal_order
25972597
)
25982598

2599+
@pytest.mark.parametrize("ts", get_example_tree_sequences())
2600+
def test_impute_unknown_mutations_time(self, ts):
2601+
# Tests for method='min'
2602+
imputed_time = ts.impute_unknown_mutations_time(method="min")
2603+
mutations = ts.tables.mutations
2604+
nodes_time = ts.nodes_time
2605+
table_time = np.zeros(len(mutations))
2606+
2607+
for mut_idx, mut in enumerate(mutations):
2608+
if tskit.is_unknown_time(mut.time):
2609+
node_time = nodes_time[mut.node]
2610+
table_time[mut_idx] = node_time
2611+
else:
2612+
table_time[mut_idx] = mut.time
2613+
2614+
assert np.allclose(imputed_time, table_time, rtol=1e-10, atol=1e-10)
2615+
2616+
# Check we have valid times
2617+
tables = ts.dump_tables()
2618+
tables.mutations.time = imputed_time
2619+
tables.sort()
2620+
tables.tree_sequence()
2621+
2622+
# Test for unallowed methods
2623+
with pytest.raises(
2624+
ValueError, match="Mutations time imputation method must be chosen"
2625+
):
2626+
ts.impute_unknown_mutations_time(method="foobar")
2627+
25992628

26002629
class TestSimplify:
26012630
# This class was factored out of the old TestHighlevel class 2022-12-13,

python/tskit/trees.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8270,6 +8270,7 @@ def Tajimas_D(self, sample_sets=None, windows=None, mode="site"):
82708270
:return: A ndarray with shape equal to (num windows, num statistics).
82718271
If there is one sample set and windows=None, a numpy scalar is returned.
82728272
"""
8273+
82738274
# TODO this should be done in C as we'll want to support this method there.
82748275
def tjd_func(sample_set_sizes, flattened, **kwargs):
82758276
n = sample_set_sizes
@@ -8882,6 +8883,36 @@ def coalescence_time_distribution(
88828883
span_normalise=span_normalise,
88838884
)
88848885

8886+
def impute_unknown_mutations_time(
8887+
self,
8888+
method=None,
8889+
):
8890+
"""
8891+
Returns an array of mutation times, where any unknown times are
8892+
imputed from the times of associated nodes. Not to be confused with
8893+
:meth:`TableCollection.compute_mutation_times`, which modifies the
8894+
``time`` column of the mutations table in place.
8895+
8896+
:param str method: The method used to impute the unknown mutation times.
8897+
Currently only "min" is supported, which uses the time of the node
8898+
below the mutation as the mutation time. The "min" method can also
8899+
be specified by ``method=None`` (Default: ``None``).
8900+
:return: An array of length equal to the number of mutations in the
8901+
tree sequence.
8902+
"""
8903+
allowed_methods = ["min"]
8904+
if method is None:
8905+
method = "min"
8906+
if method not in allowed_methods:
8907+
raise ValueError(
8908+
f"Mutations time imputation method must be chosen from {allowed_methods}"
8909+
)
8910+
if method == "min":
8911+
mutations_time = self.mutations_time.copy()
8912+
unknown = tskit.is_unknown_time(mutations_time)
8913+
mutations_time[unknown] = self.nodes_time[self.mutations_node[unknown]]
8914+
return mutations_time
8915+
88858916
############################################
88868917
#
88878918
# Deprecated APIs. These are either already unsupported, or will be unsupported in a

0 commit comments

Comments
 (0)