Skip to content

Commit a405474

Browse files
committed
Remove error states related to samples and individuals with no nodes
1 parent 36e4d43 commit a405474

2 files changed

Lines changed: 18 additions & 33 deletions

File tree

python/tests/test_highlevel.py

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5505,7 +5505,7 @@ def test_basic_individual_nodes(self, tmp_path):
55055505
tables.nodes.add_row(flags=tskit.NODE_IS_SAMPLE, time=0, individual=1)
55065506
ts = tables.tree_sequence()
55075507

5508-
result = ts.individual_nodes()
5508+
result = ts.individual_nodes
55095509
assert result.shape == (2, 2)
55105510
assert np.array_equal(result, [[0, 1], [2, 3]])
55115511

@@ -5529,7 +5529,7 @@ def test_variable_ploidy(self, tmp_path):
55295529

55305530
ts = tables.tree_sequence()
55315531

5532-
result = ts.individual_nodes()
5532+
result = ts.individual_nodes
55335533

55345534
assert result.shape == (3, 3)
55355535

@@ -5544,17 +5544,18 @@ def test_no_individuals(self):
55445544
ts = tables.tree_sequence()
55455545

55465546
with pytest.raises(ValueError, match="Tree sequence has no individuals"):
5547-
_ = ts.individual_nodes()
5547+
_ = ts.individual_nodes
55485548

5549-
def test_no_samples_with_individuals(self):
5549+
def test_no_nodes_with_individuals(self):
55505550
tables = tskit.TableCollection(sequence_length=100)
55515551
tables.individuals.add_row(flags=0, location=(0, 0), metadata=b"")
55525552
# Node without individual reference
55535553
tables.nodes.add_row(flags=tskit.NODE_IS_SAMPLE, time=0)
55545554
ts = tables.tree_sequence()
55555555

5556-
with pytest.raises(ValueError, match="No nodes refer to individuals"):
5557-
_ = ts.individual_nodes()
5556+
result = ts.individual_nodes
5557+
expected = np.array([[]])
5558+
assert np.array_equal(result, expected)
55585559

55595560
def test_individual_with_no_nodes(self):
55605561
tables = tskit.TableCollection(sequence_length=100)
@@ -5564,18 +5565,17 @@ def test_individual_with_no_nodes(self):
55645565
tables.nodes.add_row(flags=tskit.NODE_IS_SAMPLE, time=0, individual=0)
55655566
ts = tables.tree_sequence()
55665567

5567-
with pytest.raises(
5568-
ValueError, match="Individual 1 not associated with any nodes"
5569-
):
5570-
_ = ts.individual_nodes()
5568+
result = ts.individual_nodes
5569+
expected = np.array([[0], [-1]])
5570+
assert np.array_equal(result, expected)
55715571

55725572
def test_mixed_sample_status(self):
55735573
tables = tskit.TableCollection(sequence_length=100)
55745574
tables.individuals.add_row(flags=0, location=(0, 0), metadata=b"")
55755575
tables.nodes.add_row(flags=tskit.NODE_IS_SAMPLE, time=0, individual=0)
55765576
tables.nodes.add_row(flags=0, time=0, individual=0)
55775577
ts = tables.tree_sequence()
5578-
with pytest.raises(
5579-
ValueError, match="has nodes that are sample and non-samples"
5580-
):
5581-
_ = ts.individual_nodes()
5578+
5579+
result = ts.individual_nodes
5580+
expected = np.array([[0, 1]])
5581+
assert np.array_equal(result, expected)

python/tskit/trees.py

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10476,12 +10476,11 @@ def ld_matrix(
1047610476
mode=mode,
1047710477
)
1047810478

10479+
@property
1047910480
def individual_nodes(self):
1048010481
"""
1048110482
Return an array of node IDs for each individual in the tree sequence.
10482-
Errors if the tree sequence has no individuals, if individuals have
10483-
nodes that are both samples and non-samples, or if an individual
10484-
has no samples.
10483+
Errors if the tree sequence has no individuals.
1048510484
1048610485
:return: Array of shape (num_individuals, max_ploidy) containing node IDs.
1048710486
Values of -1 indicate unused slots for individuals with ploidy
@@ -10491,25 +10490,11 @@ def individual_nodes(self):
1049110490
if self.num_individuals == 0:
1049210491
raise ValueError("Tree sequence has no individuals")
1049310492

10494-
max_ploidy = 0
10495-
for i in range(self.num_individuals):
10496-
ind = self.individual(i)
10497-
max_ploidy = max(max_ploidy, len(ind.nodes))
10498-
if max_ploidy == 0:
10499-
raise ValueError("No nodes refer to individuals")
10500-
10493+
max_ploidy = max(len(i.nodes) for i in self.individuals())
1050110494
# Initialize output array with -1 (indicating no node)
1050210495
result = np.full((self.num_individuals, max_ploidy), -1, dtype=np.int32)
1050310496

10504-
for i in range(self.num_individuals):
10505-
ind = self.individual(i)
10506-
if len(ind.nodes) == 0:
10507-
raise ValueError(f"Individual {i} not associated with any nodes")
10508-
is_sample = {self.node(u).is_sample() for u in ind.nodes}
10509-
if len(is_sample) != 1:
10510-
raise ValueError(
10511-
f"Individual {ind.id} has nodes that are sample and non-samples"
10512-
)
10497+
for i, ind in enumerate(self.individuals()):
1051310498
for j, node_id in enumerate(ind.nodes):
1051410499
result[i, j] = node_id
1051510500

0 commit comments

Comments
 (0)