Fix calculating height of clades when building UPGMA tree version 2 (#3951)

* Fixed a bug in calculating the height of clades when building a UPGMA tree

* added my name to contrib.rst alphabetically

* minor corrections

* formatting changes

* Add tests

---------

Co-authored-by: She Zhang <shz66@pitt.edu>
Co-authored-by: Fabian Egli <fabianegli@users.noreply.github.com>
Co-authored-by: Eric Talevich <etal@users.noreply.github.com>
This commit is contained in:
Fabian Egli
2024-10-17 06:07:35 +02:00
committed by GitHub
parent eedf82d415
commit 82b3e67096
3 changed files with 14 additions and 13 deletions

View File

@ -745,15 +745,8 @@ class DistanceTreeConstructor(TreeConstructor):
inner_clade.clades.append(clade1) inner_clade.clades.append(clade1)
inner_clade.clades.append(clade2) inner_clade.clades.append(clade2)
# assign branch length # assign branch length
if clade1.is_terminal(): clade1.branch_length = min_dist * 1.0 / 2 - self._height_of(clade1)
clade1.branch_length = min_dist / 2 clade2.branch_length = min_dist * 1.0 / 2 - self._height_of(clade2)
else:
clade1.branch_length = min_dist / 2 - self._height_of(clade1)
if clade2.is_terminal():
clade2.branch_length = min_dist / 2
else:
clade2.branch_length = min_dist / 2 - self._height_of(clade2)
# update node list # update node list
clades[min_j] = inner_clade clades[min_j] = inner_clade
@ -876,11 +869,11 @@ class DistanceTreeConstructor(TreeConstructor):
def _height_of(self, clade): def _height_of(self, clade):
"""Calculate clade height -- the longest path to any terminal (PRIVATE).""" """Calculate clade height -- the longest path to any terminal (PRIVATE)."""
height = 0
if clade.is_terminal(): if clade.is_terminal():
height = clade.branch_length height = 0
else: else:
height = height + max(self._height_of(c) for c in clade.clades) height = max(self._height_of(c) + c.branch_length for c in clade.clades)
return height return height

View File

@ -300,6 +300,7 @@ please open an issue on GitHub or mention it on the mailing list.
- Sergei Lebedev <https://github.com/superbobry> - Sergei Lebedev <https://github.com/superbobry>
- Sergio Valqui <https://github.com/svalqui> - Sergio Valqui <https://github.com/svalqui>
- Seth Sims <seth.sims at gmail> - Seth Sims <seth.sims at gmail>
- She Zhang <https://github.com/shz66>
- Shoichiro Kawauchi <https://github.com/lacrosse91> - Shoichiro Kawauchi <https://github.com/lacrosse91>
- Shuichiro MAKIGAKI <https://github.com/shuichiro-makigaki> - Shuichiro MAKIGAKI <https://github.com/shuichiro-makigaki>
- Shyam Saladi <https://github.com/smsaladi> - Shyam Saladi <https://github.com/smsaladi>

View File

@ -9,6 +9,7 @@ import os
import tempfile import tempfile
import unittest import unittest
from io import StringIO from io import StringIO
from itertools import combinations
from Bio import Align from Bio import Align
from Bio import AlignIO from Bio import AlignIO
@ -232,7 +233,13 @@ class DistanceTreeConstructorTest(unittest.TestCase):
# Phylo.write(tree, tree_file, 'newick') # Phylo.write(tree, tree_file, 'newick')
ref_tree = Phylo.read("./TreeConstruction/upgma.tre", "newick") ref_tree = Phylo.read("./TreeConstruction/upgma.tre", "newick")
self.assertTrue(Consensus._equal_topology(tree, ref_tree)) self.assertTrue(Consensus._equal_topology(tree, ref_tree))
# ref_tree.close() # check for equal distance of all terminal nodes from the root
ref_tree.root_at_midpoint()
for len1, len2 in combinations(
[depth for node, depth in ref_tree.depths().items() if node.is_terminal()],
2,
):
self.assertAlmostEqual(len1, len2)
def test_nj_msa(self): def test_nj_msa(self):
tree = self.constructor.nj(self.dm_msa) tree = self.constructor.nj(self.dm_msa)