Skip to content

Commit c8e161b

Browse files
committed
Add highlevel API
1 parent 1aa01af commit c8e161b

2 files changed

Lines changed: 90 additions & 0 deletions

File tree

python/tests/test_highlevel.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5321,6 +5321,53 @@ def test_mixed_sample_status(self):
53215321
assert_array_equal(result, expected)
53225322

53235323

5324+
class TestRaggedArrays:
5325+
@pytest.mark.parametrize("num_rows", [0, 1, 100])
5326+
@pytest.mark.parametrize("column", ["ancestral_state", "derived_state"])
5327+
def test_site_ancestral_state(self, num_rows, column):
5328+
tables = tskit.TableCollection(sequence_length=100)
5329+
rng = random.Random(42)
5330+
for i in range(num_rows):
5331+
state_length = rng.randint(0, 10)
5332+
state = "".join(
5333+
chr(rng.randint(0x1F300, 0x1F6FF)) for _ in range(state_length)
5334+
)
5335+
if column == "ancestral_state":
5336+
tables.sites.add_row(position=i, ancestral_state=state)
5337+
elif column == "derived_state":
5338+
tables.nodes.add_row()
5339+
tables.sites.add_row(position=i, ancestral_state="A")
5340+
tables.mutations.add_row(site=i, node=0, derived_state=state)
5341+
ts = tables.tree_sequence()
5342+
a = getattr(
5343+
ts,
5344+
(
5345+
"sites_ancestral_state"
5346+
if column == "ancestral_state"
5347+
else "mutations_derived_state"
5348+
),
5349+
)
5350+
assert isinstance(a, np.ndarray)
5351+
assert a.shape == (num_rows,)
5352+
assert a.dtype == np.dtype("T")
5353+
assert a.size == num_rows
5354+
5355+
# Check that the value is cached
5356+
assert a is getattr(
5357+
ts,
5358+
(
5359+
"sites_ancestral_state"
5360+
if column == "ancestral_state"
5361+
else "mutations_derived_state"
5362+
),
5363+
)
5364+
5365+
for state, row in itertools.zip_longest(
5366+
a, ts.sites() if column == "ancestral_state" else ts.mutations()
5367+
):
5368+
assert state == getattr(row, column)
5369+
5370+
53245371
class TestSampleNodesByPloidy:
53255372
@pytest.mark.parametrize(
53265373
"n_samples,ploidy,expected",

python/tskit/trees.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4138,6 +4138,8 @@ def __init__(self, ll_tree_sequence):
41384138
self._individuals_location = None
41394139
self._individuals_nodes = None
41404140
self._mutations_edge = None
4141+
self._sites_ancestral_state = None
4142+
self._mutations_derived_state = None
41414143
# NOTE: when we've implemented read-only access via the underlying
41424144
# tables we can replace these arrays with reference to the read-only
41434145
# tables here (and remove the low-level boilerplate).
@@ -5952,6 +5954,26 @@ def sites_position(self):
59525954
"""
59535955
return self._sites_position
59545956

5957+
@property
5958+
def sites_ancestral_state(self):
5959+
"""
5960+
The ``ancestral_state`` column in the
5961+
:ref:`sec_site_table_definition` as a numpy array (dtype=StringDtype).
5962+
"""
5963+
if self._sites_ancestral_state is None:
5964+
try:
5965+
self._sites_ancestral_state = (
5966+
self._ll_tree_sequence.sites_ancestral_state
5967+
)
5968+
except AttributeError:
5969+
if not _tskit.HAS_NUMPY_2:
5970+
raise RuntimeError(
5971+
"The sites_ancestral_state property requires numpy 2.0 or later."
5972+
)
5973+
else:
5974+
raise
5975+
return self._sites_ancestral_state
5976+
59555977
@property
59565978
def sites_metadata(self):
59575979
"""
@@ -6009,6 +6031,27 @@ def mutations_time(self):
60096031
"""
60106032
return self._mutations_time
60116033

6034+
@property
6035+
def mutations_derived_state(self):
6036+
"""
6037+
Access to the ``derived_state`` column in the
6038+
:ref:`sec_mutation_table_definition` as a numpy array (dtype=StringDtype).
6039+
"""
6040+
if self._mutations_derived_state is None:
6041+
try:
6042+
self._mutations_derived_state = (
6043+
self._ll_tree_sequence.mutations_derived_state
6044+
)
6045+
except AttributeError:
6046+
if not _tskit.HAS_NUMPY_2:
6047+
raise RuntimeError(
6048+
"The mutations_derived_state property requires "
6049+
"numpy 2.0 or later."
6050+
)
6051+
else:
6052+
raise
6053+
return self._mutations_derived_state
6054+
60126055
@property
60136056
def mutations_metadata(self):
60146057
"""

0 commit comments

Comments
 (0)