phylogenie 3.1.11__tar.gz → 3.1.18__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.11/src/phylogenie.egg-info → phylogenie-3.1.18}/PKG-INFO +1 -1
- {phylogenie-3.1.11 → phylogenie-3.1.18}/pyproject.toml +2 -2
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/__init__.py +8 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/draw.py +40 -27
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/generators/factories.py +17 -13
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/generators/trees.py +17 -3
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/msa.py +11 -4
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/__init__.py +2 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/gillespie.py +11 -2
- {phylogenie-3.1.11 → phylogenie-3.1.18/src/phylogenie.egg-info}/PKG-INFO +1 -1
- {phylogenie-3.1.11 → phylogenie-3.1.18}/LICENSE.txt +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/README.md +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/setup.cfg +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/generators/__init__.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/generators/alisim.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/generators/configs.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/generators/dataset.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/generators/typeguards.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/io/__init__.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/io/fasta.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/main.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/mixins.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/py.typed +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/skyline/__init__.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/skyline/matrix.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/skyline/parameter.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/skyline/vector.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/events/__init__.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/events/base.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/events/contact_tracing.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/events/core.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/events/mutations.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/features.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/io/__init__.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/io/newick.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/io/nexus.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/model.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/tree.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/treesimulator/utils.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/typeguards.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie/typings.py +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie.egg-info/SOURCES.txt +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie.egg-info/dependency_links.txt +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie.egg-info/entry_points.txt +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie.egg-info/requires.txt +0 -0
- {phylogenie-3.1.11 → phylogenie-3.1.18}/src/phylogenie.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "phylogenie"
|
|
3
|
-
version = "3.1.
|
|
3
|
+
version = "3.1.18"
|
|
4
4
|
description = "Generate phylogenetic datasets with minimal setup effort"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -29,4 +29,4 @@ phylogenie = "phylogenie.main:main"
|
|
|
29
29
|
|
|
30
30
|
[build-system]
|
|
31
31
|
requires = ["setuptools>=42"]
|
|
32
|
-
build-backend = "setuptools.build_meta"
|
|
32
|
+
build-backend = "setuptools.build_meta"
|
|
@@ -38,6 +38,7 @@ from phylogenie.treesimulator import (
|
|
|
38
38
|
Tree,
|
|
39
39
|
compute_mean_leaf_pairwise_distance,
|
|
40
40
|
compute_sackin_index,
|
|
41
|
+
count_hops,
|
|
41
42
|
dump_newick,
|
|
42
43
|
generate_trees,
|
|
43
44
|
get_BD_events,
|
|
@@ -50,12 +51,15 @@ from phylogenie.treesimulator import (
|
|
|
50
51
|
get_FBD_events,
|
|
51
52
|
get_mrca,
|
|
52
53
|
get_mutation_id,
|
|
54
|
+
get_node_ages,
|
|
53
55
|
get_node_depth_levels,
|
|
54
56
|
get_node_depths,
|
|
55
57
|
get_node_height_levels,
|
|
56
58
|
get_node_heights,
|
|
57
59
|
get_node_leaf_counts,
|
|
58
60
|
get_node_state,
|
|
61
|
+
get_node_times,
|
|
62
|
+
get_path,
|
|
59
63
|
load_newick,
|
|
60
64
|
load_nexus,
|
|
61
65
|
set_features,
|
|
@@ -100,6 +104,7 @@ __all__ = [
|
|
|
100
104
|
"Tree",
|
|
101
105
|
"compute_mean_leaf_pairwise_distance",
|
|
102
106
|
"compute_sackin_index",
|
|
107
|
+
"count_hops",
|
|
103
108
|
"dump_newick",
|
|
104
109
|
"generate_trees",
|
|
105
110
|
"get_BD_events",
|
|
@@ -112,12 +117,15 @@ __all__ = [
|
|
|
112
117
|
"get_FBD_events",
|
|
113
118
|
"get_mrca",
|
|
114
119
|
"get_mutation_id",
|
|
120
|
+
"get_node_ages",
|
|
115
121
|
"get_node_depth_levels",
|
|
116
122
|
"get_node_depths",
|
|
117
123
|
"get_node_height_levels",
|
|
118
124
|
"get_node_heights",
|
|
119
125
|
"get_node_leaf_counts",
|
|
120
126
|
"get_node_state",
|
|
127
|
+
"get_node_times",
|
|
128
|
+
"get_path",
|
|
121
129
|
"load_newick",
|
|
122
130
|
"load_nexus",
|
|
123
131
|
"set_features",
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import datetime
|
|
2
|
+
from collections.abc import Mapping
|
|
2
3
|
from dataclasses import dataclass
|
|
3
4
|
from typing import Any, Literal, overload
|
|
4
5
|
|
|
@@ -30,7 +31,7 @@ Color = str | tuple[float, float, float] | tuple[float, float, float, float]
|
|
|
30
31
|
def draw_tree(
|
|
31
32
|
tree: Tree,
|
|
32
33
|
ax: Axes | None = None,
|
|
33
|
-
colors: Color |
|
|
34
|
+
colors: Color | Mapping[Tree, Color] = "black",
|
|
34
35
|
backward_time: bool = False,
|
|
35
36
|
branch_kwargs: dict[str, Any] | None = None,
|
|
36
37
|
sampled_ancestor_kwargs: dict[str, Any] | None = None,
|
|
@@ -44,8 +45,8 @@ def draw_tree(
|
|
|
44
45
|
The phylogenetic tree to draw.
|
|
45
46
|
ax : Axes | None, optional
|
|
46
47
|
The matplotlib Axes to draw on. If None, uses the current Axes.
|
|
47
|
-
colors : Color |
|
|
48
|
-
A single color for all branches or a
|
|
48
|
+
colors : Color | Mapping[Tree, Color], optional
|
|
49
|
+
A single color for all branches or a mapping from each node to a color.
|
|
49
50
|
backward_time : bool, optional
|
|
50
51
|
If True, the x-axis is inverted to represent time going backward.
|
|
51
52
|
branch_kwargs : dict[str, Any] | None, optional
|
|
@@ -67,7 +68,7 @@ def draw_tree(
|
|
|
67
68
|
if "marker" not in sampled_ancestor_kwargs:
|
|
68
69
|
sampled_ancestor_kwargs["marker"] = "o"
|
|
69
70
|
|
|
70
|
-
if not isinstance(colors,
|
|
71
|
+
if not isinstance(colors, Mapping):
|
|
71
72
|
colors = {node: colors for node in tree}
|
|
72
73
|
|
|
73
74
|
xs = (
|
|
@@ -141,7 +142,7 @@ def draw_dated_tree(
|
|
|
141
142
|
tree: Tree,
|
|
142
143
|
calibration_nodes: tuple[CalibrationNode, CalibrationNode],
|
|
143
144
|
ax: Axes | None = None,
|
|
144
|
-
colors: Color |
|
|
145
|
+
colors: Color | Mapping[Tree, Color] = "black",
|
|
145
146
|
branch_kwargs: dict[str, Any] | None = None,
|
|
146
147
|
) -> Axes:
|
|
147
148
|
"""
|
|
@@ -155,8 +156,8 @@ def draw_dated_tree(
|
|
|
155
156
|
Two calibration nodes defining the mapping from depth to date.
|
|
156
157
|
ax : Axes | None, optional
|
|
157
158
|
The matplotlib Axes to draw on. If None, uses the current Axes.
|
|
158
|
-
colors : Color |
|
|
159
|
-
A single color for all branches or a
|
|
159
|
+
colors : Color | Mapping[Tree, Color], optional
|
|
160
|
+
A single color for all branches or a mapping from each node to a color.
|
|
160
161
|
branch_kwargs : dict[str, Any] | None, optional
|
|
161
162
|
Additional keyword arguments to pass to the branch drawing functions.
|
|
162
163
|
|
|
@@ -170,7 +171,7 @@ def draw_dated_tree(
|
|
|
170
171
|
if branch_kwargs is None:
|
|
171
172
|
branch_kwargs = {}
|
|
172
173
|
|
|
173
|
-
if not isinstance(colors,
|
|
174
|
+
if not isinstance(colors, Mapping):
|
|
174
175
|
colors = {node: colors for node in tree}
|
|
175
176
|
|
|
176
177
|
xs = {
|
|
@@ -224,9 +225,9 @@ def _init_colored_tree_categorical(
|
|
|
224
225
|
color_by: str,
|
|
225
226
|
ax: Axes | None = None,
|
|
226
227
|
default_color: Color = "black",
|
|
227
|
-
colormap: str | Colormap = "tab20",
|
|
228
|
+
colormap: str | Mapping[str, Color] | Colormap = "tab20",
|
|
228
229
|
show_legend: bool = True,
|
|
229
|
-
labels:
|
|
230
|
+
labels: Mapping[Any, str] | None = None,
|
|
230
231
|
legend_kwargs: dict[str, Any] | None = None,
|
|
231
232
|
) -> tuple[Axes, dict[Tree, Color]]:
|
|
232
233
|
"""
|
|
@@ -242,11 +243,14 @@ def _init_colored_tree_categorical(
|
|
|
242
243
|
The matplotlib Axes to draw on. If None, uses the current Axes.
|
|
243
244
|
default_color : Color, optional
|
|
244
245
|
The color to use for nodes without the specified metadata.
|
|
245
|
-
colormap : str | Colormap, optional
|
|
246
|
-
The colormap to use for coloring categories.
|
|
246
|
+
colormap : str | Mapping[str, Color] | Colormap, optional
|
|
247
|
+
The colormap to use for coloring categories.
|
|
248
|
+
If a string, it is used to get a matplotlib colormap.
|
|
249
|
+
If a mapping, it maps category values to colors directly.
|
|
250
|
+
Defaults to 'tab20'.
|
|
247
251
|
show_legend : bool, optional
|
|
248
252
|
Whether to display a legend for the categories.
|
|
249
|
-
labels :
|
|
253
|
+
labels : Mapping[Any, str] | None, optional
|
|
250
254
|
A mapping from category values to labels for the legend.
|
|
251
255
|
legend_kwargs : dict[str, Any] | None, optional
|
|
252
256
|
Additional keyword arguments to pass to the legend.
|
|
@@ -259,13 +263,16 @@ def _init_colored_tree_categorical(
|
|
|
259
263
|
if ax is None:
|
|
260
264
|
ax = plt.gca()
|
|
261
265
|
|
|
266
|
+
features = {node: node[color_by] for node in tree if color_by in node.metadata}
|
|
262
267
|
if isinstance(colormap, str):
|
|
263
268
|
colormap = plt.get_cmap(colormap)
|
|
269
|
+
if isinstance(colormap, Colormap):
|
|
270
|
+
feature_colors = {
|
|
271
|
+
f: mcolors.to_hex(colormap(i)) for i, f in enumerate(set(features.values()))
|
|
272
|
+
}
|
|
273
|
+
else:
|
|
274
|
+
feature_colors = colormap
|
|
264
275
|
|
|
265
|
-
features = {node: node[color_by] for node in tree if color_by in node.metadata}
|
|
266
|
-
feature_colors = {
|
|
267
|
-
f: mcolors.to_hex(colormap(i)) for i, f in enumerate(set(features.values()))
|
|
268
|
-
}
|
|
269
276
|
colors = {
|
|
270
277
|
node: feature_colors[features[node]] if node in features else default_color
|
|
271
278
|
for node in tree
|
|
@@ -294,9 +301,9 @@ def draw_colored_tree_categorical(
|
|
|
294
301
|
ax: Axes | None = None,
|
|
295
302
|
backward_time: bool = False,
|
|
296
303
|
default_color: Color = "black",
|
|
297
|
-
colormap: str | Colormap = "tab20",
|
|
304
|
+
colormap: str | Mapping[str, Color] | Colormap = "tab20",
|
|
298
305
|
show_legend: bool = True,
|
|
299
|
-
labels:
|
|
306
|
+
labels: Mapping[Any, str] | None = None,
|
|
300
307
|
legend_kwargs: dict[str, Any] | None = None,
|
|
301
308
|
branch_kwargs: dict[str, Any] | None = None,
|
|
302
309
|
sampled_ancestor_kwargs: dict[str, Any] | None = None,
|
|
@@ -316,11 +323,14 @@ def draw_colored_tree_categorical(
|
|
|
316
323
|
If True, the x-axis is inverted to represent time going backward.
|
|
317
324
|
default_color : Color, optional
|
|
318
325
|
The color to use for nodes without the specified metadata.
|
|
319
|
-
colormap : str | Colormap, optional
|
|
320
|
-
The colormap to use for coloring categories.
|
|
326
|
+
colormap : str | Mapping[str, Color] | Colormap, optional
|
|
327
|
+
The colormap to use for coloring categories.
|
|
328
|
+
If a string, it is used to get a matplotlib colormap.
|
|
329
|
+
If a mapping, it maps category values to colors directly.
|
|
330
|
+
Defaults to 'tab20'.
|
|
321
331
|
show_legend : bool, optional
|
|
322
332
|
Whether to display a legend for the categories.
|
|
323
|
-
labels :
|
|
333
|
+
labels : Mapping[Any, str] | None, optional
|
|
324
334
|
A mapping from category values to labels for the legend.
|
|
325
335
|
legend_kwargs : dict[str, Any] | None, optional
|
|
326
336
|
Additional keyword arguments to pass to the legend.
|
|
@@ -360,9 +370,9 @@ def draw_colored_dated_tree_categorical(
|
|
|
360
370
|
color_by: str,
|
|
361
371
|
ax: Axes | None = None,
|
|
362
372
|
default_color: Color = "black",
|
|
363
|
-
colormap: str | Colormap = "tab20",
|
|
373
|
+
colormap: str | Mapping[str, Color] | Colormap = "tab20",
|
|
364
374
|
show_legend: bool = True,
|
|
365
|
-
labels:
|
|
375
|
+
labels: Mapping[Any, str] | None = None,
|
|
366
376
|
legend_kwargs: dict[str, Any] | None = None,
|
|
367
377
|
branch_kwargs: dict[str, Any] | None = None,
|
|
368
378
|
) -> Axes:
|
|
@@ -381,11 +391,14 @@ def draw_colored_dated_tree_categorical(
|
|
|
381
391
|
The matplotlib Axes to draw on. If None, uses the current Axes.
|
|
382
392
|
default_color : Color, optional
|
|
383
393
|
The color to use for nodes without the specified metadata.
|
|
384
|
-
colormap : str | Colormap, optional
|
|
385
|
-
The colormap to use for coloring categories.
|
|
394
|
+
colormap : str | Mapping[str, Color] | Colormap, optional
|
|
395
|
+
The colormap to use for coloring categories.
|
|
396
|
+
If a string, it is used to get a matplotlib colormap.
|
|
397
|
+
If a mapping, it maps category values to colors directly.
|
|
398
|
+
Defaults to 'tab20'.
|
|
386
399
|
show_legend : bool, optional
|
|
387
400
|
Whether to display a legend for the categories.
|
|
388
|
-
labels :
|
|
401
|
+
labels : Mapping[Any, str] | None, optional
|
|
389
402
|
A mapping from category values to labels for the legend.
|
|
390
403
|
legend_kwargs : dict[str, Any] | None, optional
|
|
391
404
|
Additional keyword arguments to pass to the legend.
|
|
@@ -19,18 +19,22 @@ from phylogenie.skyline import (
|
|
|
19
19
|
from phylogenie.treesimulator import EventType, Mutation
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def
|
|
22
|
+
def eval_expression(
|
|
23
|
+
expression: str, data: dict[str, Any], extra_globals: dict[str, Any] | None = None
|
|
24
|
+
) -> Any:
|
|
25
|
+
if extra_globals is None:
|
|
26
|
+
extra_globals = {}
|
|
23
27
|
return np.array(
|
|
24
28
|
eval(
|
|
25
29
|
expression,
|
|
26
|
-
{"np": np, **{k: np.array(v) for k, v in data.items()}},
|
|
30
|
+
{"np": np, **{k: np.array(v) for k, v in data.items()}, **extra_globals},
|
|
27
31
|
)
|
|
28
32
|
).tolist()
|
|
29
33
|
|
|
30
34
|
|
|
31
35
|
def integer(x: cfg.Integer, data: dict[str, Any]) -> int:
|
|
32
36
|
if isinstance(x, str):
|
|
33
|
-
e =
|
|
37
|
+
e = eval_expression(x, data)
|
|
34
38
|
if isinstance(e, int):
|
|
35
39
|
return e
|
|
36
40
|
raise ValueError(
|
|
@@ -41,7 +45,7 @@ def integer(x: cfg.Integer, data: dict[str, Any]) -> int:
|
|
|
41
45
|
|
|
42
46
|
def scalar(x: cfg.Scalar, data: dict[str, Any]) -> pgt.Scalar:
|
|
43
47
|
if isinstance(x, str):
|
|
44
|
-
e =
|
|
48
|
+
e = eval_expression(x, data)
|
|
45
49
|
if isinstance(e, pgt.Scalar):
|
|
46
50
|
return e
|
|
47
51
|
raise ValueError(
|
|
@@ -54,13 +58,13 @@ def string(s: Any, data: dict[str, Any]) -> str:
|
|
|
54
58
|
if not isinstance(s, str):
|
|
55
59
|
return str(s)
|
|
56
60
|
return re.sub(
|
|
57
|
-
r"\{([^{}]+)\}", lambda match: str(
|
|
61
|
+
r"\{([^{}]+)\}", lambda match: str(eval_expression(match.group(1), data)), s
|
|
58
62
|
) # Match content inside curly braces
|
|
59
63
|
|
|
60
64
|
|
|
61
65
|
def many_scalars(x: cfg.ManyScalars, data: dict[str, Any]) -> pgt.ManyScalars:
|
|
62
66
|
if isinstance(x, str):
|
|
63
|
-
e =
|
|
67
|
+
e = eval_expression(x, data)
|
|
64
68
|
if tg.is_many_scalars(e):
|
|
65
69
|
return e
|
|
66
70
|
raise ValueError(
|
|
@@ -73,7 +77,7 @@ def one_or_many_scalars(
|
|
|
73
77
|
x: cfg.OneOrManyScalars, data: dict[str, Any]
|
|
74
78
|
) -> pgt.OneOrManyScalars:
|
|
75
79
|
if isinstance(x, str):
|
|
76
|
-
e =
|
|
80
|
+
e = eval_expression(x, data)
|
|
77
81
|
if tg.is_one_or_many_scalars(e):
|
|
78
82
|
return e
|
|
79
83
|
raise ValueError(
|
|
@@ -99,7 +103,7 @@ def skyline_vector(
|
|
|
99
103
|
x: cfg.SkylineVector, data: dict[str, Any]
|
|
100
104
|
) -> SkylineVectorCoercible:
|
|
101
105
|
if isinstance(x, str):
|
|
102
|
-
e =
|
|
106
|
+
e = eval_expression(x, data)
|
|
103
107
|
if tg.is_one_or_many_scalars(e):
|
|
104
108
|
return e
|
|
105
109
|
raise ValueError(
|
|
@@ -114,7 +118,7 @@ def skyline_vector(
|
|
|
114
118
|
|
|
115
119
|
change_times = many_scalars(x.change_times, data)
|
|
116
120
|
if isinstance(x.value, str):
|
|
117
|
-
e =
|
|
121
|
+
e = eval_expression(x.value, data)
|
|
118
122
|
if tg.is_many_one_or_many_scalars(e):
|
|
119
123
|
value = e
|
|
120
124
|
else:
|
|
@@ -142,7 +146,7 @@ def one_or_many_2D_scalars(
|
|
|
142
146
|
x: cfg.OneOrMany2DScalars, data: dict[str, Any]
|
|
143
147
|
) -> pgt.OneOrMany2DScalars:
|
|
144
148
|
if isinstance(x, str):
|
|
145
|
-
e =
|
|
149
|
+
e = eval_expression(x, data)
|
|
146
150
|
if tg.is_one_or_many_2D_scalars(e):
|
|
147
151
|
return e
|
|
148
152
|
raise ValueError(
|
|
@@ -160,7 +164,7 @@ def skyline_matrix(
|
|
|
160
164
|
return None
|
|
161
165
|
|
|
162
166
|
if isinstance(x, str):
|
|
163
|
-
e =
|
|
167
|
+
e = eval_expression(x, data)
|
|
164
168
|
if tg.is_one_or_many_2D_scalars(e):
|
|
165
169
|
return e
|
|
166
170
|
raise ValueError(
|
|
@@ -175,7 +179,7 @@ def skyline_matrix(
|
|
|
175
179
|
|
|
176
180
|
change_times = many_scalars(x.change_times, data)
|
|
177
181
|
if isinstance(x.value, str):
|
|
178
|
-
e =
|
|
182
|
+
e = eval_expression(x.value, data)
|
|
179
183
|
if tg.is_many_one_or_many_2D_scalars(e):
|
|
180
184
|
value = e
|
|
181
185
|
else:
|
|
@@ -213,7 +217,7 @@ def distribution(x: cfg.Distribution, data: dict[str, Any]) -> cfg.Distribution:
|
|
|
213
217
|
args = x.args
|
|
214
218
|
for arg_name, arg_value in args.items():
|
|
215
219
|
if isinstance(arg_value, str):
|
|
216
|
-
args[arg_name] =
|
|
220
|
+
args[arg_name] = eval_expression(arg_value, data)
|
|
217
221
|
return cfg.Distribution(type=x.type, **args)
|
|
218
222
|
|
|
219
223
|
|
|
@@ -12,6 +12,7 @@ from phylogenie.generators.configs import Distribution
|
|
|
12
12
|
from phylogenie.generators.dataset import DatasetGenerator, DataType
|
|
13
13
|
from phylogenie.generators.factories import (
|
|
14
14
|
data,
|
|
15
|
+
eval_expression,
|
|
15
16
|
integer,
|
|
16
17
|
mutations,
|
|
17
18
|
scalar,
|
|
@@ -57,6 +58,7 @@ class TreeDatasetGenerator(DatasetGenerator):
|
|
|
57
58
|
timeout: float = np.inf
|
|
58
59
|
node_features: list[Feature] | None = None
|
|
59
60
|
acceptance_criterion: str | None = None
|
|
61
|
+
logs: dict[str, str] | None = None
|
|
60
62
|
|
|
61
63
|
@abstractmethod
|
|
62
64
|
def _get_events(self, data: dict[str, Any]) -> list[Event]: ...
|
|
@@ -77,10 +79,21 @@ class TreeDatasetGenerator(DatasetGenerator):
|
|
|
77
79
|
acceptance_criterion: None | Callable[[Tree], bool] = (
|
|
78
80
|
None
|
|
79
81
|
if self.acceptance_criterion is None
|
|
80
|
-
else lambda tree:
|
|
81
|
-
self.acceptance_criterion,
|
|
82
|
+
else lambda tree: eval_expression(
|
|
83
|
+
self.acceptance_criterion, # pyright: ignore
|
|
84
|
+
data,
|
|
85
|
+
{"tree": tree},
|
|
82
86
|
)
|
|
83
87
|
)
|
|
88
|
+
logs: None | dict[str, Callable[[Tree], Any]] = (
|
|
89
|
+
None
|
|
90
|
+
if self.logs is None
|
|
91
|
+
else {
|
|
92
|
+
key: lambda tree, expr=expr: eval_expression(expr, data, {"tree": tree})
|
|
93
|
+
for key, expr in self.logs.items()
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
|
|
84
97
|
return simulate_tree(
|
|
85
98
|
events=events,
|
|
86
99
|
n_tips=None if self.n_tips is None else integer(self.n_tips, data),
|
|
@@ -92,6 +105,7 @@ class TreeDatasetGenerator(DatasetGenerator):
|
|
|
92
105
|
seed=seed,
|
|
93
106
|
timeout=self.timeout,
|
|
94
107
|
acceptance_criterion=acceptance_criterion,
|
|
108
|
+
logs=logs,
|
|
95
109
|
)
|
|
96
110
|
|
|
97
111
|
def generate_one(
|
|
@@ -111,7 +125,7 @@ class TreeDatasetGenerator(DatasetGenerator):
|
|
|
111
125
|
dump_newick(tree, f"{filename}.nwk")
|
|
112
126
|
break
|
|
113
127
|
except TimeoutError:
|
|
114
|
-
print("Simulation timed out
|
|
128
|
+
print("Simulation timed out. Retrying with different parameters...")
|
|
115
129
|
return d | metadata
|
|
116
130
|
|
|
117
131
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from collections.abc import Iterator
|
|
1
|
+
from collections.abc import Iterable, Iterator
|
|
2
2
|
from dataclasses import dataclass
|
|
3
3
|
from datetime import date
|
|
4
4
|
|
|
@@ -11,16 +11,23 @@ class Sequence:
|
|
|
11
11
|
chars: str
|
|
12
12
|
time: float | date | None = None
|
|
13
13
|
|
|
14
|
+
def __len__(self) -> int:
|
|
15
|
+
return len(self.chars)
|
|
16
|
+
|
|
14
17
|
|
|
15
18
|
class MSA:
|
|
16
|
-
def __init__(self, sequences:
|
|
17
|
-
self.
|
|
18
|
-
lengths = {len(sequence
|
|
19
|
+
def __init__(self, sequences: Iterable[Sequence]):
|
|
20
|
+
self._sequences = sequences
|
|
21
|
+
lengths = {len(sequence) for sequence in sequences}
|
|
19
22
|
if len(lengths) > 1:
|
|
20
23
|
raise ValueError(
|
|
21
24
|
f"All sequences in the alignment must have the same length (got lengths: {lengths})"
|
|
22
25
|
)
|
|
23
26
|
|
|
27
|
+
@property
|
|
28
|
+
def sequences(self) -> tuple[Sequence, ...]:
|
|
29
|
+
return tuple(self._sequences)
|
|
30
|
+
|
|
24
31
|
@property
|
|
25
32
|
def ids(self) -> list[str]:
|
|
26
33
|
return [sequence.id for sequence in self.sequences]
|
|
@@ -25,6 +25,7 @@ from phylogenie.treesimulator.tree import Tree
|
|
|
25
25
|
from phylogenie.treesimulator.utils import (
|
|
26
26
|
compute_mean_leaf_pairwise_distance,
|
|
27
27
|
compute_sackin_index,
|
|
28
|
+
count_hops,
|
|
28
29
|
get_distance,
|
|
29
30
|
get_mrca,
|
|
30
31
|
get_node_ages,
|
|
@@ -66,6 +67,7 @@ __all__ = [
|
|
|
66
67
|
"Tree",
|
|
67
68
|
"compute_mean_leaf_pairwise_distance",
|
|
68
69
|
"compute_sackin_index",
|
|
70
|
+
"count_hops",
|
|
69
71
|
"get_distance",
|
|
70
72
|
"get_mrca",
|
|
71
73
|
"get_node_ages",
|
|
@@ -25,6 +25,7 @@ def simulate_tree(
|
|
|
25
25
|
seed: int | None = None,
|
|
26
26
|
timeout: float = np.inf,
|
|
27
27
|
acceptance_criterion: Callable[[Tree], bool] | None = None,
|
|
28
|
+
logs: dict[str, Callable[[Tree], Any]] | None = None,
|
|
28
29
|
) -> tuple[Tree, dict[str, Any]]:
|
|
29
30
|
if (max_time != np.inf) == (n_tips is not None):
|
|
30
31
|
raise ValueError("Exactly one of max_time or n_tips must be specified.")
|
|
@@ -85,7 +86,13 @@ def simulate_tree(
|
|
|
85
86
|
model.sample(individual, current_time, True)
|
|
86
87
|
|
|
87
88
|
tree = model.get_sampled_tree()
|
|
88
|
-
|
|
89
|
+
|
|
90
|
+
if acceptance_criterion is not None and not acceptance_criterion(tree):
|
|
91
|
+
continue
|
|
92
|
+
|
|
93
|
+
if logs is not None:
|
|
94
|
+
for key, func in logs.items():
|
|
95
|
+
metadata[key] = func(tree)
|
|
89
96
|
return (tree, metadata)
|
|
90
97
|
|
|
91
98
|
|
|
@@ -102,6 +109,7 @@ def generate_trees(
|
|
|
102
109
|
n_jobs: int = -1,
|
|
103
110
|
timeout: float = np.inf,
|
|
104
111
|
acceptance_criterion: Callable[[Tree], bool] | None = None,
|
|
112
|
+
logs: dict[str, Callable[[Tree], Any]] | None = None,
|
|
105
113
|
) -> pd.DataFrame:
|
|
106
114
|
if isinstance(output_dir, str):
|
|
107
115
|
output_dir = Path(output_dir)
|
|
@@ -121,6 +129,7 @@ def generate_trees(
|
|
|
121
129
|
seed=seed,
|
|
122
130
|
timeout=timeout,
|
|
123
131
|
acceptance_criterion=acceptance_criterion,
|
|
132
|
+
logs=logs,
|
|
124
133
|
)
|
|
125
134
|
metadata["file_id"] = i
|
|
126
135
|
if node_features is not None:
|
|
@@ -128,7 +137,7 @@ def generate_trees(
|
|
|
128
137
|
dump_newick(tree, output_dir / f"{i}.nwk")
|
|
129
138
|
return metadata
|
|
130
139
|
except TimeoutError:
|
|
131
|
-
print("Simulation timed out
|
|
140
|
+
print("Simulation timed out. Retrying with a different seed...")
|
|
132
141
|
seed += 1
|
|
133
142
|
|
|
134
143
|
rng = default_rng(seed)
|
|
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.11 → phylogenie-3.1.18}/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
|
|
File without changes
|
|
File without changes
|