Dendropy: добавьте внутренний узел посередине между двумя узлами
Я новичок в DendroPy. То, что я хочу сделать, кажется простым, но я не могу понять, как это сделать правильно, и я ничего не нашел в Интернете.
Я хочу добавить узел посередине между двумя узлами в существующем корневом дереве dendropy.
from dendropy import Tree, Taxon, Node
t1 = Tree.get_from_string(
"(((sp1: 0.35, sp2: 0.15):0.75, sp3:1): 0.5, (sp4: 0.5, sp5: 0.05)MRCA_sp4&sp5: 1)root;",
"newick", rooting='force-rooted'
)
t1.print_plot()
mrca = t1.mrca(taxon_labels=["sp4", "sp5"])
print(mrca.description())
MRCA sp4 и sp5 определяется правильно. Теперь я пытаюсь добавить узел на полпути между MRCA и корнем, используя приведенный ниже код:
def add_node_midway_between_2_nodes(lowernode, taxon_label=None, node_label=None):
newtaxon = Taxon(label=taxon_label)
newnode = Node(taxon=newtaxon, label=node_label)
newnode.parent_node = lowernode.parent_node
newnode.edge_length = lowernode.edge_length/2
lowernode.parent_node = newnode
lowernode.edge_length = newnode.edge_length
return newnode
node = add_node_midway_between_2_nodes(mrca, node_label="midway between root and MRCA sp4&sp5")
t1.print_plot()
str_t1 = t1.as_string(schema='newick')
print(str_t1)
Дерево с узлом между корнем и MRCA sp4&sp5
[&R] (((sp1:0.35,sp2:0.15):0.75,sp3:1.0):0.5,((sp4:0.5,sp5:0.05)MRCA_sp4&sp5:0.5)midway_between_root_and_MRCA_sp4&sp5:0.5)root;
Глядя на сюжет и на строку, кажется, что это сработало. Но затем, когда я снова пытаюсь вычислить MRCA sp4 и sp5, он больше не находит «MRCA sp4 и sp5», а корневой узел.
mrca = t1.mrca(taxon_labels=["sp4", "sp5"])
print(mrca.description())
Вывод = Описание корневого узла
Проходя через parent_node из sp5, я все еще нахожу «MRCA sp4 и sp5».
От отчаяния я попытался переделать дерево с помощью строки str_t1, но это тоже не работает и даже дает другой результат (столь же неверный): узел "посередине между корнем и MRCA sp4&sp5"
t1 = Tree.get_from_string(
str_t1,
"newick", rooting='force-rooted'
)
mrca = t1.mrca(taxon_labels=["sp4", "sp5"])
print(mrca.description())
Выходные данные = описание узла «на полпути между корнем и MRCA sp4 и sp5»
Так что же представляет собой чистый способ добавить узел посередине между двумя узлами, который впоследствии не создает странных событий?
Большое спасибо
1 ответ
Ваш код в основном работает, но вы должныupdate_taxon_namespace
и
update_bipartitions
корректно применять любые изменения топологии дерева, как это рекомендовано в документации . Итак, в вашем случае это будет выглядеть так:
def add_node_midway_between_2_nodes(lowernode, taxon_label=None, node_label=None):
newtaxon = Taxon(label=taxon_label)
newnode = Node(taxon=newtaxon, label=node_label)
newnode.parent_node = lowernode.parent_node
newnode.edge_length = lowernode.edge_length/2
lowernode.parent_node = newnode
lowernode.edge_length = newnode.edge_length
return newnode
node = add_node_midway_between_2_nodes(
mrca, node_label="midway between root and MRCA sp4&sp5"
)
t1.update_taxon_namespace()
t1.update_bipartitions(
suppress_unifurcations=False, suppress_storage=True
) # suppress_storage is optional, I just do not want to create a bipartitions list
t1.print_plot()
str_t1 = t1.as_string(schema='newick')
print(str_t1)
Гульника!
Обновление пространства имен таксонов должно производиться до обновления разделов, так как последний должен использовать правильныйTaxonNamespace
. В противном случае вы все равно получите странное поведение.
Однако лучше использовать встроенныйNode
методы тонкой реконструкции деревьев. Например, я бы переписал функцию так:
def insert_new_node_posterior(
node: Node,
*,
taxon_label: Optional[str] = None,
node_label: Optional[str] = None,
edge_length: Real,
# If it was product or at least reusable in the future code,
# I would add more arguments for proportion specification,
# using height, distance from root &c.
) -> Node:
parent = node.parent_node
if not parent:
raise Exception("You cannot insert a node in posterior to the root.")
new_taxon = Taxon(label=taxon_label)
i = parent.child_nodes().index(node)
parent.remove_child(node)
intermediate_node = parent.insert_new_child(
index=i, taxon=new_taxon, label=node_label, edge_length=edge_length
)
node.edge_length -= edge_length
intermediate_node.add_child(node)
return intermediate_node
node = insert_new_node_posterior(
mrca,
node_label="midway between root and MRCA sp4&sp5",
edge_length=mrca.edge_length / 2
)
t1.update_taxon_namespace()
t1.update_bipartitions(
suppress_unifurcations=False, suppress_storage=True
)
t1.print_plot()
str_t1 = t1.as_string(schema='newick')
print(str_t1)
Тем не менее,Tree.mrca
все еще показывает неправильный узел:
Node object at 0x1be8b959460<Node object at 0x1be8b959460: 'midway between root and MRCA sp4&sp5' (<Taxon 0x1be8cdceeb0 'None'>)>
[Edge]
Edge object at 0x1be8b959400 (1917897249792, Length=0.5)
[Taxon]
Taxon object at 0x1be8cdceeb0: <Unnamed Taxon>
[Parent]
Node object at 0x1be8c3b2b80<Node object at 0x1be8c3b2b80: 'root' (None)>
[Children]
[0] Node object at 0x1be8be4d6a0<Node object at 0x1be8be4d6a0: 'MRCA sp4&sp5' (None)>
Хотя в данном случае это не баг, а просто особенность метода. В связи с этим в исходном коде :
if cms:
# for at least one taxon cm has 1 and bipartition has 1
if cms == leafset_bitmask:
# curr_node has all of the 1's that bipartition has
if cm == leafset_bitmask:
return curr_node # Vovin's comment: Since there is a unifurcation,
# it returns the current node
# instead of the next iteration
last_match = curr_node
nd_source = iter(curr_node.child_nodes())
else:
# we have reached a child that has some, but not all of the
# required taxa as descendants, so we return the last_match
return last_match
Например, если мы добавим дочерний элемент к новому узлу, он будет работать хорошо:
node = insert_new_node_posterior(
mrca,
node_label="midway between root and MRCA sp4&sp5",
edge_length=mrca.edge_length / 2
)
node.new_child(label="sp6", edge_length=1, taxon=Taxon(label="sp6"))
t1.update_taxon_namespace()
t1.update_bipartitions(
suppress_unifurcations=False, suppress_storage=True
)
mrca = t1.mrca(taxon_labels=["sp4", "sp5"])
print(mrca.description())
Node object at 0x1be8c1e22b0<Node object at 0x1be8c1e22b0: 'MRCA sp4&sp5' (None)>
[Edge]
Edge object at 0x1be8c1e2340 (1917906199360, Length=0.5)
[Taxon]
None
[Parent]
Node object at 0x1be8ba8da30<Node object at 0x1be8ba8da30: 'midway between root and MRCA sp4&sp5' (<Taxon 0x1be8ba8d370 'None'>)>
[Children]
[0] Node object at 0x1be8c1e2910<Node object at 0x1be8c1e2910: 'None' (<Taxon 0x1be8c1e2640 'sp4'>)>
[1] Node object at 0x1be8c1e28e0<Node object at 0x1be8c1e28e0: 'None' (<Taxon 0x1be8c1e2e50 'sp5'>)>