diff --git a/python/CHANGELOG.rst b/python/CHANGELOG.rst index 6cfc075bbf..1fd56f3b01 100644 --- a/python/CHANGELOG.rst +++ b/python/CHANGELOG.rst @@ -37,6 +37,10 @@ - Add the ``centre`` option to ``TreeSequence.genetic_relatedness`` and ``TreeSequence.genetic_relatedness_weighted``. +- Add ``Interval.mid`` and ``Tree.mid`` properties to return the midpoint of the interval. + (:user:`currocam`, :pr:`2960`) + + -------------------- [0.5.7] - 2024-06-17 -------------------- @@ -54,7 +58,7 @@ `TreeSequence.allele_frequency_spectrum(mode="branch", polarised=False)`, which was half as big as it should have been. (:user:`petrelharp`, :user:`nspope`, :pr:`2933`) - + -------------------- [0.5.6] - 2023-10-10 -------------------- diff --git a/python/tests/test_highlevel.py b/python/tests/test_highlevel.py index 4a9337dcb4..f390420e40 100644 --- a/python/tests/test_highlevel.py +++ b/python/tests/test_highlevel.py @@ -4009,6 +4009,7 @@ def test_apis(self): assert t1.get_parent_dict() == t1.parent_dict assert t1.get_total_branch_length() == t1.total_branch_length assert t1.span == t1.interval.right - t1.interval.left + assert t1.mid == t1.interval.left + (t1.interval.right - t1.interval.left) / 2 # node properties root = t1.get_root() for node in t1.nodes(): @@ -4131,6 +4132,9 @@ def test_interval(self): assert tree.interval.span == pytest.approx( breakpoints[i + 1] - breakpoints[i] ) + assert tree.interval.mid == pytest.approx( + breakpoints[i] + (breakpoints[i + 1] - breakpoints[i]) / 2 + ) def verify_tree_arrays(self, tree): ts = tree.tree_sequence diff --git a/python/tskit/trees.py b/python/tskit/trees.py index 52d0bd380f..08ea2dbe0a 100644 --- a/python/tskit/trees.py +++ b/python/tskit/trees.py @@ -89,6 +89,13 @@ def span(self) -> float | int: """ return self.right - self.left + @property + def mid(self) -> float | int: + """ + The middle point of this interval, simply ``left+(right-left)/2``. + """ + return self.left + (self.right - self.left) / 2 + class EdgeDiff(NamedTuple): interval: Interval @@ -1686,6 +1693,19 @@ def span(self): """ return self.interval.span + @property + def mid(self): + """ + Returns the midpoint of the genomic interval that this tree represents + the history of. This is defined as :math:`(l + (r - l) / 2)`, where + :math:`(l, r)` is the genomic interval returned by + :attr:`~Tree.interval`. + + :return: The genomic distance covered by this tree. + :rtype: float + """ + return self.interval.mid + def get_sample_size(self): # Deprecated alias for self.sample_size return self.sample_size