phylogenie 3.1.7__tar.gz → 3.1.11__tar.gz
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-3.1.7/src/phylogenie.egg-info → phylogenie-3.1.11}/PKG-INFO +5 -6
- {phylogenie-3.1.7 → phylogenie-3.1.11}/README.md +4 -5
- {phylogenie-3.1.7 → phylogenie-3.1.11}/pyproject.toml +1 -1
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/__init__.py +0 -14
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/draw.py +113 -25
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/io/fasta.py +9 -3
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/msa.py +4 -3
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/__init__.py +6 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/features.py +6 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/tree.py +10 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/utils.py +11 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11/src/phylogenie.egg-info}/PKG-INFO +5 -6
- {phylogenie-3.1.7 → phylogenie-3.1.11}/LICENSE.txt +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/setup.cfg +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/generators/__init__.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/generators/alisim.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/generators/configs.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/generators/dataset.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/generators/factories.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/generators/trees.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/generators/typeguards.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/io/__init__.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/main.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/mixins.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/py.typed +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/skyline/__init__.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/skyline/matrix.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/skyline/parameter.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/skyline/vector.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/events/__init__.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/events/base.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/events/contact_tracing.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/events/core.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/events/mutations.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/gillespie.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/io/__init__.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/io/newick.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/io/nexus.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/model.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/typeguards.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/typings.py +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie.egg-info/SOURCES.txt +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie.egg-info/dependency_links.txt +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie.egg-info/entry_points.txt +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie.egg-info/requires.txt +0 -0
- {phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: phylogenie
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.11
|
|
4
4
|
Summary: Generate phylogenetic datasets with minimal setup effort
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -23,7 +23,6 @@ Dynamic: license-file
|
|
|
23
23
|
[](https://pypi.org/project/phylogenie/)
|
|
24
24
|

|
|
25
25
|
|
|
26
|
-
|
|
27
26
|
Phylogenie is a [Python](https://www.python.org/) package designed to easily simulate phylogenetic datasets—such as trees and multiple sequence alignments (MSAs)—with minimal setup effort. Simply specify the distributions from which your parameters should be sampled, and Phylogenie will handle the rest!
|
|
28
27
|
|
|
29
28
|
## ✨ Features
|
|
@@ -73,21 +72,21 @@ Phylogenie relies on [AliSim](https://iqtree.github.io/doc/AliSim) for simulatin
|
|
|
73
72
|
|
|
74
73
|
## 🚀 Quick Start
|
|
75
74
|
|
|
76
|
-
Once you have installed Phylogenie, check out the [
|
|
75
|
+
Once you have installed Phylogenie, check out the [tutorials](https://github.com/gabriele-marino/phylogenie/tree/main/tutorials) folder.
|
|
77
76
|
It includes a collection of thoroughly commented configuration files, organized as a step-by-step tutorial. These examples will help you understand how to use Phylogenie in practice and can be easily adapted to fit your own workflow.
|
|
78
77
|
|
|
79
78
|
For quick start, pick your favorite config file and run Phylogenie with:
|
|
80
79
|
```bash
|
|
81
|
-
phylogenie
|
|
80
|
+
phylogenie tutorials/config_file.yaml
|
|
82
81
|
```
|
|
83
82
|
This command will create the output dataset in the folder specified inside the configuration file, including data directories and metadata files for each dataset split defined in the config.
|
|
84
83
|
|
|
85
84
|
>❗ *Tip*: Can’t choose just one config file?
|
|
86
|
-
You can run them all at once by pointing Phylogenie to the folder! Just use: `phylogenie
|
|
85
|
+
You can run them all at once by pointing Phylogenie to the folder! Just use: `phylogenie tutorials`. In this mode, Phylogenie will automatically find all `.yaml` files in the folder you specified and run for each of them!
|
|
87
86
|
|
|
88
87
|
## 📖 Documentation
|
|
89
88
|
|
|
90
|
-
- The [
|
|
89
|
+
- The [tutorials](https://github.com/gabriele-marino/phylogenie/tree/main/tutorials) folder contains many ready-to-use, extensively commented configuration files that serve as a step-by-step tutorial to guide you through using Phylogenie. You can explore them to learn how it works or adapt them directly to your own workflows.
|
|
91
90
|
- A complete user guide and API reference are under development. In the meantime, feel free to [reach out](mailto:gabmarino.8601@email.com) if you have any questions about integrating Phylogenie into your workflows.
|
|
92
91
|
|
|
93
92
|
## 📄 License
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
[](https://pypi.org/project/phylogenie/)
|
|
9
9
|

|
|
10
10
|
|
|
11
|
-
|
|
12
11
|
Phylogenie is a [Python](https://www.python.org/) package designed to easily simulate phylogenetic datasets—such as trees and multiple sequence alignments (MSAs)—with minimal setup effort. Simply specify the distributions from which your parameters should be sampled, and Phylogenie will handle the rest!
|
|
13
12
|
|
|
14
13
|
## ✨ Features
|
|
@@ -58,21 +57,21 @@ Phylogenie relies on [AliSim](https://iqtree.github.io/doc/AliSim) for simulatin
|
|
|
58
57
|
|
|
59
58
|
## 🚀 Quick Start
|
|
60
59
|
|
|
61
|
-
Once you have installed Phylogenie, check out the [
|
|
60
|
+
Once you have installed Phylogenie, check out the [tutorials](https://github.com/gabriele-marino/phylogenie/tree/main/tutorials) folder.
|
|
62
61
|
It includes a collection of thoroughly commented configuration files, organized as a step-by-step tutorial. These examples will help you understand how to use Phylogenie in practice and can be easily adapted to fit your own workflow.
|
|
63
62
|
|
|
64
63
|
For quick start, pick your favorite config file and run Phylogenie with:
|
|
65
64
|
```bash
|
|
66
|
-
phylogenie
|
|
65
|
+
phylogenie tutorials/config_file.yaml
|
|
67
66
|
```
|
|
68
67
|
This command will create the output dataset in the folder specified inside the configuration file, including data directories and metadata files for each dataset split defined in the config.
|
|
69
68
|
|
|
70
69
|
>❗ *Tip*: Can’t choose just one config file?
|
|
71
|
-
You can run them all at once by pointing Phylogenie to the folder! Just use: `phylogenie
|
|
70
|
+
You can run them all at once by pointing Phylogenie to the folder! Just use: `phylogenie tutorials`. In this mode, Phylogenie will automatically find all `.yaml` files in the folder you specified and run for each of them!
|
|
72
71
|
|
|
73
72
|
## 📖 Documentation
|
|
74
73
|
|
|
75
|
-
- The [
|
|
74
|
+
- The [tutorials](https://github.com/gabriele-marino/phylogenie/tree/main/tutorials) folder contains many ready-to-use, extensively commented configuration files that serve as a step-by-step tutorial to guide you through using Phylogenie. You can explore them to learn how it works or adapt them directly to your own workflows.
|
|
76
75
|
- A complete user guide and API reference are under development. In the meantime, feel free to [reach out](mailto:gabmarino.8601@email.com) if you have any questions about integrating Phylogenie into your workflows.
|
|
77
76
|
|
|
78
77
|
## 📄 License
|
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
from phylogenie.draw import (
|
|
2
|
-
draw_colored_dated_tree_categorical,
|
|
3
|
-
draw_colored_dated_tree_continuous,
|
|
4
|
-
draw_colored_tree_categorical,
|
|
5
|
-
draw_colored_tree_continuous,
|
|
6
|
-
draw_dated_tree,
|
|
7
|
-
draw_tree,
|
|
8
|
-
)
|
|
9
1
|
from phylogenie.generators import (
|
|
10
2
|
AliSimDatasetGenerator,
|
|
11
3
|
BDEITreeDatasetGenerator,
|
|
@@ -71,12 +63,6 @@ from phylogenie.treesimulator import (
|
|
|
71
63
|
)
|
|
72
64
|
|
|
73
65
|
__all__ = [
|
|
74
|
-
"draw_colored_dated_tree_categorical",
|
|
75
|
-
"draw_colored_dated_tree_continuous",
|
|
76
|
-
"draw_colored_tree_categorical",
|
|
77
|
-
"draw_colored_tree_continuous",
|
|
78
|
-
"draw_dated_tree",
|
|
79
|
-
"draw_tree",
|
|
80
66
|
"AliSimDatasetGenerator",
|
|
81
67
|
"BDEITreeDatasetGenerator",
|
|
82
68
|
"BDSSTreeDatasetGenerator",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import datetime
|
|
1
2
|
from dataclasses import dataclass
|
|
2
|
-
from datetime import datetime
|
|
3
3
|
from typing import Any, Literal, overload
|
|
4
4
|
|
|
5
5
|
import matplotlib.colors as mcolors
|
|
@@ -10,13 +10,18 @@ from matplotlib.axes import Axes
|
|
|
10
10
|
from matplotlib.colors import Colormap
|
|
11
11
|
from mpl_toolkits.axes_grid1.inset_locator import inset_axes # pyright: ignore
|
|
12
12
|
|
|
13
|
-
from phylogenie.treesimulator import
|
|
13
|
+
from phylogenie.treesimulator import (
|
|
14
|
+
Tree,
|
|
15
|
+
get_node_ages,
|
|
16
|
+
get_node_depth_levels,
|
|
17
|
+
get_node_depths,
|
|
18
|
+
)
|
|
14
19
|
|
|
15
20
|
|
|
16
21
|
@dataclass
|
|
17
22
|
class CalibrationNode:
|
|
18
23
|
node: Tree
|
|
19
|
-
date: datetime
|
|
24
|
+
date: datetime.date
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
Color = str | tuple[float, float, float] | tuple[float, float, float, float]
|
|
@@ -27,6 +32,8 @@ def draw_tree(
|
|
|
27
32
|
ax: Axes | None = None,
|
|
28
33
|
colors: Color | dict[Tree, Color] = "black",
|
|
29
34
|
backward_time: bool = False,
|
|
35
|
+
branch_kwargs: dict[str, Any] | None = None,
|
|
36
|
+
sampled_ancestor_kwargs: dict[str, Any] | None = None,
|
|
30
37
|
) -> Axes:
|
|
31
38
|
"""
|
|
32
39
|
Draw a phylogenetic tree with colored branches.
|
|
@@ -41,6 +48,10 @@ def draw_tree(
|
|
|
41
48
|
A single color for all branches or a dictionary mapping each node to a color.
|
|
42
49
|
backward_time : bool, optional
|
|
43
50
|
If True, the x-axis is inverted to represent time going backward.
|
|
51
|
+
branch_kwargs : dict[str, Any] | None, optional
|
|
52
|
+
Additional keyword arguments to pass to the branch drawing functions.
|
|
53
|
+
sampled_ancestor_kwargs : dict[str, Any] | None, optional
|
|
54
|
+
Additional keyword arguments to highlight sampled ancestors.
|
|
44
55
|
|
|
45
56
|
Returns
|
|
46
57
|
-------
|
|
@@ -49,33 +60,51 @@ def draw_tree(
|
|
|
49
60
|
"""
|
|
50
61
|
if ax is None:
|
|
51
62
|
ax = plt.gca()
|
|
63
|
+
if branch_kwargs is None:
|
|
64
|
+
branch_kwargs = {}
|
|
65
|
+
if sampled_ancestor_kwargs is None:
|
|
66
|
+
sampled_ancestor_kwargs = {}
|
|
67
|
+
if "marker" not in sampled_ancestor_kwargs:
|
|
68
|
+
sampled_ancestor_kwargs["marker"] = "o"
|
|
52
69
|
|
|
53
70
|
if not isinstance(colors, dict):
|
|
54
71
|
colors = {node: colors for node in tree}
|
|
55
72
|
|
|
56
73
|
xs = (
|
|
57
|
-
|
|
74
|
+
get_node_ages(tree)
|
|
75
|
+
if backward_time
|
|
76
|
+
else get_node_depth_levels(tree)
|
|
58
77
|
if any(node.branch_length is None for node in tree.iter_descendants())
|
|
59
78
|
else get_node_depths(tree)
|
|
60
79
|
)
|
|
61
|
-
if backward_time:
|
|
62
|
-
max_x = max(xs.values())
|
|
63
|
-
xs = {node: max_x - x for node, x in xs.items()}
|
|
64
80
|
|
|
65
|
-
|
|
81
|
+
leaves = tree.get_leaves()
|
|
82
|
+
ys: dict[Tree, float] = {
|
|
83
|
+
node: i
|
|
84
|
+
for i, node in enumerate(leaves)
|
|
85
|
+
if node.parent is None or node.branch_length != 0
|
|
86
|
+
}
|
|
66
87
|
for node in tree.postorder_traversal():
|
|
67
88
|
if node.is_internal():
|
|
68
|
-
|
|
89
|
+
children = [child for child in node.children if child.branch_length != 0]
|
|
90
|
+
ys[node] = sum(ys[child] for child in children) / len(children)
|
|
91
|
+
for leaf in leaves:
|
|
92
|
+
if leaf.parent is not None and leaf.branch_length == 0:
|
|
93
|
+
ys[leaf] = ys[leaf.parent]
|
|
69
94
|
|
|
70
95
|
if tree.branch_length is not None:
|
|
71
96
|
xmin = xs[tree] + tree.branch_length if backward_time else 0
|
|
72
|
-
ax.hlines(
|
|
97
|
+
ax.hlines( # pyright: ignore
|
|
98
|
+
y=ys[tree], xmin=xmin, xmax=xs[tree], color=colors[tree], **branch_kwargs
|
|
99
|
+
)
|
|
73
100
|
for node in tree:
|
|
74
101
|
x1, y1 = xs[node], ys[node]
|
|
102
|
+
if node.parent is not None and node.branch_length == 0:
|
|
103
|
+
ax.plot(x1, y1, color=colors[node], **sampled_ancestor_kwargs) # pyright: ignore
|
|
75
104
|
for child in node.children:
|
|
76
105
|
x2, y2 = xs[child], ys[child]
|
|
77
|
-
ax.hlines(y=y2, xmin=x1, xmax=x2, color=colors[child]) # pyright: ignore
|
|
78
|
-
ax.vlines(x=x1, ymin=y1, ymax=y2, color=colors[child]) # pyright: ignore
|
|
106
|
+
ax.hlines(y=y2, xmin=x1, xmax=x2, color=colors[child], **branch_kwargs) # pyright: ignore
|
|
107
|
+
ax.vlines(x=x1, ymin=y1, ymax=y2, color=colors[child], **branch_kwargs) # pyright: ignore
|
|
79
108
|
|
|
80
109
|
if backward_time:
|
|
81
110
|
ax.invert_xaxis()
|
|
@@ -86,7 +115,7 @@ def draw_tree(
|
|
|
86
115
|
|
|
87
116
|
def _depth_to_date(
|
|
88
117
|
depth: float, calibration_nodes: tuple[CalibrationNode, CalibrationNode]
|
|
89
|
-
) -> datetime:
|
|
118
|
+
) -> datetime.date:
|
|
90
119
|
"""
|
|
91
120
|
Convert a depth value to a date using linear interpolation between two calibration nodes.
|
|
92
121
|
|
|
@@ -99,7 +128,7 @@ def _depth_to_date(
|
|
|
99
128
|
|
|
100
129
|
Returns
|
|
101
130
|
-------
|
|
102
|
-
datetime
|
|
131
|
+
datetime.date
|
|
103
132
|
The interpolated date corresponding to the given depth.
|
|
104
133
|
"""
|
|
105
134
|
node1, node2 = calibration_nodes
|
|
@@ -113,6 +142,7 @@ def draw_dated_tree(
|
|
|
113
142
|
calibration_nodes: tuple[CalibrationNode, CalibrationNode],
|
|
114
143
|
ax: Axes | None = None,
|
|
115
144
|
colors: Color | dict[Tree, Color] = "black",
|
|
145
|
+
branch_kwargs: dict[str, Any] | None = None,
|
|
116
146
|
) -> Axes:
|
|
117
147
|
"""
|
|
118
148
|
Draw a phylogenetic tree with branches positioned according to calibrated dates.
|
|
@@ -127,6 +157,8 @@ def draw_dated_tree(
|
|
|
127
157
|
The matplotlib Axes to draw on. If None, uses the current Axes.
|
|
128
158
|
colors : Color | dict[Tree, Color], optional
|
|
129
159
|
A single color for all branches or a dictionary mapping each node to a color.
|
|
160
|
+
branch_kwargs : dict[str, Any] | None, optional
|
|
161
|
+
Additional keyword arguments to pass to the branch drawing functions.
|
|
130
162
|
|
|
131
163
|
Returns
|
|
132
164
|
-------
|
|
@@ -135,6 +167,8 @@ def draw_dated_tree(
|
|
|
135
167
|
"""
|
|
136
168
|
if ax is None:
|
|
137
169
|
ax = plt.gca()
|
|
170
|
+
if branch_kwargs is None:
|
|
171
|
+
branch_kwargs = {}
|
|
138
172
|
|
|
139
173
|
if not isinstance(colors, dict):
|
|
140
174
|
colors = {node: colors for node in tree}
|
|
@@ -156,6 +190,7 @@ def draw_dated_tree(
|
|
|
156
190
|
xmin=mdates.date2num(origin_date), # pyright: ignore
|
|
157
191
|
xmax=mdates.date2num(xs[tree]), # pyright: ignore
|
|
158
192
|
color=colors[tree],
|
|
193
|
+
**branch_kwargs,
|
|
159
194
|
)
|
|
160
195
|
for node in tree:
|
|
161
196
|
x1, y1 = xs[node], ys[node]
|
|
@@ -166,8 +201,15 @@ def draw_dated_tree(
|
|
|
166
201
|
xmin=mdates.date2num(x1), # pyright: ignore
|
|
167
202
|
xmax=mdates.date2num(x2), # pyright: ignore
|
|
168
203
|
color=colors[child],
|
|
204
|
+
**branch_kwargs,
|
|
205
|
+
)
|
|
206
|
+
ax.vlines( # pyright: ignore
|
|
207
|
+
x=mdates.date2num(x1), # pyright: ignore
|
|
208
|
+
ymin=y1,
|
|
209
|
+
ymax=y2,
|
|
210
|
+
color=colors[child],
|
|
211
|
+
**branch_kwargs,
|
|
169
212
|
)
|
|
170
|
-
ax.vlines(x=mdates.date2num(x1), ymin=y1, ymax=y2, color=colors[child]) # pyright: ignore
|
|
171
213
|
|
|
172
214
|
ax.xaxis.set_major_locator(mdates.AutoDateLocator())
|
|
173
215
|
ax.xaxis.set_major_formatter(mdates.DateFormatter("%Y-%m-%d"))
|
|
@@ -256,6 +298,8 @@ def draw_colored_tree_categorical(
|
|
|
256
298
|
show_legend: bool = True,
|
|
257
299
|
labels: dict[Any, str] | None = None,
|
|
258
300
|
legend_kwargs: dict[str, Any] | None = None,
|
|
301
|
+
branch_kwargs: dict[str, Any] | None = None,
|
|
302
|
+
sampled_ancestor_kwargs: dict[str, Any] | None = None,
|
|
259
303
|
):
|
|
260
304
|
"""
|
|
261
305
|
Draw a phylogenetic tree with branches colored based on categorical metadata.
|
|
@@ -280,6 +324,10 @@ def draw_colored_tree_categorical(
|
|
|
280
324
|
A mapping from category values to labels for the legend.
|
|
281
325
|
legend_kwargs : dict[str, Any] | None, optional
|
|
282
326
|
Additional keyword arguments to pass to the legend.
|
|
327
|
+
branch_kwargs : dict[str, Any] | None, optional
|
|
328
|
+
Additional keyword arguments to pass to the branch drawing functions.
|
|
329
|
+
sampled_ancestor_kwargs : dict[str, Any] | None, optional
|
|
330
|
+
Additional keyword arguments to highlight sampled ancestors.
|
|
283
331
|
|
|
284
332
|
Returns
|
|
285
333
|
-------
|
|
@@ -296,7 +344,14 @@ def draw_colored_tree_categorical(
|
|
|
296
344
|
labels=labels,
|
|
297
345
|
legend_kwargs=legend_kwargs,
|
|
298
346
|
)
|
|
299
|
-
return draw_tree(
|
|
347
|
+
return draw_tree(
|
|
348
|
+
tree=tree,
|
|
349
|
+
ax=ax,
|
|
350
|
+
colors=colors,
|
|
351
|
+
backward_time=backward_time,
|
|
352
|
+
branch_kwargs=branch_kwargs,
|
|
353
|
+
sampled_ancestor_kwargs=sampled_ancestor_kwargs,
|
|
354
|
+
)
|
|
300
355
|
|
|
301
356
|
|
|
302
357
|
def draw_colored_dated_tree_categorical(
|
|
@@ -309,6 +364,7 @@ def draw_colored_dated_tree_categorical(
|
|
|
309
364
|
show_legend: bool = True,
|
|
310
365
|
labels: dict[Any, str] | None = None,
|
|
311
366
|
legend_kwargs: dict[str, Any] | None = None,
|
|
367
|
+
branch_kwargs: dict[str, Any] | None = None,
|
|
312
368
|
) -> Axes:
|
|
313
369
|
"""
|
|
314
370
|
Draw a dated phylogenetic tree with branches colored based on categorical metadata.
|
|
@@ -333,6 +389,8 @@ def draw_colored_dated_tree_categorical(
|
|
|
333
389
|
A mapping from category values to labels for the legend.
|
|
334
390
|
legend_kwargs : dict[str, Any] | None, optional
|
|
335
391
|
Additional keyword arguments to pass to the legend.
|
|
392
|
+
branch_kwargs : dict[str, Any] | None, optional
|
|
393
|
+
Additional keyword arguments to pass to the branch drawing functions.
|
|
336
394
|
|
|
337
395
|
Returns
|
|
338
396
|
-------
|
|
@@ -350,7 +408,11 @@ def draw_colored_dated_tree_categorical(
|
|
|
350
408
|
legend_kwargs=legend_kwargs,
|
|
351
409
|
)
|
|
352
410
|
return draw_dated_tree(
|
|
353
|
-
tree=tree,
|
|
411
|
+
tree=tree,
|
|
412
|
+
calibration_nodes=calibration_nodes,
|
|
413
|
+
ax=ax,
|
|
414
|
+
colors=colors,
|
|
415
|
+
branch_kwargs=branch_kwargs,
|
|
354
416
|
)
|
|
355
417
|
|
|
356
418
|
|
|
@@ -378,7 +440,7 @@ def _init_colored_tree_continuous(
|
|
|
378
440
|
vmin: float | None = ...,
|
|
379
441
|
vmax: float | None = ...,
|
|
380
442
|
*,
|
|
381
|
-
show_hist: Literal[True],
|
|
443
|
+
show_hist: Literal[True] = True,
|
|
382
444
|
hist_kwargs: dict[str, Any] | None = ...,
|
|
383
445
|
hist_axes_kwargs: dict[str, Any] | None = ...,
|
|
384
446
|
) -> tuple[Axes, dict[Tree, Color], Axes]: ...
|
|
@@ -390,7 +452,6 @@ def _init_colored_tree_continuous(
|
|
|
390
452
|
colormap: str | Colormap = "viridis",
|
|
391
453
|
vmin: float | None = None,
|
|
392
454
|
vmax: float | None = None,
|
|
393
|
-
*,
|
|
394
455
|
show_hist: bool = True,
|
|
395
456
|
hist_kwargs: dict[str, Any] | None = None,
|
|
396
457
|
hist_axes_kwargs: dict[str, Any] | None = None,
|
|
@@ -474,6 +535,8 @@ def draw_colored_tree_continuous(
|
|
|
474
535
|
colormap: str | Colormap = "viridis",
|
|
475
536
|
vmin: float | None = None,
|
|
476
537
|
vmax: float | None = None,
|
|
538
|
+
branch_kwargs: dict[str, Any] | None = None,
|
|
539
|
+
sampled_ancestor_kwargs: dict[str, Any] | None = None,
|
|
477
540
|
*,
|
|
478
541
|
show_hist: Literal[False],
|
|
479
542
|
hist_kwargs: dict[str, Any] | None = None,
|
|
@@ -489,8 +552,9 @@ def draw_colored_tree_continuous(
|
|
|
489
552
|
colormap: str | Colormap = "viridis",
|
|
490
553
|
vmin: float | None = None,
|
|
491
554
|
vmax: float | None = None,
|
|
492
|
-
|
|
493
|
-
|
|
555
|
+
branch_kwargs: dict[str, Any] | None = None,
|
|
556
|
+
sampled_ancestor_kwargs: dict[str, Any] | None = None,
|
|
557
|
+
show_hist: Literal[True] = True,
|
|
494
558
|
hist_kwargs: dict[str, Any] | None = None,
|
|
495
559
|
hist_axes_kwargs: dict[str, Any] | None = None,
|
|
496
560
|
) -> tuple[Axes, Axes]: ...
|
|
@@ -503,6 +567,8 @@ def draw_colored_tree_continuous(
|
|
|
503
567
|
colormap: str | Colormap = "viridis",
|
|
504
568
|
vmin: float | None = None,
|
|
505
569
|
vmax: float | None = None,
|
|
570
|
+
branch_kwargs: dict[str, Any] | None = None,
|
|
571
|
+
sampled_ancestor_kwargs: dict[str, Any] | None = None,
|
|
506
572
|
show_hist: bool = True,
|
|
507
573
|
hist_kwargs: dict[str, Any] | None = None,
|
|
508
574
|
hist_axes_kwargs: dict[str, Any] | None = None,
|
|
@@ -528,6 +594,10 @@ def draw_colored_tree_continuous(
|
|
|
528
594
|
The minimum value for normalization. If None, uses the minimum of the data.
|
|
529
595
|
vmax : float | None, optional
|
|
530
596
|
The maximum value for normalization. If None, uses the maximum of the data.
|
|
597
|
+
branch_kwargs : dict[str, Any] | None, optional
|
|
598
|
+
Additional keyword arguments to pass to the branch drawing functions.
|
|
599
|
+
sampled_ancestor_kwargs : dict[str, Any] | None, optional
|
|
600
|
+
Additional keyword arguments to highlight sampled ancestors.
|
|
531
601
|
show_hist : bool, optional
|
|
532
602
|
Whether to display a histogram of the continuous values.
|
|
533
603
|
hist_kwargs : dict[str, Any] | None, optional
|
|
@@ -555,7 +625,12 @@ def draw_colored_tree_continuous(
|
|
|
555
625
|
hist_axes_kwargs=hist_axes_kwargs,
|
|
556
626
|
)
|
|
557
627
|
return draw_tree(
|
|
558
|
-
tree=tree,
|
|
628
|
+
tree=tree,
|
|
629
|
+
ax=ax,
|
|
630
|
+
colors=colors,
|
|
631
|
+
backward_time=backward_time,
|
|
632
|
+
branch_kwargs=branch_kwargs,
|
|
633
|
+
sampled_ancestor_kwargs=sampled_ancestor_kwargs,
|
|
559
634
|
), hist_ax
|
|
560
635
|
|
|
561
636
|
ax, colors = _init_colored_tree_continuous(
|
|
@@ -570,7 +645,14 @@ def draw_colored_tree_continuous(
|
|
|
570
645
|
hist_kwargs=hist_kwargs,
|
|
571
646
|
hist_axes_kwargs=hist_axes_kwargs,
|
|
572
647
|
)
|
|
573
|
-
return draw_tree(
|
|
648
|
+
return draw_tree(
|
|
649
|
+
tree=tree,
|
|
650
|
+
ax=ax,
|
|
651
|
+
colors=colors,
|
|
652
|
+
backward_time=backward_time,
|
|
653
|
+
branch_kwargs=branch_kwargs,
|
|
654
|
+
sampled_ancestor_kwargs=sampled_ancestor_kwargs,
|
|
655
|
+
)
|
|
574
656
|
|
|
575
657
|
|
|
576
658
|
@overload
|
|
@@ -583,6 +665,7 @@ def draw_colored_dated_tree_continuous(
|
|
|
583
665
|
colormap: str | Colormap = "viridis",
|
|
584
666
|
vmin: float | None = None,
|
|
585
667
|
vmax: float | None = None,
|
|
668
|
+
branch_kwargs: dict[str, Any] | None = None,
|
|
586
669
|
*,
|
|
587
670
|
show_hist: Literal[False],
|
|
588
671
|
hist_kwargs: dict[str, Any] | None = None,
|
|
@@ -598,8 +681,8 @@ def draw_colored_dated_tree_continuous(
|
|
|
598
681
|
colormap: str | Colormap = "viridis",
|
|
599
682
|
vmin: float | None = None,
|
|
600
683
|
vmax: float | None = None,
|
|
601
|
-
|
|
602
|
-
show_hist: Literal[True],
|
|
684
|
+
branch_kwargs: dict[str, Any] | None = None,
|
|
685
|
+
show_hist: Literal[True] = True,
|
|
603
686
|
hist_kwargs: dict[str, Any] | None = None,
|
|
604
687
|
hist_axes_kwargs: dict[str, Any] | None = None,
|
|
605
688
|
) -> tuple[Axes, Axes]: ...
|
|
@@ -612,6 +695,7 @@ def draw_colored_dated_tree_continuous(
|
|
|
612
695
|
colormap: str | Colormap = "viridis",
|
|
613
696
|
vmin: float | None = None,
|
|
614
697
|
vmax: float | None = None,
|
|
698
|
+
branch_kwargs: dict[str, Any] | None = None,
|
|
615
699
|
show_hist: bool = True,
|
|
616
700
|
hist_kwargs: dict[str, Any] | None = None,
|
|
617
701
|
hist_axes_kwargs: dict[str, Any] | None = None,
|
|
@@ -637,6 +721,8 @@ def draw_colored_dated_tree_continuous(
|
|
|
637
721
|
The minimum value for normalization. If None, uses the minimum of the data.
|
|
638
722
|
vmax : float | None, optional
|
|
639
723
|
The maximum value for normalization. If None, uses the maximum of the data.
|
|
724
|
+
branch_kwargs : dict[str, Any] | None, optional
|
|
725
|
+
Additional keyword arguments to pass to the branch drawing functions.
|
|
640
726
|
show_hist : bool, optional
|
|
641
727
|
Whether to display a histogram of the continuous values.
|
|
642
728
|
hist_kwargs : dict[str, Any] | None, optional
|
|
@@ -668,6 +754,7 @@ def draw_colored_dated_tree_continuous(
|
|
|
668
754
|
calibration_nodes=calibration_nodes,
|
|
669
755
|
ax=ax,
|
|
670
756
|
colors=colors,
|
|
757
|
+
branch_kwargs=branch_kwargs,
|
|
671
758
|
), hist_ax
|
|
672
759
|
|
|
673
760
|
ax, colors = _init_colored_tree_continuous(
|
|
@@ -687,4 +774,5 @@ def draw_colored_dated_tree_continuous(
|
|
|
687
774
|
calibration_nodes=calibration_nodes,
|
|
688
775
|
ax=ax,
|
|
689
776
|
colors=colors,
|
|
777
|
+
branch_kwargs=branch_kwargs,
|
|
690
778
|
)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from datetime import date
|
|
1
2
|
from pathlib import Path
|
|
2
3
|
from typing import Callable
|
|
3
4
|
|
|
@@ -5,7 +6,8 @@ from phylogenie.msa import MSA, Sequence
|
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
def load_fasta(
|
|
8
|
-
fasta_file: str | Path,
|
|
9
|
+
fasta_file: str | Path,
|
|
10
|
+
extract_time_from_id: Callable[[str], float | date] | None = None,
|
|
9
11
|
) -> MSA:
|
|
10
12
|
sequences: list[Sequence] = []
|
|
11
13
|
with open(fasta_file, "r") as f:
|
|
@@ -17,10 +19,14 @@ def load_fasta(
|
|
|
17
19
|
if extract_time_from_id is not None:
|
|
18
20
|
time = extract_time_from_id(id)
|
|
19
21
|
elif "|" in id:
|
|
22
|
+
last_metadata = id.split("|")[-1]
|
|
20
23
|
try:
|
|
21
|
-
time = float(
|
|
24
|
+
time = float(last_metadata)
|
|
22
25
|
except ValueError:
|
|
23
|
-
|
|
26
|
+
try:
|
|
27
|
+
time = date.fromisoformat(last_metadata)
|
|
28
|
+
except ValueError:
|
|
29
|
+
pass
|
|
24
30
|
chars = next(f).strip()
|
|
25
31
|
sequences.append(Sequence(id, chars, time))
|
|
26
32
|
return MSA(sequences)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from collections.abc import Iterator
|
|
2
2
|
from dataclasses import dataclass
|
|
3
|
+
from datetime import date
|
|
3
4
|
|
|
4
5
|
import numpy as np
|
|
5
6
|
|
|
@@ -8,7 +9,7 @@ import numpy as np
|
|
|
8
9
|
class Sequence:
|
|
9
10
|
id: str
|
|
10
11
|
chars: str
|
|
11
|
-
time: float | None = None
|
|
12
|
+
time: float | date | None = None
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
class MSA:
|
|
@@ -25,8 +26,8 @@ class MSA:
|
|
|
25
26
|
return [sequence.id for sequence in self.sequences]
|
|
26
27
|
|
|
27
28
|
@property
|
|
28
|
-
def times(self) -> list[float]:
|
|
29
|
-
times: list[float] = []
|
|
29
|
+
def times(self) -> list[float | date]:
|
|
30
|
+
times: list[float | date] = []
|
|
30
31
|
for sequence in self:
|
|
31
32
|
if sequence.time is None:
|
|
32
33
|
raise ValueError(f"Time is not set for sequence {sequence.id}.")
|
|
@@ -27,11 +27,14 @@ from phylogenie.treesimulator.utils import (
|
|
|
27
27
|
compute_sackin_index,
|
|
28
28
|
get_distance,
|
|
29
29
|
get_mrca,
|
|
30
|
+
get_node_ages,
|
|
30
31
|
get_node_depth_levels,
|
|
31
32
|
get_node_depths,
|
|
32
33
|
get_node_height_levels,
|
|
33
34
|
get_node_heights,
|
|
34
35
|
get_node_leaf_counts,
|
|
36
|
+
get_node_times,
|
|
37
|
+
get_path,
|
|
35
38
|
)
|
|
36
39
|
|
|
37
40
|
__all__ = [
|
|
@@ -65,9 +68,12 @@ __all__ = [
|
|
|
65
68
|
"compute_sackin_index",
|
|
66
69
|
"get_distance",
|
|
67
70
|
"get_mrca",
|
|
71
|
+
"get_node_ages",
|
|
68
72
|
"get_node_depth_levels",
|
|
69
73
|
"get_node_depths",
|
|
70
74
|
"get_node_height_levels",
|
|
71
75
|
"get_node_heights",
|
|
72
76
|
"get_node_leaf_counts",
|
|
77
|
+
"get_node_times",
|
|
78
|
+
"get_path",
|
|
73
79
|
]
|
|
@@ -5,11 +5,13 @@ from phylogenie.treesimulator.events.mutations import get_mutation_id
|
|
|
5
5
|
from phylogenie.treesimulator.model import get_node_state
|
|
6
6
|
from phylogenie.treesimulator.tree import Tree
|
|
7
7
|
from phylogenie.treesimulator.utils import (
|
|
8
|
+
get_node_ages,
|
|
8
9
|
get_node_depth_levels,
|
|
9
10
|
get_node_depths,
|
|
10
11
|
get_node_height_levels,
|
|
11
12
|
get_node_heights,
|
|
12
13
|
get_node_leaf_counts,
|
|
14
|
+
get_node_times,
|
|
13
15
|
)
|
|
14
16
|
|
|
15
17
|
|
|
@@ -22,6 +24,7 @@ def _get_mutations(tree: Tree) -> dict[Tree, int]:
|
|
|
22
24
|
|
|
23
25
|
|
|
24
26
|
class Feature(str, Enum):
|
|
27
|
+
AGE = "age"
|
|
25
28
|
DEPTH = "depth"
|
|
26
29
|
DEPTH_LEVEL = "depth_level"
|
|
27
30
|
HEIGHT = "height"
|
|
@@ -29,9 +32,11 @@ class Feature(str, Enum):
|
|
|
29
32
|
MUTATION = "mutation"
|
|
30
33
|
N_LEAVES = "n_leaves"
|
|
31
34
|
STATE = "state"
|
|
35
|
+
TIME = "time"
|
|
32
36
|
|
|
33
37
|
|
|
34
38
|
FEATURES_EXTRACTORS = {
|
|
39
|
+
Feature.AGE: get_node_ages,
|
|
35
40
|
Feature.DEPTH: get_node_depths,
|
|
36
41
|
Feature.DEPTH_LEVEL: get_node_depth_levels,
|
|
37
42
|
Feature.HEIGHT: get_node_heights,
|
|
@@ -39,6 +44,7 @@ FEATURES_EXTRACTORS = {
|
|
|
39
44
|
Feature.MUTATION: _get_mutations,
|
|
40
45
|
Feature.N_LEAVES: get_node_leaf_counts,
|
|
41
46
|
Feature.STATE: _get_states,
|
|
47
|
+
Feature.TIME: get_node_times,
|
|
42
48
|
}
|
|
43
49
|
|
|
44
50
|
|
|
@@ -153,6 +153,16 @@ class Tree(MetadataMixin):
|
|
|
153
153
|
child.branch_length_or_raise() + child.height for child in self.children
|
|
154
154
|
)
|
|
155
155
|
|
|
156
|
+
@property
|
|
157
|
+
def time(self) -> float:
|
|
158
|
+
return self.depth
|
|
159
|
+
|
|
160
|
+
@property
|
|
161
|
+
def age(self) -> float:
|
|
162
|
+
if self.parent is None:
|
|
163
|
+
return self.height
|
|
164
|
+
return self.parent.age - self.branch_length_or_raise()
|
|
165
|
+
|
|
156
166
|
# -------------
|
|
157
167
|
# Miscellaneous
|
|
158
168
|
# -------------
|
|
@@ -51,6 +51,17 @@ def get_node_heights(tree: Tree) -> dict[Tree, float]:
|
|
|
51
51
|
return heights
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
def get_node_times(tree: Tree) -> dict[Tree, float]:
|
|
55
|
+
return get_node_depths(tree)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def get_node_ages(tree: Tree) -> dict[Tree, float]:
|
|
59
|
+
ages: dict[Tree, float] = {tree: tree.height}
|
|
60
|
+
for node in tree.iter_descendants():
|
|
61
|
+
ages[node] = ages[node.parent] - node.branch_length # pyright: ignore
|
|
62
|
+
return ages
|
|
63
|
+
|
|
64
|
+
|
|
54
65
|
def get_mrca(node1: Tree, node2: Tree) -> Tree:
|
|
55
66
|
node1_ancestors = set(node1.iter_upward())
|
|
56
67
|
for node2_ancestor in node2.iter_upward():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: phylogenie
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.11
|
|
4
4
|
Summary: Generate phylogenetic datasets with minimal setup effort
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -23,7 +23,6 @@ Dynamic: license-file
|
|
|
23
23
|
[](https://pypi.org/project/phylogenie/)
|
|
24
24
|

|
|
25
25
|
|
|
26
|
-
|
|
27
26
|
Phylogenie is a [Python](https://www.python.org/) package designed to easily simulate phylogenetic datasets—such as trees and multiple sequence alignments (MSAs)—with minimal setup effort. Simply specify the distributions from which your parameters should be sampled, and Phylogenie will handle the rest!
|
|
28
27
|
|
|
29
28
|
## ✨ Features
|
|
@@ -73,21 +72,21 @@ Phylogenie relies on [AliSim](https://iqtree.github.io/doc/AliSim) for simulatin
|
|
|
73
72
|
|
|
74
73
|
## 🚀 Quick Start
|
|
75
74
|
|
|
76
|
-
Once you have installed Phylogenie, check out the [
|
|
75
|
+
Once you have installed Phylogenie, check out the [tutorials](https://github.com/gabriele-marino/phylogenie/tree/main/tutorials) folder.
|
|
77
76
|
It includes a collection of thoroughly commented configuration files, organized as a step-by-step tutorial. These examples will help you understand how to use Phylogenie in practice and can be easily adapted to fit your own workflow.
|
|
78
77
|
|
|
79
78
|
For quick start, pick your favorite config file and run Phylogenie with:
|
|
80
79
|
```bash
|
|
81
|
-
phylogenie
|
|
80
|
+
phylogenie tutorials/config_file.yaml
|
|
82
81
|
```
|
|
83
82
|
This command will create the output dataset in the folder specified inside the configuration file, including data directories and metadata files for each dataset split defined in the config.
|
|
84
83
|
|
|
85
84
|
>❗ *Tip*: Can’t choose just one config file?
|
|
86
|
-
You can run them all at once by pointing Phylogenie to the folder! Just use: `phylogenie
|
|
85
|
+
You can run them all at once by pointing Phylogenie to the folder! Just use: `phylogenie tutorials`. In this mode, Phylogenie will automatically find all `.yaml` files in the folder you specified and run for each of them!
|
|
87
86
|
|
|
88
87
|
## 📖 Documentation
|
|
89
88
|
|
|
90
|
-
- The [
|
|
89
|
+
- The [tutorials](https://github.com/gabriele-marino/phylogenie/tree/main/tutorials) folder contains many ready-to-use, extensively commented configuration files that serve as a step-by-step tutorial to guide you through using Phylogenie. You can explore them to learn how it works or adapt them directly to your own workflows.
|
|
91
90
|
- A complete user guide and API reference are under development. In the meantime, feel free to [reach out](mailto:gabmarino.8601@email.com) if you have any questions about integrating Phylogenie into your workflows.
|
|
92
91
|
|
|
93
92
|
## 📄 License
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{phylogenie-3.1.7 → phylogenie-3.1.11}/src/phylogenie/treesimulator/events/contact_tracing.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|