iplotx 0.11.1__py3-none-any.whl → 0.12.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.
- iplotx/art3d/edge/__init__.py +120 -1
- iplotx/edge/__init__.py +1 -0
- iplotx/ingest/providers/tree/dendropy.py +59 -0
- iplotx/network.py +4 -1
- iplotx/style/leaf_info.py +1 -0
- iplotx/utils/matplotlib.py +78 -0
- iplotx/version.py +1 -1
- iplotx/vertex.py +1 -1
- {iplotx-0.11.1.dist-info → iplotx-0.12.0.dist-info}/METADATA +10 -6
- {iplotx-0.11.1.dist-info → iplotx-0.12.0.dist-info}/RECORD +11 -10
- {iplotx-0.11.1.dist-info → iplotx-0.12.0.dist-info}/WHEEL +0 -0
iplotx/art3d/edge/__init__.py
CHANGED
|
@@ -2,13 +2,26 @@
|
|
|
2
2
|
Module containing code to manipulate edge visualisations in 3D, especially the Edge3DCollection class.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
import numpy as np
|
|
6
|
+
from matplotlib import (
|
|
7
|
+
colors as mcolors,
|
|
8
|
+
)
|
|
9
|
+
from matplotlib.collections import (
|
|
10
|
+
LineCollection,
|
|
11
|
+
)
|
|
12
|
+
from mpl_toolkits.mplot3d import (
|
|
13
|
+
Axes3D,
|
|
14
|
+
)
|
|
6
15
|
from mpl_toolkits.mplot3d.art3d import (
|
|
7
16
|
Line3DCollection,
|
|
17
|
+
_viewlim_mask,
|
|
8
18
|
)
|
|
9
19
|
|
|
10
20
|
from ...utils.matplotlib import (
|
|
11
21
|
_forwarder,
|
|
22
|
+
_proj_transform_vectors,
|
|
23
|
+
_zalpha,
|
|
24
|
+
_get_data_scale,
|
|
12
25
|
)
|
|
13
26
|
from ...edge import (
|
|
14
27
|
EdgeCollection,
|
|
@@ -73,11 +86,113 @@ class Edge3DCollection(Line3DCollection):
|
|
|
73
86
|
segments3d.append(segment)
|
|
74
87
|
self.set_segments(segments3d)
|
|
75
88
|
|
|
89
|
+
def do_3d_projection(self):
|
|
90
|
+
"""
|
|
91
|
+
Project the points according to renderer matrix.
|
|
92
|
+
"""
|
|
93
|
+
segments = np.asanyarray(self._segments3d)
|
|
94
|
+
|
|
95
|
+
mask = False
|
|
96
|
+
if np.ma.isMA(segments):
|
|
97
|
+
mask = segments.mask
|
|
98
|
+
|
|
99
|
+
if self._axlim_clip:
|
|
100
|
+
viewlim_mask = _viewlim_mask(
|
|
101
|
+
segments[..., 0], segments[..., 1], segments[..., 2], self.axes
|
|
102
|
+
)
|
|
103
|
+
if np.any(viewlim_mask):
|
|
104
|
+
# broadcast mask to 3D
|
|
105
|
+
viewlim_mask = np.broadcast_to(
|
|
106
|
+
viewlim_mask[..., np.newaxis], (*viewlim_mask.shape, 3)
|
|
107
|
+
)
|
|
108
|
+
mask = mask | viewlim_mask
|
|
109
|
+
xyzs = np.ma.array(_proj_transform_vectors(segments, self.axes.M), mask=mask)
|
|
110
|
+
segments_2d = xyzs[..., 0:2]
|
|
111
|
+
LineCollection.set_segments(self, segments_2d)
|
|
112
|
+
|
|
113
|
+
# Use the average projected z value of each line for depthshade
|
|
114
|
+
xyzs_mean = xyzs.mean(axis=1)
|
|
115
|
+
self._data_scale = _get_data_scale(*(xyzs_mean.T))
|
|
116
|
+
self._vzs = xyzs_mean[..., 2]
|
|
117
|
+
|
|
118
|
+
# FIXME
|
|
119
|
+
if len(xyzs) > 0:
|
|
120
|
+
minz = min(xyzs[..., 2].min(), 1e9)
|
|
121
|
+
else:
|
|
122
|
+
minz = np.nan
|
|
123
|
+
return minz
|
|
124
|
+
|
|
125
|
+
def _maybe_depth_shade_and_sort_colors(self, color_array):
|
|
126
|
+
color_array = (
|
|
127
|
+
_zalpha(
|
|
128
|
+
color_array,
|
|
129
|
+
self._vzs,
|
|
130
|
+
min_alpha=self._depthshade_minalpha,
|
|
131
|
+
_data_scale=self._data_scale,
|
|
132
|
+
)
|
|
133
|
+
if self._vzs is not None and self._depthshade
|
|
134
|
+
else color_array
|
|
135
|
+
)
|
|
136
|
+
return mcolors.to_rgba_array(color_array, self._alpha)
|
|
137
|
+
|
|
138
|
+
def set_edgecolor(self, color):
|
|
139
|
+
"""Set the edge color of the collection."""
|
|
140
|
+
self._edgecolors = mcolors.to_rgba_array(color, self._alpha)
|
|
141
|
+
self._edgecolors_noshade = self._edgecolors.copy()
|
|
142
|
+
|
|
143
|
+
def get_edgecolor(self):
|
|
144
|
+
"""Set the edge color of the collection, including depth shading."""
|
|
145
|
+
# We need this check here to make sure we do not double-apply the depth
|
|
146
|
+
# based alpha shading when the edge color is "face" which means the
|
|
147
|
+
# edge colour should be identical to the face colour.
|
|
148
|
+
if not hasattr(self, "_edgecolors_noshade"):
|
|
149
|
+
self._edgecolors_noshade = self._edgecolors.copy()
|
|
150
|
+
return self._maybe_depth_shade_and_sort_colors(self._edgecolors_noshade)
|
|
151
|
+
|
|
152
|
+
set_edgecolors = set_edgecolor
|
|
153
|
+
get_edgecolors = get_edgecolor
|
|
154
|
+
|
|
155
|
+
def get_depthshade(self):
|
|
156
|
+
"""Get whether depth shading is performed on collection members."""
|
|
157
|
+
return self._depthshade
|
|
158
|
+
|
|
159
|
+
def get_depthshade_minalpha(self):
|
|
160
|
+
"""The minimum alpha value used by depth-shading."""
|
|
161
|
+
return self._depthshade_minalpha
|
|
162
|
+
|
|
163
|
+
def set_depthshade(
|
|
164
|
+
self,
|
|
165
|
+
depthshade,
|
|
166
|
+
depthshade_minalpha=0.1,
|
|
167
|
+
):
|
|
168
|
+
"""
|
|
169
|
+
Set whether depth shading is performed on collection members.
|
|
170
|
+
|
|
171
|
+
Parameters
|
|
172
|
+
----------
|
|
173
|
+
depthshade : bool
|
|
174
|
+
Whether to shade the patches in order to give the appearance of
|
|
175
|
+
depth.
|
|
176
|
+
depthshade_minalpha : float
|
|
177
|
+
Sets the minimum alpha value used by depth-shading.
|
|
178
|
+
|
|
179
|
+
.. versionadded:: 3.11
|
|
180
|
+
"""
|
|
181
|
+
self._depthshade = depthshade
|
|
182
|
+
self._depthshade_minalpha = depthshade_minalpha
|
|
183
|
+
self.stale = True
|
|
184
|
+
|
|
76
185
|
def _update_before_draw(self) -> None:
|
|
77
186
|
"""Update the collection before drawing."""
|
|
78
187
|
if isinstance(self.axes, Axes3D) and hasattr(self, "do_3d_projection"):
|
|
79
188
|
self.do_3d_projection()
|
|
80
189
|
|
|
190
|
+
if not hasattr(self, "_edgecolors_noshade"):
|
|
191
|
+
self._edgecolors_noshade = self._edgecolors.copy()
|
|
192
|
+
self._edgecolors = self._maybe_depth_shade_and_sort_colors(
|
|
193
|
+
self._edgecolors_noshade,
|
|
194
|
+
)
|
|
195
|
+
|
|
81
196
|
# TODO: Here's where we would shorten the edges to fit the vertex
|
|
82
197
|
# projections from 3D onto 2D, if we wanted to do that. Because edges
|
|
83
198
|
# in 3D are chains of segments rathen than splines, the shortening
|
|
@@ -111,6 +226,7 @@ def edge_collection_2d_to_3d(
|
|
|
111
226
|
col: EdgeCollection,
|
|
112
227
|
zdir: str = "z",
|
|
113
228
|
axlim_clip: bool = False,
|
|
229
|
+
depthshade: bool = True,
|
|
114
230
|
):
|
|
115
231
|
"""Convert a 2D EdgeCollection to a 3D Edge3DCollection.
|
|
116
232
|
|
|
@@ -127,6 +243,9 @@ def edge_collection_2d_to_3d(
|
|
|
127
243
|
# NOTE: after this line, none of the EdgeCollection methods will work
|
|
128
244
|
# It's become a static drawer now. It uses segments instead of paths.
|
|
129
245
|
col.__class__ = Edge3DCollection
|
|
246
|
+
col._depthshade = depthshade
|
|
247
|
+
col._depthshade_minalpha = 0.1
|
|
248
|
+
|
|
130
249
|
col._compute_edge_segments()
|
|
131
250
|
|
|
132
251
|
col._axlim_clip = axlim_clip
|
iplotx/edge/__init__.py
CHANGED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
from typing import (
|
|
2
|
+
Any,
|
|
3
|
+
Optional,
|
|
4
|
+
Sequence,
|
|
5
|
+
)
|
|
6
|
+
import importlib
|
|
7
|
+
|
|
8
|
+
from ...typing import (
|
|
9
|
+
TreeDataProvider,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class DendropyDataProvider(TreeDataProvider):
|
|
14
|
+
def is_rooted(self) -> bool:
|
|
15
|
+
return True
|
|
16
|
+
|
|
17
|
+
def get_root(self) -> Any:
|
|
18
|
+
"""Get the root of the tree."""
|
|
19
|
+
return next(self.preorder())
|
|
20
|
+
|
|
21
|
+
def preorder(self) -> Any:
|
|
22
|
+
"""Preorder traversal of the tree.
|
|
23
|
+
|
|
24
|
+
NOTE: This will work on both entire Trees and Nodes (which means a subtree including self).
|
|
25
|
+
"""
|
|
26
|
+
if hasattr(self.tree, "preorder_node_iter"):
|
|
27
|
+
return self.tree.preorder_node_iter()
|
|
28
|
+
return self.tree.preorder_iter()
|
|
29
|
+
|
|
30
|
+
def postorder(self) -> Any:
|
|
31
|
+
"""Preorder traversal of the tree.
|
|
32
|
+
|
|
33
|
+
NOTE: This will work on both entire Trees and Nodes (which means a subtree including self).
|
|
34
|
+
"""
|
|
35
|
+
if hasattr(self.tree, "postorder_node_iter"):
|
|
36
|
+
return self.tree.postorder_node_iter()
|
|
37
|
+
return self.tree.postorder_iter()
|
|
38
|
+
|
|
39
|
+
def get_leaves(self) -> Sequence[Any]:
|
|
40
|
+
"""Get a list of leaves."""
|
|
41
|
+
return self.tree.leaf_nodes()
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def get_children(node: Any) -> Sequence[Any]:
|
|
45
|
+
return node.child_nodes()
|
|
46
|
+
|
|
47
|
+
@staticmethod
|
|
48
|
+
def get_branch_length(node: Any) -> Optional[float]:
|
|
49
|
+
return node.edge.length
|
|
50
|
+
|
|
51
|
+
@staticmethod
|
|
52
|
+
def check_dependencies() -> bool:
|
|
53
|
+
return importlib.util.find_spec("dendropy") is not None
|
|
54
|
+
|
|
55
|
+
@staticmethod
|
|
56
|
+
def tree_type():
|
|
57
|
+
import dendropy
|
|
58
|
+
|
|
59
|
+
return dendropy.Tree
|
iplotx/network.py
CHANGED
|
@@ -279,10 +279,11 @@ class NetworkArtist(mpl.artist.Artist):
|
|
|
279
279
|
)
|
|
280
280
|
|
|
281
281
|
if self.get_ndim() == 3:
|
|
282
|
+
depthshade = get_style(".vertex").get("depthshade", True)
|
|
282
283
|
vertex_collection_2d_to_3d(
|
|
283
284
|
self._vertices,
|
|
284
285
|
zs=self.get_layout().iloc[:, 2].values,
|
|
285
|
-
depthshade=
|
|
286
|
+
depthshade=depthshade,
|
|
286
287
|
)
|
|
287
288
|
|
|
288
289
|
def _add_edges(self):
|
|
@@ -367,8 +368,10 @@ class NetworkArtist(mpl.artist.Artist):
|
|
|
367
368
|
self._edges.set_array(colorarray)
|
|
368
369
|
|
|
369
370
|
if self.get_ndim() == 3:
|
|
371
|
+
depthshade = get_style(".edge").get("depthshade", True)
|
|
370
372
|
edge_collection_2d_to_3d(
|
|
371
373
|
self._edges,
|
|
374
|
+
depthshade=depthshade,
|
|
372
375
|
)
|
|
373
376
|
|
|
374
377
|
@_stale_wrapper
|
iplotx/style/leaf_info.py
CHANGED
iplotx/utils/matplotlib.py
CHANGED
|
@@ -4,6 +4,7 @@ from math import atan2
|
|
|
4
4
|
import numpy as np
|
|
5
5
|
import pandas as pd
|
|
6
6
|
import matplotlib as mpl
|
|
7
|
+
import matplotlib.colors as mcolors
|
|
7
8
|
|
|
8
9
|
from .geometry import (
|
|
9
10
|
_evaluate_squared_bezier,
|
|
@@ -204,3 +205,80 @@ def _build_cmap_fun(
|
|
|
204
205
|
norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax)
|
|
205
206
|
|
|
206
207
|
return lambda x: cmap(norm(x))
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
# NOTE: this is polyfill from future matplotlib versions
|
|
211
|
+
# LICENSED UNDER THE MPL LICENSE from:
|
|
212
|
+
# https://github.com/matplotlib/matplotlib/blob/main/lib/mpl_toolkits/mplot3d/proj3d.py
|
|
213
|
+
def _proj_transform_vectors(vecs, M):
|
|
214
|
+
"""
|
|
215
|
+
Vectorized version of ``_proj_transform_vec``.
|
|
216
|
+
|
|
217
|
+
Parameters
|
|
218
|
+
----------
|
|
219
|
+
vecs : ... x 3 np.ndarray
|
|
220
|
+
Input vectors
|
|
221
|
+
M : 4 x 4 np.ndarray
|
|
222
|
+
Projection matrix
|
|
223
|
+
"""
|
|
224
|
+
vecs_shape = vecs.shape
|
|
225
|
+
vecs = vecs.reshape(-1, 3).T
|
|
226
|
+
|
|
227
|
+
vecs_pad = np.empty((vecs.shape[0] + 1,) + vecs.shape[1:])
|
|
228
|
+
vecs_pad[:-1] = vecs
|
|
229
|
+
vecs_pad[-1] = 1
|
|
230
|
+
product = np.dot(M, vecs_pad)
|
|
231
|
+
tvecs = product[:3] / product[3]
|
|
232
|
+
|
|
233
|
+
return tvecs.T.reshape(vecs_shape)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def _zalpha(
|
|
237
|
+
colors,
|
|
238
|
+
zs,
|
|
239
|
+
min_alpha=0.3,
|
|
240
|
+
_data_scale=None,
|
|
241
|
+
):
|
|
242
|
+
"""Modify the alpha values of the color list according to z-depth."""
|
|
243
|
+
|
|
244
|
+
if len(colors) == 0 or len(zs) == 0:
|
|
245
|
+
return np.zeros((0, 4))
|
|
246
|
+
|
|
247
|
+
# Alpha values beyond the range 0-1 inclusive make no sense, so clip them
|
|
248
|
+
min_alpha = np.clip(min_alpha, 0, 1)
|
|
249
|
+
|
|
250
|
+
if _data_scale is None or _data_scale == 0:
|
|
251
|
+
# Don't scale the alpha values since we have no valid data scale for reference
|
|
252
|
+
sats = np.ones_like(zs)
|
|
253
|
+
|
|
254
|
+
else:
|
|
255
|
+
# Deeper points have an increasingly transparent appearance
|
|
256
|
+
sats = np.clip(1 - (zs - np.min(zs)) / _data_scale, min_alpha, 1)
|
|
257
|
+
|
|
258
|
+
rgba = np.broadcast_to(mcolors.to_rgba_array(colors), (len(zs), 4))
|
|
259
|
+
|
|
260
|
+
# Change the alpha values of the colors using the generated alpha multipliers
|
|
261
|
+
return np.column_stack([rgba[:, :3], rgba[:, 3] * sats])
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _get_data_scale(X, Y, Z):
|
|
265
|
+
"""
|
|
266
|
+
Estimate the scale of the 3D data for use in depth shading
|
|
267
|
+
|
|
268
|
+
Parameters
|
|
269
|
+
----------
|
|
270
|
+
X, Y, Z : masked arrays
|
|
271
|
+
The data to estimate the scale of.
|
|
272
|
+
"""
|
|
273
|
+
# Account for empty datasets. Assume that X Y and Z have the same number
|
|
274
|
+
# of elements.
|
|
275
|
+
if not np.ma.count(X):
|
|
276
|
+
return 0
|
|
277
|
+
|
|
278
|
+
# Estimate the scale using the RSS of the ranges of the dimensions
|
|
279
|
+
# Note that we don't use np.ma.ptp() because we otherwise get a build
|
|
280
|
+
# warning about handing empty arrays.
|
|
281
|
+
ptp_x = X.max() - X.min()
|
|
282
|
+
ptp_y = Y.max() - Y.min()
|
|
283
|
+
ptp_z = Z.max() - Z.min()
|
|
284
|
+
return np.sqrt(ptp_x**2 + ptp_y**2 + ptp_z**2)
|
iplotx/version.py
CHANGED
iplotx/vertex.py
CHANGED
|
@@ -398,7 +398,7 @@ def make_patch(
|
|
|
398
398
|
**kwargs,
|
|
399
399
|
) -> tuple[Patch, float]:
|
|
400
400
|
"""Make a patch of the given marker shape and size."""
|
|
401
|
-
forbidden_props = ["label", "cmap", "norm", "cascade", "deep"]
|
|
401
|
+
forbidden_props = ["label", "cmap", "norm", "cascade", "deep", "depthshade"]
|
|
402
402
|
for prop in forbidden_props:
|
|
403
403
|
if prop in kwargs:
|
|
404
404
|
kwargs.pop(prop)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: iplotx
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.12.0
|
|
4
4
|
Summary: Plot networkx from igraph and networkx.
|
|
5
5
|
Project-URL: Homepage, https://github.com/fabilab/iplotx
|
|
6
6
|
Project-URL: Documentation, https://readthedocs.org/iplotx
|
|
@@ -10,8 +10,9 @@ Project-URL: Changelog, https://github.com/fabilab/iplotx/blob/main/CHANGELOG.md
|
|
|
10
10
|
Author-email: Fabio Zanini <fabio.zanini@unsw.edu.au>
|
|
11
11
|
Maintainer-email: Fabio Zanini <fabio.zanini@unsw.edu.au>
|
|
12
12
|
License: MIT
|
|
13
|
-
Keywords: graph,network,plotting,visualisation
|
|
13
|
+
Keywords: graph,network,phylogeny,plotting,tree,visualisation
|
|
14
14
|
Classifier: Development Status :: 5 - Production/Stable
|
|
15
|
+
Classifier: Framework :: Matplotlib
|
|
15
16
|
Classifier: Intended Audience :: Developers
|
|
16
17
|
Classifier: Intended Audience :: Education
|
|
17
18
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -52,13 +53,14 @@ Supports:
|
|
|
52
53
|
- **networks**:
|
|
53
54
|
- [networkx](https://networkx.org/)
|
|
54
55
|
- [igraph](igraph.readthedocs.io/)
|
|
55
|
-
- [minimal network data structure](https://iplotx.readthedocs.io/en/latest/gallery/plot_simplenetworkdataprovider.html#sphx-glr-gallery-plot-simplenetworkdataprovider-py) (
|
|
56
|
+
- [minimal network data structure](https://iplotx.readthedocs.io/en/latest/gallery/plot_simplenetworkdataprovider.html#sphx-glr-gallery-plot-simplenetworkdataprovider-py) (zero dependency)
|
|
56
57
|
- **trees**:
|
|
57
58
|
- [ETE4](https://etetoolkit.github.io/ete/)
|
|
58
59
|
- [cogent3](https://cogent3.org/)
|
|
59
60
|
- [Biopython](https://biopython.org/)
|
|
60
61
|
- [scikit-bio](https://scikit.bio)
|
|
61
|
-
- [
|
|
62
|
+
- [dendropy](https://jeetsukumaran.github.io/DendroPy/index.html)
|
|
63
|
+
- [minimal tree data structure](https://iplotx.readthedocs.io/en/latest/gallery/tree/plot_simpletreedataprovider.html#sphx-glr-gallery-tree-plot-simpletreedataprovider-py) (zero dependency)
|
|
62
64
|
|
|
63
65
|
In addition to the above, *any* network or tree analysis library can register an [entry point](https://iplotx.readthedocs.io/en/latest/providers.html#creating-a-custom-data-provider) to gain compatibility with `iplotx` with no intervention from our side.
|
|
64
66
|
|
|
@@ -89,15 +91,17 @@ See [gallery](https://iplotx.readthedocs.io/en/latest/gallery/index.html).
|
|
|
89
91
|
|
|
90
92
|
## Features
|
|
91
93
|
- Plot networks from multiple libraries including networkx and igraph, using matplotlib as a backend. ✅
|
|
92
|
-
- Plot trees from multiple libraries such as cogent3, ETE4, skbio, and
|
|
94
|
+
- Plot trees from multiple libraries such as cogent3, ETE4, skbio, biopython, and dendropy. ✅
|
|
93
95
|
- Flexible yet easy styling, including an internal library of styles ✅
|
|
94
96
|
- Interactive plotting, e.g. zooming and panning after the plot is created. ✅
|
|
95
97
|
- Store the plot to disk thanks to the many matplotlib backends (SVG, PNG, PDF, etc.). ✅
|
|
96
|
-
-
|
|
98
|
+
- 3D network visualisation with depth shading. ✅
|
|
99
|
+
- Efficient plotting of large graphs (up to ~1 million nodes on a laptop). ✅
|
|
97
100
|
- Edit plotting elements after the plot is created, e.g. changing node colors, labels, etc. ✅
|
|
98
101
|
- Animations, e.g. showing the evolution of a network over time. ✅
|
|
99
102
|
- Mouse and keyboard interaction, e.g. hovering over nodes/edges to get information about them. ✅
|
|
100
103
|
- Node clustering and covers, e.g. showing communities in a network. ✅
|
|
104
|
+
- Edge tension, edge waypoints, and edge ports. ✅
|
|
101
105
|
- Choice of tree layouts and orientations. ✅
|
|
102
106
|
- Tree-specific options: cascades, subtree styling, split edges, etc. ✅
|
|
103
107
|
- (WIP) Support uni- and bi-directional communication between graph object and plot object.🏗️
|
|
@@ -4,17 +4,17 @@ iplotx/cascades.py,sha256=OPqF7Huls-HFmDA5MCF6DEZlUeRVaXsbQcHBoKAgNJs,8182
|
|
|
4
4
|
iplotx/groups.py,sha256=g6ahm61BSBmd2weIjr40MvPi_GcNRgvNb9YklQsiza4,6784
|
|
5
5
|
iplotx/label.py,sha256=7eS8ByadrhdIFOZz19U4VrS-oXY_ndFYNB-D4RZbFqI,9573
|
|
6
6
|
iplotx/layout.py,sha256=KxmRLqjo8AYCBAmXez8rIiLU2sM34qhb6ox9AHYwRyE,4839
|
|
7
|
-
iplotx/network.py,sha256=
|
|
7
|
+
iplotx/network.py,sha256=mhR1hwlLrATYJfCZUgk7sfmtw3yEjAE0TtE0b-1N8hE,13567
|
|
8
8
|
iplotx/plotting.py,sha256=icEefWJnS2lEGLp4t1LhDSP40JuvNKgOie3FDLOnTMk,13195
|
|
9
9
|
iplotx/tree.py,sha256=TxbNoBHS0CfswrcMIWCNtnOl_3e4-PwCrVo0goywC0U,28807
|
|
10
10
|
iplotx/typing.py,sha256=QLdzV358IiD1CFe88MVp0D77FSx5sSAVUmM_2WPPE8I,1463
|
|
11
|
-
iplotx/version.py,sha256=
|
|
12
|
-
iplotx/vertex.py,sha256=
|
|
11
|
+
iplotx/version.py,sha256=OAoDyBg_N0NwrLolwb2vnkue-AwN9sTDzRmDcTNfAog,67
|
|
12
|
+
iplotx/vertex.py,sha256=_yYyvusn4vYvi6RBEW6CHa3vnbv43GnZylnMIaK4bG0,16040
|
|
13
13
|
iplotx/art3d/vertex.py,sha256=Xf8Um30X2doCd8KdNN7332F6BxC4k72Mb_GeRAuzQfQ,2545
|
|
14
|
-
iplotx/art3d/edge/__init__.py,sha256=
|
|
14
|
+
iplotx/art3d/edge/__init__.py,sha256=uw1U_mMXqcZAvea-7JbU1PUKULQD1CMMrbwY02tiWRQ,8529
|
|
15
15
|
iplotx/art3d/edge/arrow.py,sha256=14BFXY9kDOUGPZl2fMD9gRVGyaaN5kyd-l6ikBg6WHU,3601
|
|
16
16
|
iplotx/art3d/edge/geometry.py,sha256=76VUmpPG-4Mls7x_994dMwdDPrWWnjT7nHJsHfwK_hA,2467
|
|
17
|
-
iplotx/edge/__init__.py,sha256=
|
|
17
|
+
iplotx/edge/__init__.py,sha256=lkrMkQFx9PNzorKc9trQ8MggC-nZSyALhvP78DMvhN4,26363
|
|
18
18
|
iplotx/edge/arrow.py,sha256=U7vvBo7IMwo1qiyU9cyUEwraOaBcJLgdu9oU2OyoHL4,17453
|
|
19
19
|
iplotx/edge/geometry.py,sha256=jkTMvQC5425GjB_fmGLIPJeSDAr_7NZF8zZDLTrSj34,15541
|
|
20
20
|
iplotx/edge/leaf.py,sha256=SyGMv2PIOoH0pey8-aMVaZheK3hNe1Qz_okcyWbc4E4,4268
|
|
@@ -27,16 +27,17 @@ iplotx/ingest/providers/network/networkx.py,sha256=ehCg4npL073HX-eAG-VoP6refLPsM
|
|
|
27
27
|
iplotx/ingest/providers/network/simple.py,sha256=e_aHhiHhN9DrMoNrt7tEMPURXGhQ1TYRPzsxDEptUlc,3766
|
|
28
28
|
iplotx/ingest/providers/tree/biopython.py,sha256=4N_54cVyHHPcASJZGr6pHKE2p5R3i8Cm307SLlSLHLA,1480
|
|
29
29
|
iplotx/ingest/providers/tree/cogent3.py,sha256=JmELbDK7LyybiJzFNbmeqZ4ySJoDajvFfJebpNfFKWo,1073
|
|
30
|
+
iplotx/ingest/providers/tree/dendropy.py,sha256=uRMe46PfDPUTeNInUO2Gbp4pVr-WIFIZQvrND2tovsg,1548
|
|
30
31
|
iplotx/ingest/providers/tree/ete4.py,sha256=D7usSq0MOjzrk3EoLi834IlaDGwv7_qG6Qt0ptfKqfI,928
|
|
31
32
|
iplotx/ingest/providers/tree/simple.py,sha256=aV9wGqBomJ5klM_aJQeuL_Q_J1pLCv6AFN98BPDiKUw,2593
|
|
32
33
|
iplotx/ingest/providers/tree/skbio.py,sha256=O1KUr8tYi28pZ3VVjapgO4Uj-YpMuix3GhOH5je8Lv4,822
|
|
33
34
|
iplotx/style/__init__.py,sha256=rf1GutrE8hHUhCoe4FGKYX-aNtHuu_U-kYQnqUxZNrY,10282
|
|
34
|
-
iplotx/style/leaf_info.py,sha256=
|
|
35
|
+
iplotx/style/leaf_info.py,sha256=3xBn7xv9Uy2KAqdhM9S6ew5ZBJrGRTXRL3xXb8atfLw,1018
|
|
35
36
|
iplotx/style/library.py,sha256=58Y8BlllGLsR4pQM7_PVCP5tH6_4GkchXZvJpqGHlcg,8534
|
|
36
37
|
iplotx/utils/geometry.py,sha256=6RrC6qaB0-1vIk1LhGA4CfsiMd-9JNniSPyL_l9mshE,9245
|
|
37
38
|
iplotx/utils/internal.py,sha256=WWfcZDGK8Ut1y_tOHRGg9wSqY1bwSeLQO7dHM_8Tvwo,107
|
|
38
|
-
iplotx/utils/matplotlib.py,sha256=
|
|
39
|
+
iplotx/utils/matplotlib.py,sha256=p_53Oamof0RI4mtV8HrdDtZbgVqUxeUZ_KDvLZSiBUQ,8604
|
|
39
40
|
iplotx/utils/style.py,sha256=vyNP80nDYVinqm6_9ltCJCtjK35ZcGlHvOskNv3eQBc,4225
|
|
40
|
-
iplotx-0.
|
|
41
|
-
iplotx-0.
|
|
42
|
-
iplotx-0.
|
|
41
|
+
iplotx-0.12.0.dist-info/METADATA,sha256=OcfxvA_JL2GOXYH7_67iDL1N4_U3fDm7--3nXbUHKU8,5087
|
|
42
|
+
iplotx-0.12.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
43
|
+
iplotx-0.12.0.dist-info/RECORD,,
|
|
File without changes
|