iplotx 0.6.4__py3-none-any.whl → 0.6.6__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.
- iplotx/edge/__init__.py +5 -0
- iplotx/ingest/providers/network/networkx.py +7 -1
- iplotx/ingest/typing.py +9 -6
- iplotx/network.py +20 -12
- iplotx/plotting.py +16 -11
- iplotx/tree.py +7 -6
- iplotx/utils/matplotlib.py +32 -6
- iplotx/version.py +1 -1
- iplotx/vertex.py +6 -3
- {iplotx-0.6.4.dist-info → iplotx-0.6.6.dist-info}/METADATA +1 -1
- {iplotx-0.6.4.dist-info → iplotx-0.6.6.dist-info}/RECORD +12 -12
- {iplotx-0.6.4.dist-info → iplotx-0.6.6.dist-info}/WHEEL +0 -0
iplotx/edge/__init__.py
CHANGED
|
@@ -131,6 +131,9 @@ class EdgeCollection(mpl.collections.PatchCollection):
|
|
|
131
131
|
self._style["split"],
|
|
132
132
|
)
|
|
133
133
|
|
|
134
|
+
zorder = self._style.get("zorder", 2)
|
|
135
|
+
self.set_zorder(zorder)
|
|
136
|
+
|
|
134
137
|
def _add_subedges(
|
|
135
138
|
self,
|
|
136
139
|
nedges,
|
|
@@ -357,6 +360,8 @@ class EdgeCollection(mpl.collections.PatchCollection):
|
|
|
357
360
|
waypoints = edge_stylei.get("waypoints", "none")
|
|
358
361
|
if waypoints is False or waypoints is np.False_:
|
|
359
362
|
waypoints = "none"
|
|
363
|
+
elif isinstance(waypoints, (list, tuple)) and len(waypoints) == 0:
|
|
364
|
+
waypoints = "none"
|
|
360
365
|
elif waypoints is True or waypoints is np.True_:
|
|
361
366
|
raise ValueError(
|
|
362
367
|
"Could not determine automatically type of edge waypoints.",
|
|
@@ -101,7 +101,13 @@ class NetworkXDataProvider(NetworkDataProvider):
|
|
|
101
101
|
else:
|
|
102
102
|
if len(edge_labels) != len(edge_df):
|
|
103
103
|
raise ValueError("Edge labels must be the same length as the number of edges.")
|
|
104
|
-
|
|
104
|
+
if isinstance(edge_labels, dict):
|
|
105
|
+
edge_labels = pd.Series(edge_labels)
|
|
106
|
+
edge_df["label"] = edge_labels.loc[
|
|
107
|
+
edge_df.set_index(["_ipx_source", "_ipx_target"]).index
|
|
108
|
+
].values
|
|
109
|
+
else:
|
|
110
|
+
edge_df["label"] = edge_labels
|
|
105
111
|
|
|
106
112
|
network_data = {
|
|
107
113
|
"vertex_df": vertex_df,
|
iplotx/ingest/typing.py
CHANGED
|
@@ -138,11 +138,13 @@ class TreeDataProvider(Protocol):
|
|
|
138
138
|
|
|
139
139
|
Note: This is a default implemntation that can be overridden by the provider.
|
|
140
140
|
"""
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
141
|
+
if hasattr(self.tree, "root"):
|
|
142
|
+
root_attr = self.tree.root
|
|
143
|
+
if callable(root_attr):
|
|
144
|
+
return root_attr()
|
|
145
|
+
else:
|
|
146
|
+
return root_attr
|
|
147
|
+
return self.tree.get_root()
|
|
146
148
|
|
|
147
149
|
def get_leaves(self) -> Sequence[Any]:
|
|
148
150
|
"""Get the tree leaves/tips in a provider-specific data structure.
|
|
@@ -311,11 +313,12 @@ class TreeDataProvider(Protocol):
|
|
|
311
313
|
leaf_name_attrs = ("name",)
|
|
312
314
|
|
|
313
315
|
# Add edge_df
|
|
314
|
-
edge_data = {"_ipx_source": [], "_ipx_target": []}
|
|
316
|
+
edge_data = {"_ipx_source": [], "_ipx_target": [], "branch_length": []}
|
|
315
317
|
for node in self.preorder():
|
|
316
318
|
for child in self.get_children(node):
|
|
317
319
|
edge_data["_ipx_source"].append(node)
|
|
318
320
|
edge_data["_ipx_target"].append(child)
|
|
321
|
+
edge_data["branch_length"].append(self.get_branch_length(child))
|
|
319
322
|
edge_df = pd.DataFrame(edge_data)
|
|
320
323
|
tree_data["edge_df"] = edge_df
|
|
321
324
|
|
iplotx/network.py
CHANGED
|
@@ -140,7 +140,10 @@ class NetworkArtist(mpl.artist.Artist):
|
|
|
140
140
|
return self
|
|
141
141
|
|
|
142
142
|
def get_children(self):
|
|
143
|
-
|
|
143
|
+
if hasattr(self, "_edges"):
|
|
144
|
+
return (self._vertices, self._edges)
|
|
145
|
+
else:
|
|
146
|
+
return (self._vertices,)
|
|
144
147
|
|
|
145
148
|
def set_figure(self, fig):
|
|
146
149
|
super().set_figure(fig)
|
|
@@ -184,12 +187,14 @@ class NetworkArtist(mpl.artist.Artist):
|
|
|
184
187
|
if len(layout) == 0:
|
|
185
188
|
return mpl.transforms.Bbox([[0, 0], [1, 1]])
|
|
186
189
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
+
bboxes = [
|
|
191
|
+
self._vertices.get_datalim(transData),
|
|
192
|
+
]
|
|
193
|
+
if hasattr(self, "_edges"):
|
|
194
|
+
bboxes.append(
|
|
190
195
|
self._edges.get_datalim(transData),
|
|
191
|
-
|
|
192
|
-
)
|
|
196
|
+
)
|
|
197
|
+
bbox = mpl.transforms.Bbox.union(bboxes)
|
|
193
198
|
|
|
194
199
|
bbox = bbox.expanded(sw=(1.0 + pad), sh=(1.0 + pad))
|
|
195
200
|
return bbox
|
|
@@ -239,17 +244,21 @@ class NetworkArtist(mpl.artist.Artist):
|
|
|
239
244
|
labels = self._get_label_series("edge")
|
|
240
245
|
edge_style = get_style(".edge")
|
|
241
246
|
|
|
247
|
+
edge_df = self._ipx_internal_data["edge_df"].set_index(["_ipx_source", "_ipx_target"])
|
|
248
|
+
|
|
249
|
+
if len(edge_df) == 0:
|
|
250
|
+
return
|
|
251
|
+
|
|
242
252
|
if "cmap" in edge_style:
|
|
243
253
|
cmap_fun = _build_cmap_fun(
|
|
244
|
-
edge_style
|
|
245
|
-
|
|
254
|
+
edge_style,
|
|
255
|
+
"color",
|
|
246
256
|
edge_style.get("norm", None),
|
|
257
|
+
internal=edge_df,
|
|
247
258
|
)
|
|
248
259
|
else:
|
|
249
260
|
cmap_fun = None
|
|
250
261
|
|
|
251
|
-
edge_df = self._ipx_internal_data["edge_df"].set_index(["_ipx_source", "_ipx_target"])
|
|
252
|
-
|
|
253
262
|
if "cmap" in edge_style:
|
|
254
263
|
colorarray = []
|
|
255
264
|
edgepatches = []
|
|
@@ -312,8 +321,7 @@ class NetworkArtist(mpl.artist.Artist):
|
|
|
312
321
|
if not self.get_visible():
|
|
313
322
|
return
|
|
314
323
|
|
|
315
|
-
#
|
|
316
|
-
# this is kind of funny actually
|
|
324
|
+
# Handle zorder manually, just like in AxesBase in mpl
|
|
317
325
|
children = list(self.get_children())
|
|
318
326
|
children.sort(key=lambda x: x.zorder)
|
|
319
327
|
for art in children:
|
iplotx/plotting.py
CHANGED
|
@@ -28,6 +28,7 @@ def network(
|
|
|
28
28
|
title: Optional[str] = None,
|
|
29
29
|
aspect: Optional[str | float] = None,
|
|
30
30
|
margins: float | tuple[float, float] = 0,
|
|
31
|
+
strip_axes: bool = True,
|
|
31
32
|
**kwargs,
|
|
32
33
|
) -> list[mpl.artist.Artist]:
|
|
33
34
|
"""Plot this network and/or vertex grouping using the specified layout.
|
|
@@ -53,6 +54,7 @@ def network(
|
|
|
53
54
|
used as a quick fix when some vertex shapes reach beyond the plot edge. This is
|
|
54
55
|
a fraction of the data limits, so 0.1 means 10% of the data limits will be left
|
|
55
56
|
as margin.
|
|
57
|
+
strip_axes: If True, remove axis spines and ticks.
|
|
56
58
|
kwargs: Additional arguments are treated as an alternate way to specify style. If
|
|
57
59
|
both "style" and additional **kwargs are provided, they are both applied in that
|
|
58
60
|
order (style, then **kwargs).
|
|
@@ -110,7 +112,7 @@ def network(
|
|
|
110
112
|
if aspect is not None:
|
|
111
113
|
ax.set_aspect(aspect)
|
|
112
114
|
|
|
113
|
-
|
|
115
|
+
_postprocess_axes(ax, artists, strip=strip_axes)
|
|
114
116
|
|
|
115
117
|
if np.isscalar(margins):
|
|
116
118
|
margins = (margins, margins)
|
|
@@ -132,6 +134,7 @@ def tree(
|
|
|
132
134
|
title: Optional[str] = None,
|
|
133
135
|
aspect: Optional[str | float] = None,
|
|
134
136
|
margins: float | tuple[float, float] = 0,
|
|
137
|
+
strip_axes: bool = True,
|
|
135
138
|
**kwargs,
|
|
136
139
|
) -> TreeArtist:
|
|
137
140
|
"""Plot a tree using the specified layout.
|
|
@@ -143,6 +146,7 @@ def tree(
|
|
|
143
146
|
show_support: If True, show the support values for the nodes (assumed to be from 0 to 100,
|
|
144
147
|
rounded to nearest integer). If both this parameter and vertex_labels are set,
|
|
145
148
|
show_support takes precedence and hides the vertex labels.
|
|
149
|
+
strip_axes: If True, remove axis spines and ticks.
|
|
146
150
|
|
|
147
151
|
Returns:
|
|
148
152
|
A TreeArtist object, set as a direct child of the matplotlib Axes.
|
|
@@ -173,7 +177,7 @@ def tree(
|
|
|
173
177
|
if aspect is not None:
|
|
174
178
|
ax.set_aspect(aspect)
|
|
175
179
|
|
|
176
|
-
|
|
180
|
+
_postprocess_axes(ax, [artist], strip=strip_axes)
|
|
177
181
|
|
|
178
182
|
if np.isscalar(margins):
|
|
179
183
|
margins = (margins, margins)
|
|
@@ -184,18 +188,19 @@ def tree(
|
|
|
184
188
|
|
|
185
189
|
|
|
186
190
|
# INTERNAL ROUTINES
|
|
187
|
-
def
|
|
191
|
+
def _postprocess_axes(ax, artists, strip=True):
|
|
188
192
|
"""Postprocess axis after plotting."""
|
|
189
193
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
194
|
+
if strip:
|
|
195
|
+
# Despine
|
|
196
|
+
ax.spines["right"].set_visible(False)
|
|
197
|
+
ax.spines["top"].set_visible(False)
|
|
198
|
+
ax.spines["left"].set_visible(False)
|
|
199
|
+
ax.spines["bottom"].set_visible(False)
|
|
195
200
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
201
|
+
# Remove axis ticks
|
|
202
|
+
ax.set_xticks([])
|
|
203
|
+
ax.set_yticks([])
|
|
199
204
|
|
|
200
205
|
# Set new data limits
|
|
201
206
|
bboxes = []
|
iplotx/tree.py
CHANGED
|
@@ -329,8 +329,8 @@ class TreeArtist(mpl.artist.Artist):
|
|
|
329
329
|
|
|
330
330
|
if "cmap" in edge_style:
|
|
331
331
|
cmap_fun = _build_cmap_fun(
|
|
332
|
-
edge_style
|
|
333
|
-
|
|
332
|
+
edge_style,
|
|
333
|
+
"color",
|
|
334
334
|
)
|
|
335
335
|
else:
|
|
336
336
|
cmap_fun = None
|
|
@@ -537,16 +537,17 @@ class TreeArtist(mpl.artist.Artist):
|
|
|
537
537
|
labels = self._get_label_series("edge")
|
|
538
538
|
edge_style = get_style(".edge")
|
|
539
539
|
|
|
540
|
+
edge_df = self._ipx_internal_data["edge_df"].set_index(["_ipx_source", "_ipx_target"])
|
|
541
|
+
|
|
540
542
|
if "cmap" in edge_style:
|
|
541
543
|
cmap_fun = _build_cmap_fun(
|
|
542
|
-
edge_style
|
|
543
|
-
|
|
544
|
+
edge_style,
|
|
545
|
+
"color",
|
|
546
|
+
internal=edge_df,
|
|
544
547
|
)
|
|
545
548
|
else:
|
|
546
549
|
cmap_fun = None
|
|
547
550
|
|
|
548
|
-
edge_df = self._ipx_internal_data["edge_df"].set_index(["_ipx_source", "_ipx_target"])
|
|
549
|
-
|
|
550
551
|
if "cmap" in edge_style:
|
|
551
552
|
colorarray = []
|
|
552
553
|
edgepatches = []
|
iplotx/utils/matplotlib.py
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
from typing import Optional, Any
|
|
1
2
|
from functools import wraps, partial
|
|
2
3
|
from math import atan2
|
|
3
4
|
import numpy as np
|
|
5
|
+
import pandas as pd
|
|
4
6
|
import matplotlib as mpl
|
|
5
7
|
|
|
6
8
|
from .geometry import (
|
|
@@ -162,15 +164,39 @@ def _compute_mid_coord_and_rot(path, trans):
|
|
|
162
164
|
return coord, rot
|
|
163
165
|
|
|
164
166
|
|
|
165
|
-
def _build_cmap_fun(
|
|
166
|
-
|
|
167
|
+
def _build_cmap_fun(
|
|
168
|
+
style: dict[str, Any],
|
|
169
|
+
key: str,
|
|
170
|
+
norm=None,
|
|
171
|
+
internal: Optional[pd.DataFrame] = None,
|
|
172
|
+
):
|
|
173
|
+
"""Map colormap on top of numerical values.
|
|
174
|
+
|
|
175
|
+
Parameters:
|
|
176
|
+
style: A dictionary of style properties.
|
|
177
|
+
key: The key in the style dictionary to look for values. Values can be a list/array,
|
|
178
|
+
a dictionary of numerical values, or a string, in which case the corresponding
|
|
179
|
+
column in the "internal" DataFrame is used as an array of numerical values.
|
|
180
|
+
norm: An optional matplotlib Normalize instance. If None, the values are normalized.
|
|
181
|
+
internal: An optional DataFrame, required if "values" is a string.
|
|
182
|
+
"""
|
|
183
|
+
values = style[key]
|
|
184
|
+
cmap = style["cmap"]
|
|
185
|
+
|
|
167
186
|
cmap = mpl.cm._ensure_cmap(cmap)
|
|
168
187
|
|
|
169
|
-
if
|
|
170
|
-
|
|
188
|
+
if isinstance(values, str):
|
|
189
|
+
if not isinstance(internal, pd.DataFrame):
|
|
190
|
+
raise ValueError("If 'values' is a string, 'internal' must be a DataFrame.")
|
|
191
|
+
values = internal[values].values
|
|
192
|
+
internal[key] = values
|
|
193
|
+
|
|
194
|
+
else:
|
|
195
|
+
if np.isscalar(values):
|
|
196
|
+
values = [values]
|
|
171
197
|
|
|
172
|
-
|
|
173
|
-
|
|
198
|
+
if isinstance(values, dict):
|
|
199
|
+
values = np.array(list(values.values()))
|
|
174
200
|
|
|
175
201
|
if norm is None:
|
|
176
202
|
vmin = np.nanmin(values)
|
iplotx/version.py
CHANGED
iplotx/vertex.py
CHANGED
|
@@ -68,7 +68,7 @@ class VertexCollection(PatchCollection):
|
|
|
68
68
|
"""
|
|
69
69
|
|
|
70
70
|
self._index = layout.index
|
|
71
|
-
self._style = style
|
|
71
|
+
self._style = style if style is not None else {}
|
|
72
72
|
self._layout = layout
|
|
73
73
|
self._layout_coordinate_system = layout_coordinate_system
|
|
74
74
|
|
|
@@ -94,6 +94,9 @@ class VertexCollection(PatchCollection):
|
|
|
94
94
|
if self._labels is not None:
|
|
95
95
|
self._compute_label_collection()
|
|
96
96
|
|
|
97
|
+
zorder = self._style.get("zorder", 1)
|
|
98
|
+
self.set_zorder(zorder)
|
|
99
|
+
|
|
97
100
|
def __len__(self):
|
|
98
101
|
"""Return the number of vertices in the collection."""
|
|
99
102
|
return len(self.get_paths())
|
|
@@ -226,8 +229,8 @@ class VertexCollection(PatchCollection):
|
|
|
226
229
|
style = self._style or {}
|
|
227
230
|
if "cmap" in style:
|
|
228
231
|
cmap_fun = _build_cmap_fun(
|
|
229
|
-
style
|
|
230
|
-
|
|
232
|
+
style,
|
|
233
|
+
"facecolor",
|
|
231
234
|
)
|
|
232
235
|
else:
|
|
233
236
|
cmap_fun = None
|
|
@@ -4,22 +4,22 @@ iplotx/cascades.py,sha256=OPqF7Huls-HFmDA5MCF6DEZlUeRVaXsbQcHBoKAgNJs,8182
|
|
|
4
4
|
iplotx/groups.py,sha256=_9KdIiTAi1kXtd2mDywgBJCbqoRq2z-5fzOPf76Wgb8,6287
|
|
5
5
|
iplotx/label.py,sha256=6am3a0ejcW_bWEXSOODE1Ke3AyCU1lJ45RfnXNbHAQw,8923
|
|
6
6
|
iplotx/layout.py,sha256=KxmRLqjo8AYCBAmXez8rIiLU2sM34qhb6ox9AHYwRyE,4839
|
|
7
|
-
iplotx/network.py,sha256=
|
|
8
|
-
iplotx/plotting.py,sha256=
|
|
9
|
-
iplotx/tree.py,sha256=
|
|
7
|
+
iplotx/network.py,sha256=LaW9zQZ4sKiDVb25_icnquGNnN7HrKC7NO07o6PSmGI,11527
|
|
8
|
+
iplotx/plotting.py,sha256=eLsdOOZ15SQTcNeSxqpxYtzfiVPo5Npqgg5wrxyJfrs,7561
|
|
9
|
+
iplotx/tree.py,sha256=Zzz7nCPZrSjh9_yHXFdd8hjbF-FYURTZs00rUHc4OT8,27304
|
|
10
10
|
iplotx/typing.py,sha256=QLdzV358IiD1CFe88MVp0D77FSx5sSAVUmM_2WPPE8I,1463
|
|
11
|
-
iplotx/version.py,sha256=
|
|
12
|
-
iplotx/vertex.py,sha256
|
|
13
|
-
iplotx/edge/__init__.py,sha256=
|
|
11
|
+
iplotx/version.py,sha256=96OI0pGtnG3BPfu9NZSoIkqwIZYegDQOF3vky5yMB_k,66
|
|
12
|
+
iplotx/vertex.py,sha256=-JZaQPjIAWWP8Wap1HyR4g4HXLNGLwjf4v6jyo994Tk,14671
|
|
13
|
+
iplotx/edge/__init__.py,sha256=HlxeIs88RbRrTetJNLcoq9gjV7cBhOdqQoiVZFFylFc,27081
|
|
14
14
|
iplotx/edge/arrow.py,sha256=C4XoHGCYou1z2alz5Q2VhdaWYEzgebtEF70zVYY_frk,15533
|
|
15
15
|
iplotx/edge/geometry.py,sha256=tiaF4PzvsNBoROrEgcCsw0YdxxZr3oBxF4ord_k4ThA,15069
|
|
16
16
|
iplotx/edge/leaf.py,sha256=SyGMv2PIOoH0pey8-aMVaZheK3hNe1Qz_okcyWbc4E4,4268
|
|
17
17
|
iplotx/edge/ports.py,sha256=BpkbiEhX4mPBBAhOv4jcKFG4Y8hxXz5GRtVLCC0jbtI,1235
|
|
18
18
|
iplotx/ingest/__init__.py,sha256=S0YfnXcFKseB7ZBQc4yRt0cNDsLlhqdom0TmSY3OY2E,4756
|
|
19
19
|
iplotx/ingest/heuristics.py,sha256=715VqgfKek5LOJnu1vTo7RqPgCl-Bb8Cf6o7_Tt57fA,5797
|
|
20
|
-
iplotx/ingest/typing.py,sha256=
|
|
20
|
+
iplotx/ingest/typing.py,sha256=61LwNwrTHVh8eqqC778Gr81zPYcUKW61mDgGCCsuGSk,14181
|
|
21
21
|
iplotx/ingest/providers/network/igraph.py,sha256=8dWeaQ_ZNdltC098V2YeLXsGdJHQnBa6shF1GAfl0Zg,2973
|
|
22
|
-
iplotx/ingest/providers/network/networkx.py,sha256=
|
|
22
|
+
iplotx/ingest/providers/network/networkx.py,sha256=4sPFOx87ipOYlXu0hjJl25Z4So_RnhO1CYYozGp-wJg,4626
|
|
23
23
|
iplotx/ingest/providers/network/simple.py,sha256=e_aHhiHhN9DrMoNrt7tEMPURXGhQ1TYRPzsxDEptUlc,3766
|
|
24
24
|
iplotx/ingest/providers/tree/biopython.py,sha256=4N_54cVyHHPcASJZGr6pHKE2p5R3i8Cm307SLlSLHLA,1480
|
|
25
25
|
iplotx/ingest/providers/tree/cogent3.py,sha256=JmELbDK7LyybiJzFNbmeqZ4ySJoDajvFfJebpNfFKWo,1073
|
|
@@ -31,8 +31,8 @@ iplotx/style/leaf_info.py,sha256=JoX1cPjRM_k3f93jzUPQ3gPlVP4wY_n032nOVhrgelU,969
|
|
|
31
31
|
iplotx/style/library.py,sha256=wO-eeY3EZfAl0v21aX9f5_MiZhHuL2kGsBYA3uJkIGs,8535
|
|
32
32
|
iplotx/utils/geometry.py,sha256=6RrC6qaB0-1vIk1LhGA4CfsiMd-9JNniSPyL_l9mshE,9245
|
|
33
33
|
iplotx/utils/internal.py,sha256=WWfcZDGK8Ut1y_tOHRGg9wSqY1bwSeLQO7dHM_8Tvwo,107
|
|
34
|
-
iplotx/utils/matplotlib.py,sha256=
|
|
34
|
+
iplotx/utils/matplotlib.py,sha256=wELE73quQv10-1w9uA5eDTgkZkylJvjg7pd3K5tZPOo,6294
|
|
35
35
|
iplotx/utils/style.py,sha256=wMWxJykxBD-JmcN8-rSKlWcV6pMfwKgR4EzSpk_NX8k,547
|
|
36
|
-
iplotx-0.6.
|
|
37
|
-
iplotx-0.6.
|
|
38
|
-
iplotx-0.6.
|
|
36
|
+
iplotx-0.6.6.dist-info/METADATA,sha256=48xdO8iccA0Y53CJLK-7xCI3rRYptFlq1MQJ_UR-cnE,4908
|
|
37
|
+
iplotx-0.6.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
38
|
+
iplotx-0.6.6.dist-info/RECORD,,
|
|
File without changes
|