iplotx 0.11.0__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.
@@ -2,13 +2,26 @@
2
2
  Module containing code to manipulate edge visualisations in 3D, especially the Edge3DCollection class.
3
3
  """
4
4
 
5
- from mpl_toolkits.mplot3d import Axes3D
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
@@ -705,6 +705,7 @@ def make_stub_patch(**kwargs):
705
705
  "norm",
706
706
  "split",
707
707
  "shrink",
708
+ "depthshade",
708
709
  # DEPRECATED
709
710
  "padding",
710
711
  ]
iplotx/groups.py CHANGED
@@ -65,7 +65,7 @@ class GroupingArtist(PatchCollection):
65
65
  self._points_per_curve = points_per_curve
66
66
 
67
67
  network = kwargs.pop("network", None)
68
- self.layout = normalise_layout(layout, network=network)
68
+ self.layout = layout = normalise_layout(layout, network=network)
69
69
  self.ndim = layout.shape[1]
70
70
 
71
71
  patches, grouping, coords_hulls = self._create_patches(
@@ -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=False,
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
@@ -42,6 +42,7 @@ nonrotating_leaves = (
42
42
  "angular",
43
43
  "curved",
44
44
  "capstyle",
45
+ "depthshade",
45
46
  )
46
47
 
47
48
  # Union of all style leaves (rotating and nonrotating)
@@ -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
@@ -2,4 +2,4 @@
2
2
  iplotx version information module.
3
3
  """
4
4
 
5
- __version__ = "0.11.0"
5
+ __version__ = "0.12.0"
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.11.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) (for educational purposes)
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
- - [minimal tree data structure](https://iplotx.readthedocs.io/en/latest/gallery/tree/plot_simpletreedataprovider.html#sphx-glr-gallery-tree-plot-simpletreedataprovider-py) (for educational purposes)
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 biopython. ✅
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
- - Efficient plotting of large graphs using matplotlib's collection functionality. ✅
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.🏗️
@@ -1,20 +1,20 @@
1
1
  iplotx/__init__.py,sha256=RzSct91jO8abrxOIn33rKEnDUgYpu1oj4olbObgX_hs,489
2
2
  iplotx/artists.py,sha256=XNtRwuvQdKkZCAejILydLD3J5B87sg5xPXuZFv_Gkk8,654
3
3
  iplotx/cascades.py,sha256=OPqF7Huls-HFmDA5MCF6DEZlUeRVaXsbQcHBoKAgNJs,8182
4
- iplotx/groups.py,sha256=X0G-EULkd7WBn1j82r-cBgpzZRd7gQ1cfqFoYNweLns,6775
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=ae5rZwzWxmcBQXx1Y0q24jaXcM1hT1kip-JKsyk11QY,13385
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=mharC6dtEtQmAi9lgWMRhn8D3jCoxBqPbGjIoeD7D9Y,67
12
- iplotx/vertex.py,sha256=bjvAy9UciPWkA1J-SroWF9ZaTXRzNKtDZXBlZ80VM60,16026
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=EzzW06YEeyIu52gXormkGIobae-etwKevZ_PDBr-S9c,4624
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=wMKXD1h5SBaUv6HmebIc5wc9k8AuukaXzAOBu7epaqA,26341
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=mcd6ewZl3jC0CPshmbeUkNp2geoihJW9515roGy2T8o,1000
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=wELE73quQv10-1w9uA5eDTgkZkylJvjg7pd3K5tZPOo,6294
39
+ iplotx/utils/matplotlib.py,sha256=p_53Oamof0RI4mtV8HrdDtZbgVqUxeUZ_KDvLZSiBUQ,8604
39
40
  iplotx/utils/style.py,sha256=vyNP80nDYVinqm6_9ltCJCtjK35ZcGlHvOskNv3eQBc,4225
40
- iplotx-0.11.0.dist-info/METADATA,sha256=yTnevMcILo2NHdvx7EOniBU6zX4vD4ujJWdA3RR7hVU,4880
41
- iplotx-0.11.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
42
- iplotx-0.11.0.dist-info/RECORD,,
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,,