phylogenie 2.1.21__py3-none-any.whl → 2.1.22__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of phylogenie might be problematic. Click here for more details.
- phylogenie/draw.py +4 -1
- phylogenie/io.py +48 -41
- phylogenie/tree.py +7 -4
- {phylogenie-2.1.21.dist-info → phylogenie-2.1.22.dist-info}/METADATA +1 -1
- {phylogenie-2.1.21.dist-info → phylogenie-2.1.22.dist-info}/RECORD +8 -8
- {phylogenie-2.1.21.dist-info → phylogenie-2.1.22.dist-info}/LICENSE.txt +0 -0
- {phylogenie-2.1.21.dist-info → phylogenie-2.1.22.dist-info}/WHEEL +0 -0
- {phylogenie-2.1.21.dist-info → phylogenie-2.1.22.dist-info}/entry_points.txt +0 -0
phylogenie/draw.py
CHANGED
|
@@ -28,7 +28,10 @@ def _draw_colored_tree(tree: Tree, ax: Axes, colors: Color | dict[Tree, Color])
|
|
|
28
28
|
if any(node.branch_length is None for node in tree)
|
|
29
29
|
else get_node_depths(tree)
|
|
30
30
|
)
|
|
31
|
-
ys = {node: i for i, node in enumerate(tree.
|
|
31
|
+
ys: dict[Tree, float] = {node: i for i, node in enumerate(tree.get_leaves())}
|
|
32
|
+
for node in tree.postorder_traversal():
|
|
33
|
+
if node.is_internal():
|
|
34
|
+
ys[node] = sum(ys[child] for child in node.children) / len(node.children)
|
|
32
35
|
|
|
33
36
|
for node in tree:
|
|
34
37
|
x1, y1 = xs[node], ys[node]
|
phylogenie/io.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import re
|
|
1
2
|
from typing import Callable
|
|
2
3
|
|
|
3
4
|
from phylogenie.msa import MSA, Sequence
|
|
@@ -12,54 +13,56 @@ def _parse_newick(newick: str) -> Tree:
|
|
|
12
13
|
i = 0
|
|
13
14
|
while i < len(newick):
|
|
14
15
|
|
|
15
|
-
def
|
|
16
|
+
def _read_chars(stoppers: list[str]) -> str:
|
|
16
17
|
nonlocal i
|
|
17
18
|
chars = ""
|
|
18
|
-
while newick[i] not in stoppers:
|
|
19
|
+
while i < len(newick) and newick[i] not in stoppers:
|
|
19
20
|
chars += newick[i]
|
|
20
21
|
i += 1
|
|
22
|
+
if i == len(newick):
|
|
23
|
+
raise ValueError(f"Expected one of {stoppers}, got end of string")
|
|
21
24
|
return chars
|
|
22
25
|
|
|
23
26
|
if newick[i] == "(":
|
|
24
27
|
stack.append(current_nodes)
|
|
25
28
|
current_nodes = []
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
i += 1
|
|
30
|
+
continue
|
|
31
|
+
|
|
32
|
+
current_node = Tree(_read_chars(["[", ":", ",", ")", ";"]))
|
|
33
|
+
|
|
34
|
+
if newick[i] == "[":
|
|
35
|
+
i += 1
|
|
36
|
+
if newick[i] != "&":
|
|
37
|
+
raise ValueError("Expected '[&' at the start of node features")
|
|
38
|
+
i += 1
|
|
39
|
+
features = re.split(r",(?=[^,]+=)", _read_chars(["]"]))
|
|
40
|
+
i += 1
|
|
41
|
+
for feature in features:
|
|
42
|
+
key, value = feature.split("=")
|
|
43
|
+
try:
|
|
44
|
+
current_node.set(key, eval(value))
|
|
45
|
+
except Exception:
|
|
46
|
+
current_node.set(key, value)
|
|
32
47
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
current_children = []
|
|
37
|
-
current_nodes.append(current_node)
|
|
48
|
+
if newick[i] == ":":
|
|
49
|
+
i += 1
|
|
50
|
+
current_node.branch_length = float(_read_chars([",", ")", ";"]))
|
|
38
51
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
except Exception as e:
|
|
50
|
-
raise ValueError(
|
|
51
|
-
f"Error setting node feature `{key}` to `{value}`: {e}"
|
|
52
|
-
)
|
|
53
|
-
|
|
54
|
-
if newick[i] == ")":
|
|
55
|
-
current_children = current_nodes
|
|
56
|
-
current_nodes = stack.pop()
|
|
57
|
-
elif newick[i] == ";":
|
|
58
|
-
return current_node
|
|
52
|
+
for node in current_children:
|
|
53
|
+
current_node.add_child(node)
|
|
54
|
+
current_children = []
|
|
55
|
+
current_nodes.append(current_node)
|
|
56
|
+
|
|
57
|
+
if newick[i] == ")":
|
|
58
|
+
current_children = current_nodes
|
|
59
|
+
current_nodes = stack.pop()
|
|
60
|
+
elif newick[i] == ";":
|
|
61
|
+
return current_node
|
|
59
62
|
|
|
60
63
|
i += 1
|
|
61
64
|
|
|
62
|
-
raise ValueError("Newick string
|
|
65
|
+
raise ValueError("Newick string should end with ';'")
|
|
63
66
|
|
|
64
67
|
|
|
65
68
|
def load_newick(filepath: str) -> Tree | list[Tree]:
|
|
@@ -71,19 +74,23 @@ def load_newick(filepath: str) -> Tree | list[Tree]:
|
|
|
71
74
|
def _to_newick(tree: Tree) -> str:
|
|
72
75
|
children_newick = ",".join([_to_newick(child) for child in tree.children])
|
|
73
76
|
newick = tree.name
|
|
74
|
-
if children_newick:
|
|
75
|
-
newick = f"({children_newick}){newick}"
|
|
76
|
-
if tree.branch_length is not None:
|
|
77
|
-
newick += f":{tree.branch_length}"
|
|
78
77
|
if tree.features:
|
|
79
78
|
reprs = {k: repr(v).replace("'", '"') for k, v in tree.features.items()}
|
|
80
79
|
for k, r in reprs.items():
|
|
81
|
-
if "
|
|
80
|
+
if "," in k or "=" in k or "]" in k:
|
|
81
|
+
raise ValueError(
|
|
82
|
+
f"Invalid feature key `{k}`: keys must not contain ',', '=', or ']'"
|
|
83
|
+
)
|
|
84
|
+
if "=" in r or "]" in r:
|
|
82
85
|
raise ValueError(
|
|
83
|
-
f"
|
|
86
|
+
f"Invalid value `{r}` for feature `{k}`: values must not contain '=' or ']'"
|
|
84
87
|
)
|
|
85
88
|
features = [f"{k}={repr}" for k, repr in reprs.items()]
|
|
86
|
-
newick += f"[
|
|
89
|
+
newick += f"[&{','.join(features)}]"
|
|
90
|
+
if children_newick:
|
|
91
|
+
newick = f"({children_newick}){newick}"
|
|
92
|
+
if tree.branch_length is not None:
|
|
93
|
+
newick += f":{tree.branch_length}"
|
|
87
94
|
return newick
|
|
88
95
|
|
|
89
96
|
|
phylogenie/tree.py
CHANGED
|
@@ -136,16 +136,19 @@ class Tree:
|
|
|
136
136
|
def get_leaves(self) -> tuple["Tree", ...]:
|
|
137
137
|
return tuple(node for node in self if node.is_leaf())
|
|
138
138
|
|
|
139
|
+
def is_internal(self) -> bool:
|
|
140
|
+
return not self.is_leaf()
|
|
141
|
+
|
|
139
142
|
def get_internal_nodes(self) -> tuple["Tree", ...]:
|
|
140
|
-
return tuple(node for node in self if
|
|
143
|
+
return tuple(node for node in self if node.is_internal())
|
|
141
144
|
|
|
142
145
|
def is_binary(self) -> bool:
|
|
143
146
|
return all(len(node.children) in (0, 2) for node in self)
|
|
144
147
|
|
|
145
|
-
def ladderize(self,
|
|
146
|
-
self._children.sort(key=
|
|
148
|
+
def ladderize(self, key: Callable[["Tree"], Any]) -> None:
|
|
149
|
+
self._children.sort(key=key)
|
|
147
150
|
for child in self.children:
|
|
148
|
-
child.ladderize(
|
|
151
|
+
child.ladderize(key)
|
|
149
152
|
|
|
150
153
|
def copy(self):
|
|
151
154
|
new_tree = Tree(self.name, self.branch_length)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
phylogenie/__init__.py,sha256=8ulA-U7-WnBLNsqRYqPOPrJG8X4ZzyEU02oaDbR_Hxs,2849
|
|
2
|
-
phylogenie/draw.py,sha256=
|
|
2
|
+
phylogenie/draw.py,sha256=F0XCHn9ARpWuG1t9dwi7sNc7meBQYfKUgAnNsBm3tXU,5132
|
|
3
3
|
phylogenie/generators/__init__.py,sha256=zsOxy28-9j9alOQLIgrOAFfmM58NNHO_NEtW-KXQXAY,888
|
|
4
4
|
phylogenie/generators/alisim.py,sha256=0aCLuGInifWgAvfh7zARWSKF4EMw3TjlPXMLSECui0k,2783
|
|
5
5
|
phylogenie/generators/configs.py,sha256=WFoeKpgj9ZQIom7BKqwpgXbriiQGg3jFBMLoD8KButk,1073
|
|
@@ -7,7 +7,7 @@ phylogenie/generators/dataset.py,sha256=pPwW9yxm9fkU0PPllFq8EsPlqau8tth-4OatbA_h
|
|
|
7
7
|
phylogenie/generators/factories.py,sha256=TuVFQWRjq33Hewjw_Lp8tQ0l_IPtqYDyQCNJhtiHpw8,7882
|
|
8
8
|
phylogenie/generators/trees.py,sha256=6tHS013RNRyIsObeYq2Kx9it7Yc0TgiMkeAHbskHzAM,10748
|
|
9
9
|
phylogenie/generators/typeguards.py,sha256=yj4VkhOaUXJ2OrY-6zhOeY9C4yKIQxjZtk2d-vIxttQ,828
|
|
10
|
-
phylogenie/io.py,sha256=
|
|
10
|
+
phylogenie/io.py,sha256=vUG2yVtoV98tNHut46uSuB3VPj6s64VDhUp1EaSk0o0,4084
|
|
11
11
|
phylogenie/main.py,sha256=vtvSpQxBNlYABoFQ25czl-l3fIr4QRo3svWVd-jcArw,1170
|
|
12
12
|
phylogenie/models.py,sha256=pCg9ob0RpLUHwM49x4knKxL4FNPr3-EU_6zMXsvxtAg,370
|
|
13
13
|
phylogenie/msa.py,sha256=JDGyZUsAq6-m-SQjoCDjAkAZIxfgyl_PDIhdYn5HOow,2064
|
|
@@ -16,7 +16,7 @@ phylogenie/skyline/__init__.py,sha256=7pF4CUb4ZCLzNYJNhOjpuTOLTRhlK7L6ugfccNqjIG
|
|
|
16
16
|
phylogenie/skyline/matrix.py,sha256=Gl8OgKjtieG0NwPYiPimKI36gefV8fm_OeorjdXxPTs,9146
|
|
17
17
|
phylogenie/skyline/parameter.py,sha256=EM9qlPt0JhMBy3TbztM0dj24BaGNEy8KWKdTObDKhbI,4644
|
|
18
18
|
phylogenie/skyline/vector.py,sha256=bJP7_FNX_Klt6wXqsyfj0KX3VNj6-dIhzCKSJuQcOV0,7115
|
|
19
|
-
phylogenie/tree.py,sha256=
|
|
19
|
+
phylogenie/tree.py,sha256=P1uM6s32TsODpvNJQIPMix9oj39vGSw_wsHYp2wmy5U,5246
|
|
20
20
|
phylogenie/treesimulator/__init__.py,sha256=yqS2vtYMhdWSXc9RAnX1dd4zAqSQweMLyVKTnJLfGTU,1106
|
|
21
21
|
phylogenie/treesimulator/events/__init__.py,sha256=6zSgZ0MEUMvTK4yPlSolJnRWzCARLS-jYreTzh45mQo,1033
|
|
22
22
|
phylogenie/treesimulator/events/contact_tracing.py,sha256=_nJ85yhgGkeruQgMHvGpDYoyhheBf8M4LgZWiWdi5dY,4801
|
|
@@ -28,8 +28,8 @@ phylogenie/treesimulator/model.py,sha256=Nyg6R8XmMwZMSw1-dII81sU9uU7tDe-NMs8v1qK
|
|
|
28
28
|
phylogenie/typeguards.py,sha256=JtqmbEWJZBRHbWgCvcl6nrWm3VcBfzRbklbTBYHItn0,1325
|
|
29
29
|
phylogenie/typings.py,sha256=GknvAFXyiaWeeYJ8Lk5d6E2VHT-xW6ONEojYbtJYiB8,476
|
|
30
30
|
phylogenie/utils.py,sha256=ehVk_2kvjW8Q_EyM2kxBPHYiK-KlPmZQx7JeVN6Fh-E,5419
|
|
31
|
-
phylogenie-2.1.
|
|
32
|
-
phylogenie-2.1.
|
|
33
|
-
phylogenie-2.1.
|
|
34
|
-
phylogenie-2.1.
|
|
35
|
-
phylogenie-2.1.
|
|
31
|
+
phylogenie-2.1.22.dist-info/LICENSE.txt,sha256=NUrDqElK-eD3I0WqC004CJsy6cs0JgsAoebDv_42-pw,1071
|
|
32
|
+
phylogenie-2.1.22.dist-info/METADATA,sha256=QgoaWVi9EtxzC1LHpAP7Kt4NyQoH6m8HjdNWGtLEvB8,5477
|
|
33
|
+
phylogenie-2.1.22.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
34
|
+
phylogenie-2.1.22.dist-info/entry_points.txt,sha256=Rt6_usN0FkBX1ZfiqCirjMN9FKOgFLG8rydcQ8kugeE,51
|
|
35
|
+
phylogenie-2.1.22.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|