tree-annotated-plot 0.3.0__py3-none-any.whl → 0.4.0__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.
- tree_annotated_plot/_config.py +12 -2
- tree_annotated_plot/_plot.py +36 -14
- {tree_annotated_plot-0.3.0.dist-info → tree_annotated_plot-0.4.0.dist-info}/METADATA +3 -3
- tree_annotated_plot-0.4.0.dist-info/RECORD +11 -0
- {tree_annotated_plot-0.3.0.dist-info → tree_annotated_plot-0.4.0.dist-info}/WHEEL +1 -1
- tree_annotated_plot-0.3.0.dist-info/RECORD +0 -11
- {tree_annotated_plot-0.3.0.dist-info → tree_annotated_plot-0.4.0.dist-info}/entry_points.txt +0 -0
- {tree_annotated_plot-0.3.0.dist-info → tree_annotated_plot-0.4.0.dist-info}/licenses/LICENSE +0 -0
tree_annotated_plot/_config.py
CHANGED
|
@@ -68,6 +68,15 @@ class PlotConfig:
|
|
|
68
68
|
"(x-encoded).",
|
|
69
69
|
] = None
|
|
70
70
|
|
|
71
|
+
spacing: Annotated[
|
|
72
|
+
int,
|
|
73
|
+
"Pixels of blank space between the tree panel and the chart panel. "
|
|
74
|
+
"Default 0, which butts the two together. Distinct from "
|
|
75
|
+
"`shift_tree_loc`, which moves the tree within its own panel by "
|
|
76
|
+
"resizing the label strip; `spacing` sets the gap between the panels "
|
|
77
|
+
"and applies whether or not `connect_leader_to_label` is on.",
|
|
78
|
+
] = 0
|
|
79
|
+
|
|
71
80
|
tree_line_width: Annotated[
|
|
72
81
|
float,
|
|
73
82
|
"Stroke width (px) for the tree's branch lines. Default 2.",
|
|
@@ -155,8 +164,9 @@ class PlotConfig:
|
|
|
155
164
|
shift_tree_loc: Annotated[
|
|
156
165
|
int,
|
|
157
166
|
"Pixels by which to shift the tree toward (positive) or away from "
|
|
158
|
-
"(negative) the chart
|
|
159
|
-
"connect_leader_to_label is off
|
|
167
|
+
"(negative) the chart, by resizing the label strip inside the tree "
|
|
168
|
+
"panel. Default 0. Has no effect when connect_leader_to_label is off; "
|
|
169
|
+
"to set the gap between the tree and chart panels use `spacing`.",
|
|
160
170
|
] = 0
|
|
161
171
|
|
|
162
172
|
color_tree_by: Annotated[
|
tree_annotated_plot/_plot.py
CHANGED
|
@@ -49,6 +49,7 @@ def plot(
|
|
|
49
49
|
branch_length: Literal["div", "num_date"],
|
|
50
50
|
tree_size: int = 100,
|
|
51
51
|
tree_location: TreeLocation | None = None,
|
|
52
|
+
spacing: int = 0,
|
|
52
53
|
tree_line_width: float = 2.0,
|
|
53
54
|
tree_node_size: float = 45,
|
|
54
55
|
leader_line_width: float = 1.0,
|
|
@@ -77,6 +78,7 @@ def plot(
|
|
|
77
78
|
branch_length=branch_length,
|
|
78
79
|
tree_size=tree_size,
|
|
79
80
|
tree_location=tree_location,
|
|
81
|
+
spacing=spacing,
|
|
80
82
|
tree_line_width=tree_line_width,
|
|
81
83
|
tree_node_size=tree_node_size,
|
|
82
84
|
leader_line_width=leader_line_width,
|
|
@@ -281,7 +283,10 @@ def _build(
|
|
|
281
283
|
hoisted_config, hoisted_other = _pop_toplevel_only_attrs(new_chart)
|
|
282
284
|
|
|
283
285
|
combined = _concat_for_location(
|
|
284
|
-
tree_chart=tree_chart,
|
|
286
|
+
tree_chart=tree_chart,
|
|
287
|
+
user_chart=new_chart,
|
|
288
|
+
location=location,
|
|
289
|
+
spacing=config.spacing,
|
|
285
290
|
)
|
|
286
291
|
_apply_combined_config(combined, hoisted_config)
|
|
287
292
|
for k, v in hoisted_other.items():
|
|
@@ -320,6 +325,7 @@ def _concat_for_location(
|
|
|
320
325
|
tree_chart: alt.TopLevelMixin,
|
|
321
326
|
user_chart: alt.TopLevelMixin,
|
|
322
327
|
location: TreeLocation,
|
|
328
|
+
spacing: int,
|
|
323
329
|
) -> alt.HConcatChart | alt.VConcatChart:
|
|
324
330
|
"""Concat tree and chart in the order implied by the tree's location.
|
|
325
331
|
|
|
@@ -333,19 +339,19 @@ def _concat_for_location(
|
|
|
333
339
|
user-chart marks whose color values aren't in the tree's domain.
|
|
334
340
|
"""
|
|
335
341
|
if location == "left":
|
|
336
|
-
return alt.hconcat(tree_chart, user_chart, spacing=
|
|
342
|
+
return alt.hconcat(tree_chart, user_chart, spacing=spacing).resolve_scale(
|
|
337
343
|
y="independent", color="independent"
|
|
338
344
|
)
|
|
339
345
|
if location == "right":
|
|
340
|
-
return alt.hconcat(user_chart, tree_chart, spacing=
|
|
346
|
+
return alt.hconcat(user_chart, tree_chart, spacing=spacing).resolve_scale(
|
|
341
347
|
y="independent", color="independent"
|
|
342
348
|
)
|
|
343
349
|
if location == "top":
|
|
344
|
-
return alt.vconcat(tree_chart, user_chart, spacing=
|
|
350
|
+
return alt.vconcat(tree_chart, user_chart, spacing=spacing).resolve_scale(
|
|
345
351
|
x="independent", color="independent"
|
|
346
352
|
)
|
|
347
353
|
if location == "bottom":
|
|
348
|
-
return alt.vconcat(user_chart, tree_chart, spacing=
|
|
354
|
+
return alt.vconcat(user_chart, tree_chart, spacing=spacing).resolve_scale(
|
|
349
355
|
x="independent", color="independent"
|
|
350
356
|
)
|
|
351
357
|
raise ValueError(f"unreachable: tree_location={location!r}")
|
|
@@ -1475,6 +1481,11 @@ def _build_scale_bar_layer(
|
|
|
1475
1481
|
|
|
1476
1482
|
_LABEL_PAD_PX_MIN = 4
|
|
1477
1483
|
_LABEL_PAD_RATIO = 0.4 # `LABEL_PAD_PX = max(MIN, font_size * RATIO)`
|
|
1484
|
+
# Gap between the labels and the chart, kept separate from the tree-facing pad
|
|
1485
|
+
# above because it clears the chart's frame rather than the deepest tip, and so
|
|
1486
|
+
# wants a small fixed clearance rather than the pad's larger, faster-growing one.
|
|
1487
|
+
_LABEL_CHART_GAP_PX_MIN = 3
|
|
1488
|
+
_LABEL_CHART_GAP_RATIO = 0.2 # `LABEL_CHART_GAP_PX = max(MIN, font_size * RATIO)`
|
|
1478
1489
|
_LABEL_CHAR_PX_RATIO = 0.6 # rough proportional sans-serif glyph-width estimate
|
|
1479
1490
|
_LABEL_HALO_RATIO = 0.6 # white-halo strokeWidth as a fraction of font_size
|
|
1480
1491
|
|
|
@@ -1614,9 +1625,15 @@ def _build_tree_chart(
|
|
|
1614
1625
|
max_name_len = max((len(n) for n in names), default=0)
|
|
1615
1626
|
char_px = strain_label_font_size * _LABEL_CHAR_PX_RATIO
|
|
1616
1627
|
label_pad_px = max(_LABEL_PAD_PX_MIN, strain_label_font_size * _LABEL_PAD_RATIO)
|
|
1628
|
+
chart_gap_px = max(
|
|
1629
|
+
_LABEL_CHART_GAP_PX_MIN, strain_label_font_size * _LABEL_CHART_GAP_RATIO
|
|
1630
|
+
)
|
|
1617
1631
|
# Strip needs to fit the longest label plus `halo_px / 2` of halo
|
|
1618
|
-
# extension on the leader-facing side,
|
|
1619
|
-
|
|
1632
|
+
# extension on the leader-facing side, a pad between the tree and the
|
|
1633
|
+
# text, and a smaller gap between the text and the chart.
|
|
1634
|
+
label_pixel_width = (
|
|
1635
|
+
label_pad_px + chart_gap_px + max_name_len * char_px + halo_px / 2
|
|
1636
|
+
)
|
|
1620
1637
|
strip_pixel_width = label_pixel_width - shift_tree_loc
|
|
1621
1638
|
if strip_pixel_width <= 0:
|
|
1622
1639
|
raise ValueError(
|
|
@@ -1629,9 +1646,13 @@ def _build_tree_chart(
|
|
|
1629
1646
|
per_pixel = branch_span / tree_size if tree_size else 0.0
|
|
1630
1647
|
extra_branch_units = strip_pixel_width * per_pixel
|
|
1631
1648
|
chart_edge_branch = branch_max + extra_branch_units
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1649
|
+
# Anchor the labels `chart_gap_px` *inside* the chart-facing edge rather
|
|
1650
|
+
# than on it, so the text does not run up against the chart's frame. The
|
|
1651
|
+
# leaders stop at the same place, where the text begins.
|
|
1652
|
+
label_anchor_branch = chart_edge_branch - chart_gap_px * per_pixel
|
|
1653
|
+
tips_df = tips_df.assign(x_label=label_anchor_branch)
|
|
1654
|
+
leader_df = tips_df[tips_df["x"] < label_anchor_branch].assign(
|
|
1655
|
+
x2=label_anchor_branch
|
|
1635
1656
|
)
|
|
1636
1657
|
extended_tree_size = tree_size + strip_pixel_width
|
|
1637
1658
|
else:
|
|
@@ -1680,9 +1701,9 @@ def _build_tree_chart(
|
|
|
1680
1701
|
# When connect_leader_to_label is on, the branch domain is extended
|
|
1681
1702
|
# past `branch_max` to `chart_edge_branch` so the label strip has
|
|
1682
1703
|
# data-units to occupy; tips at `branch_max` still sit at pixel
|
|
1683
|
-
# `tree_size` on the panel. Each label's chart-facing edge
|
|
1684
|
-
#
|
|
1685
|
-
# tree on the left, left for tree on the right).
|
|
1704
|
+
# `tree_size` on the panel. Each label's chart-facing edge sits
|
|
1705
|
+
# `chart_gap_px` inside `chart_edge_branch`, aligned outward (right
|
|
1706
|
+
# for tree on the left, left for tree on the right).
|
|
1686
1707
|
if tree_location == "left":
|
|
1687
1708
|
branch_domain = [branch_min, chart_edge_branch]
|
|
1688
1709
|
text_align = "right"
|
|
@@ -1783,7 +1804,8 @@ def _build_tree_chart(
|
|
|
1783
1804
|
# strip at bottom, opposite the chart above).
|
|
1784
1805
|
# tree_location="bottom" → root at bottom → branch_max at top (label
|
|
1785
1806
|
# strip at top, opposite the chart below).
|
|
1786
|
-
# Each label's chart-facing edge
|
|
1807
|
+
# Each label's chart-facing edge sits `chart_gap_px` inside
|
|
1808
|
+
# `chart_edge_branch`.
|
|
1787
1809
|
# The text mark is rotated 270° (reads bottom-to-top), which maps
|
|
1788
1810
|
# pre-rotation `align="right"` to a top anchor (text extends down)
|
|
1789
1811
|
# and `align="left"` to a bottom anchor (text extends up). For tree
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
2
|
Name: tree-annotated-plot
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Annotate the axis of an Altair / Vega-Lite plot with a phylogenetic tree.
|
|
5
5
|
Project-URL: Documentation, https://jbloomlab.github.io/tree-annotated-plot/
|
|
6
6
|
Project-URL: Homepage, https://github.com/jbloomlab/tree-annotated-plot
|
|
@@ -43,7 +43,7 @@ Requires-Dist: vl-convert-python>=1.9
|
|
|
43
43
|
Provides-Extra: dev
|
|
44
44
|
Requires-Dist: black>=24; extra == 'dev'
|
|
45
45
|
Requires-Dist: pytest>=8; extra == 'dev'
|
|
46
|
-
Requires-Dist: ruff
|
|
46
|
+
Requires-Dist: ruff<0.17,>=0.16; extra == 'dev'
|
|
47
47
|
Provides-Extra: docs
|
|
48
48
|
Requires-Dist: mkdocs-click>=0.8; extra == 'docs'
|
|
49
49
|
Requires-Dist: mkdocs-material>=9.5; extra == 'docs'
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
tree_annotated_plot/__init__.py,sha256=R39gjVnl3K2VjLba6zwtwPGADFmtNOE2UYNk1y9_z6k,351
|
|
2
|
+
tree_annotated_plot/_color.py,sha256=nOZp-KIPy6s-6gBkzW36oHrwDk_SmvVNsMiIJ-dY1Io,26519
|
|
3
|
+
tree_annotated_plot/_config.py,sha256=0ib600JaMpMz4ZjFYtvFu3nhUhliJRexTJcFpDKVOD0,13171
|
|
4
|
+
tree_annotated_plot/_plot.py,sha256=pqhR9PgQUML2-taP_k1FEidpIdBgJ6tulMEpFJbD8WI,77969
|
|
5
|
+
tree_annotated_plot/_tree.py,sha256=Bj-ABt8aooSwV7wAVTbwFGMmCnTPGOKweUWAdfb7aEI,13563
|
|
6
|
+
tree_annotated_plot/cli.py,sha256=OG6Qmzk5BaHUNrfOopX20FbzBN2ahr_SBxHpaCk6Z5c,9848
|
|
7
|
+
tree_annotated_plot-0.4.0.dist-info/METADATA,sha256=JQNY2-mmZIQA7TjABRX_YkvoZXxqix-Ixs5n23EQ1FY,11462
|
|
8
|
+
tree_annotated_plot-0.4.0.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
9
|
+
tree_annotated_plot-0.4.0.dist-info/entry_points.txt,sha256=K7edTocRbwmtM2OeZmCy3DLjmY3MR-q2EJmQQq4rj0E,69
|
|
10
|
+
tree_annotated_plot-0.4.0.dist-info/licenses/LICENSE,sha256=UIp30ue1HZit7tMmSK0SS3swJBqOcLLnLJn5LY5YdNE,1036
|
|
11
|
+
tree_annotated_plot-0.4.0.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
tree_annotated_plot/__init__.py,sha256=R39gjVnl3K2VjLba6zwtwPGADFmtNOE2UYNk1y9_z6k,351
|
|
2
|
-
tree_annotated_plot/_color.py,sha256=nOZp-KIPy6s-6gBkzW36oHrwDk_SmvVNsMiIJ-dY1Io,26519
|
|
3
|
-
tree_annotated_plot/_config.py,sha256=Xs9XfuPAaIhGuffYbsDOfcJW_f4etpgPW4ombHNuIAg,12630
|
|
4
|
-
tree_annotated_plot/_plot.py,sha256=a-sxcZ83Sp-bc0swwisOlvhV7L6bhJQWeh5kppANMX0,76901
|
|
5
|
-
tree_annotated_plot/_tree.py,sha256=Bj-ABt8aooSwV7wAVTbwFGMmCnTPGOKweUWAdfb7aEI,13563
|
|
6
|
-
tree_annotated_plot/cli.py,sha256=OG6Qmzk5BaHUNrfOopX20FbzBN2ahr_SBxHpaCk6Z5c,9848
|
|
7
|
-
tree_annotated_plot-0.3.0.dist-info/METADATA,sha256=oQGwnxJxdq3g_fx_gfn6mjsskj0RHpBcMw2pGcJNZPo,11455
|
|
8
|
-
tree_annotated_plot-0.3.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
9
|
-
tree_annotated_plot-0.3.0.dist-info/entry_points.txt,sha256=K7edTocRbwmtM2OeZmCy3DLjmY3MR-q2EJmQQq4rj0E,69
|
|
10
|
-
tree_annotated_plot-0.3.0.dist-info/licenses/LICENSE,sha256=UIp30ue1HZit7tMmSK0SS3swJBqOcLLnLJn5LY5YdNE,1036
|
|
11
|
-
tree_annotated_plot-0.3.0.dist-info/RECORD,,
|
{tree_annotated_plot-0.3.0.dist-info → tree_annotated_plot-0.4.0.dist-info}/entry_points.txt
RENAMED
|
File without changes
|
{tree_annotated_plot-0.3.0.dist-info → tree_annotated_plot-0.4.0.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|