mirror of
https://github.com/biopython/biopython.git
synced 2025-10-20 13:43:47 +08:00
Preserve root branch length in Phylo.TreeMixin.prune
This commit is contained in:
@ -660,8 +660,8 @@ class TreeMixin:
|
||||
def prune(self, target=None, **kwargs):
|
||||
"""Prunes a terminal clade from the tree.
|
||||
|
||||
If taxon is from a bifurcation, the connecting node will be collapsed
|
||||
and its branch length added to remaining terminal node. This might be no
|
||||
If the taxon is from a bifurcation, the connecting node will be collapsed
|
||||
and its branch length added to remaining terminal node. This might no
|
||||
longer be a meaningful value.
|
||||
|
||||
:returns: parent clade of the pruned target
|
||||
@ -679,17 +679,14 @@ class TreeMixin:
|
||||
parent.clades.remove(path[-1])
|
||||
if len(parent) == 1:
|
||||
# We deleted a branch from a bifurcation
|
||||
if parent == self.root:
|
||||
child = parent.clades[0]
|
||||
if child.branch_length is not None:
|
||||
child.branch_length += parent.branch_length or 0.0
|
||||
if len(path) == 1:
|
||||
# If we're at the root, move the root upwards
|
||||
# NB: This loses the length of the original branch
|
||||
newroot = parent.clades[0]
|
||||
newroot.branch_length = None
|
||||
parent = self.root = newroot
|
||||
parent = self.root = child
|
||||
else:
|
||||
# If we're not at the root, collapse this parent
|
||||
child = parent.clades[0]
|
||||
if child.branch_length is not None:
|
||||
child.branch_length += parent.branch_length or 0.0
|
||||
if len(path) < 3:
|
||||
grandparent = self.root
|
||||
else:
|
||||
|
@ -352,7 +352,7 @@ function:
|
||||
>>> Phylo.write(tree1, "tree1.nwk", "newick")
|
||||
1
|
||||
>>> Phylo.write(trees, "other_trees.xml", "phyloxml") # write the remaining trees
|
||||
12
|
||||
13
|
||||
|
||||
Convert files between any of the supported formats with the ``convert``
|
||||
function:
|
||||
@ -364,7 +364,7 @@ function:
|
||||
>>> Phylo.convert("tree1.nwk", "newick", "tree1.xml", "nexml")
|
||||
1
|
||||
>>> Phylo.convert("other_trees.xml", "phyloxml", "other_trees.nex", "nexus")
|
||||
12
|
||||
13
|
||||
|
||||
To use strings as input or output instead of actual files, use
|
||||
``StringIO`` as you would with SeqIO and AlignIO:
|
||||
@ -681,7 +681,7 @@ tree intact, make a complete copy of the tree first, using Python’s
|
||||
sort clades deepest-to-shallowest.
|
||||
|
||||
``prune``
|
||||
Prunes a terminal clade from the tree. If taxon is from a
|
||||
Prunes a terminal clade from the tree. If the taxon is from a
|
||||
bifurcation, the connecting node will be collapsed and its branch
|
||||
length added to remaining terminal node. This might no longer be a
|
||||
meaningful value.
|
||||
|
@ -408,6 +408,26 @@
|
||||
</clade>
|
||||
</clade>
|
||||
</phylogeny>
|
||||
<phylogeny rooted="true">
|
||||
<clade>
|
||||
<branch_length>0.04</branch_length>
|
||||
<clade>
|
||||
<branch_length>0.06</branch_length>
|
||||
<clade>
|
||||
<name>A</name>
|
||||
<branch_length>0.102</branch_length>
|
||||
</clade>
|
||||
<clade>
|
||||
<name>B</name>
|
||||
<branch_length>0.23</branch_length>
|
||||
</clade>
|
||||
</clade>
|
||||
<clade>
|
||||
<name>C</name>
|
||||
<branch_length>0.4</branch_length>
|
||||
</clade>
|
||||
</clade>
|
||||
</phylogeny>
|
||||
<align:alignment xmlns:align="http://example.org/align">
|
||||
<seq name="A">acgtcgcggcccgtggaagtcctctcct</seq>
|
||||
<seq name="B">aggtcgcggcctgtggaagtcctctcct</seq>
|
||||
|
@ -150,7 +150,7 @@ class IOTests(unittest.TestCase):
|
||||
trees = Phylo.parse("PhyloXML/phyloxml_examples.xml", "phyloxml")
|
||||
with tempfile.NamedTemporaryFile(mode="w") as out_handle:
|
||||
count = Phylo.write(trees, out_handle, "phyloxml")
|
||||
self.assertEqual(13, count)
|
||||
self.assertEqual(14, count)
|
||||
|
||||
def test_convert_phyloxml_filename(self):
|
||||
"""Write phyloxml to a given filename."""
|
||||
@ -162,7 +162,7 @@ class IOTests(unittest.TestCase):
|
||||
count = Phylo.write(trees, tmp_filename, "phyloxml")
|
||||
finally:
|
||||
os.remove(tmp_filename)
|
||||
self.assertEqual(13, count)
|
||||
self.assertEqual(14, count)
|
||||
|
||||
def test_int_labels(self):
|
||||
"""Read newick formatted tree with numeric labels."""
|
||||
@ -471,6 +471,7 @@ class MixinTests(unittest.TestCase):
|
||||
tree = self.phylogenies[1]
|
||||
parent = tree.prune(name="C")
|
||||
self.assertEqual(parent, tree.root)
|
||||
self.assertEqual(tree.root.branch_length, 0.06)
|
||||
self.assertEqual(len(parent.clades), 2)
|
||||
for clade, name, blen in zip(parent, "AB", (0.102, 0.23)):
|
||||
self.assertTrue(clade.is_terminal())
|
||||
@ -478,6 +479,10 @@ class MixinTests(unittest.TestCase):
|
||||
self.assertAlmostEqual(clade.branch_length, blen)
|
||||
self.assertEqual(len(tree.get_terminals()), 2)
|
||||
self.assertEqual(len(tree.get_nonterminals()), 1)
|
||||
# Taxon just below root
|
||||
tree = self.phylogenies[13]
|
||||
parent = tree.prune(name="C")
|
||||
self.assertEqual(tree.root.branch_length, 0.1)
|
||||
|
||||
def test_split(self):
|
||||
"""TreeMixin: split() method."""
|
||||
|
@ -96,13 +96,13 @@ class ParseTests(unittest.TestCase):
|
||||
test_read_apaf = _test_read_factory(EX_APAF, (1, 0))
|
||||
test_read_bcl2 = _test_read_factory(EX_BCL2, (1, 0))
|
||||
test_read_made = _test_read_factory(EX_MADE, (6, 0))
|
||||
test_read_phylo = _test_read_factory(EX_PHYLO, (13, 1))
|
||||
test_read_phylo = _test_read_factory(EX_PHYLO, (14, 1))
|
||||
test_read_dollo = _test_read_factory(EX_DOLLO, (1, 0))
|
||||
|
||||
test_parse_apaf = _test_parse_factory(EX_APAF, 1)
|
||||
test_parse_bcl2 = _test_parse_factory(EX_BCL2, 1)
|
||||
test_parse_made = _test_parse_factory(EX_MADE, 6)
|
||||
test_parse_phylo = _test_parse_factory(EX_PHYLO, 13)
|
||||
test_parse_phylo = _test_parse_factory(EX_PHYLO, 14)
|
||||
test_parse_dollo = _test_parse_factory(EX_DOLLO, 1)
|
||||
|
||||
# lvl-2 clades, sub-clade counts, lvl-3 clades
|
||||
|
Reference in New Issue
Block a user