iplotx 1.5.1__py3-none-any.whl → 1.7.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/edge/__init__.py CHANGED
@@ -367,21 +367,13 @@ class EdgeCollection(mpl.collections.PatchCollection):
367
367
 
368
368
  # Leaf rotation
369
369
  edge_stylei = rotate_style(self._style, index=i, key=(v1, v2))
370
- if edge_stylei.get("curved", False):
371
- tension = edge_stylei.get("tension", 5)
372
- ports = edge_stylei.get("ports", (None, None))
373
- elif edge_stylei.get("arc", False):
374
- tension = edge_stylei.get("tension", 1)
375
- ports = None
376
- else:
377
- tension = 0
378
- ports = None
379
370
 
380
371
  # Scale shrink by dpi
381
372
  dpi = self.figure.dpi if hasattr(self, "figure") else 72.0
382
373
  shrink = dpi / 72.0 * edge_stylei.pop("shrink", 0)
383
374
 
384
- # False is a synonym for "none"
375
+ # Edge geometry and waypoints
376
+ # waypoints: False is a synonym for "none"
385
377
  waypoints = edge_stylei.get("waypoints", "none")
386
378
  if waypoints is False or waypoints is np.False_:
387
379
  waypoints = "none"
@@ -391,10 +383,32 @@ class EdgeCollection(mpl.collections.PatchCollection):
391
383
  raise ValueError(
392
384
  "Could not determine automatically type of edge waypoints.",
393
385
  )
394
- if waypoints != "none":
395
- ports = edge_stylei.get("ports", (None, None))
396
386
 
387
+ # Waypoints, curved, and arc have a complex logic
388
+ # TODO: This could be simplified I suppose
389
+ has_waypoints = waypoints != "none"
390
+ curved = edge_stylei.get("curved", False)
397
391
  arc = edge_stylei.get("arc", False)
392
+ ports = edge_stylei.get("ports", (None, None))
393
+
394
+ # For now, we establish a hierarchy from the most specialised to
395
+ # the most common cases. Each specialisation silences lower levels
396
+ # Tension and ports are entirely enslaved to the
397
+ # waypoint/arc/curved geometry settings.
398
+ # NOTE: The idea here is to not punish users for slight style
399
+ # inconsistencies that may well stem from fallback libraries
400
+ if has_waypoints:
401
+ tension = 0
402
+ arc = False
403
+ elif arc:
404
+ tension = edge_stylei.get("tension", 1)
405
+ ports = None
406
+ curved = False
407
+ elif curved:
408
+ tension = edge_stylei.get("tension", 5)
409
+ else:
410
+ tension = 0
411
+ ports = None
398
412
 
399
413
  # Compute actual edge path
400
414
  path, angles = _compute_edge_path(
@@ -406,6 +420,7 @@ class EdgeCollection(mpl.collections.PatchCollection):
406
420
  tension=tension,
407
421
  waypoints=waypoints,
408
422
  ports=ports,
423
+ curved=curved,
409
424
  arc=arc,
410
425
  layout_coordinate_system=self._vertex_collection.get_layout_coordinate_system(),
411
426
  shrink=shrink,
iplotx/edge/geometry.py CHANGED
@@ -239,6 +239,7 @@ def _compute_edge_path_straight(
239
239
 
240
240
  def _compute_edge_path_waypoints(
241
241
  waypoints,
242
+ curved,
242
243
  vcoord_data,
243
244
  vpath_fig,
244
245
  vsize_fig,
@@ -277,8 +278,19 @@ def _compute_edge_path_waypoints(
277
278
  + vcoord_fig[i]
278
279
  )
279
280
 
280
- points = [vshorts[0]] + list(waypoints) + [vshorts[1]]
281
- codes = ["MOVETO"] + ["LINETO"] * len(waypoints) + ["LINETO"]
281
+ if not curved:
282
+ points = [vshorts[0]] + list(waypoints) + [vshorts[1]]
283
+ codes = ["MOVETO"] + ["LINETO"] * len(waypoints) + ["LINETO"]
284
+ else:
285
+ points = [vshorts[0]]
286
+ for i, waypoint in enumerate(waypoints):
287
+ if i != 0:
288
+ points.append(0.5 * (points[-1] + waypoint))
289
+ points.append(waypoint)
290
+ points.append(waypoint)
291
+ points.append(vshorts[1])
292
+ codes = ["MOVETO"] + ["CURVE4"] * (len(points) - 1)
293
+
282
294
  angles = tuple(thetas)
283
295
 
284
296
  elif waypoints in ("x0y1", "y0x1"):
@@ -587,6 +599,7 @@ def _compute_edge_path(
587
599
  tension: float = 0,
588
600
  waypoints: str | tuple[float, float] | Sequence[tuple[float, float]] | np.ndarray = "none",
589
601
  ports: Pair[Optional[str]] = (None, None),
602
+ curved: bool = False,
590
603
  arc: bool = False,
591
604
  layout_coordinate_system: str = "cartesian",
592
605
  **kwargs,
@@ -600,6 +613,7 @@ def _compute_edge_path(
600
613
  if waypoints != "none":
601
614
  return _compute_edge_path_waypoints(
602
615
  waypoints,
616
+ curved,
603
617
  *args,
604
618
  layout_coordinate_system=layout_coordinate_system,
605
619
  ports=ports,
iplotx/plotting.py CHANGED
@@ -20,6 +20,7 @@ from .network import NetworkArtist
20
20
  from .network.groups import GroupingCollection
21
21
  from .tree import TreeArtist
22
22
  from .style import context
23
+ from .utils.matplotlib import _heuristic_show
23
24
 
24
25
 
25
26
  def network(
@@ -36,6 +37,7 @@ def network(
36
37
  margins: float | tuple[float, float] | tuple[float, float, float] = 0,
37
38
  strip_axes: bool = True,
38
39
  figsize: Optional[tuple[float, float]] = None,
40
+ show: Optional[bool] = None,
39
41
  **kwargs,
40
42
  ) -> list[mpl.artist.Artist]:
41
43
  """Plot this network and/or vertex grouping using the specified layout.
@@ -70,6 +72,9 @@ def network(
70
72
  figsize: If ax is None, a new matplotlib Figure is created. This argument specifies
71
73
  the (width, height) dimension of the figure in inches. If ax is not None, this
72
74
  argument is ignored. If None, the default matplotlib figure size is used.
75
+ show: If True, call plt.show() after plotting. If False, do not call plt.show(). If
76
+ None (default), try to guess based on the environment and do not show in case of
77
+ doubt.
73
78
  kwargs: Additional arguments are treated as an alternate way to specify style. If
74
79
  both "style" and additional **kwargs are provided, they are both applied in that
75
80
  order (style, then **kwargs).
@@ -78,7 +83,12 @@ def network(
78
83
  A list of mpl.artist.Artist objects, set as a direct child of the matplotlib Axes.
79
84
  The list can have one or two elements, depending on whether you are requesting to
80
85
  plot a network, a grouping, or both.
86
+
87
+ NOTE: If your plots are now showing to screen, try passing show=True.
81
88
  """
89
+ if show is None:
90
+ show = _heuristic_show()
91
+
82
92
  # Equivalence of node_labels and vertex_labels
83
93
  if node_labels is not None:
84
94
  vertex_labels = node_labels
@@ -164,6 +174,9 @@ def network(
164
174
  if (margins[0] != 0) or (margins[1] != 0) or ((len(margins) == 3) and (margins[2] != 0)):
165
175
  ax.margins(*margins)
166
176
 
177
+ if show:
178
+ plt.show()
179
+
167
180
  return artists
168
181
 
169
182
 
@@ -187,6 +200,7 @@ def tree(
187
200
  margins: float | tuple[float, float] = 0,
188
201
  strip_axes: bool = True,
189
202
  figsize: Optional[tuple[float, float]] = None,
203
+ show: Optional[bool] = None,
190
204
  **kwargs,
191
205
  ) -> TreeArtist:
192
206
  """Plot a tree using the specified layout.
@@ -226,13 +240,21 @@ def tree(
226
240
  figsize: If ax is None, a new matplotlib Figure is created. This argument specifies
227
241
  the (width, height) dimension of the figure in inches. If ax is not None, this
228
242
  argument is ignored. If None, the default matplotlib figure size is used.
243
+ show: If True, call plt.show() after plotting. If False, do not call plt.show(). If
244
+ None (default), try to guess based on the environment and do not show in case of
245
+ doubt.
229
246
  kwargs: Additional arguments are treated as an alternate way to specify style. If
230
247
  both "style" and additional **kwargs are provided, they are both applied in that
231
248
  order (style, then **kwargs).
232
249
 
233
250
  Returns:
234
251
  A TreeArtist object, set as a direct child of the matplotlib Axes.
252
+
253
+ NOTE: If your plots are now showing to screen, try passing show=True.
235
254
  """
255
+ if show is None:
256
+ show = _heuristic_show()
257
+
236
258
  # Equivalence of node_labels and vertex_labels
237
259
  if node_labels is not None:
238
260
  vertex_labels = node_labels
@@ -270,6 +292,9 @@ def tree(
270
292
  if (margins[0] != 0) or (margins[1] != 0):
271
293
  ax.margins(*margins)
272
294
 
295
+ if show:
296
+ plt.show()
297
+
273
298
  return artist
274
299
 
275
300
 
@@ -285,6 +310,7 @@ def doubletree(
285
310
  margins: float | tuple[float, float] = 0,
286
311
  strip_axes: bool = True,
287
312
  figsize: Optional[tuple[float, float]] = None,
313
+ show: Optional[bool] = None,
288
314
  ) -> tuple[TreeArtist, TreeArtist]:
289
315
  """Visualize two trees facing each other.
290
316
 
@@ -306,9 +332,26 @@ def doubletree(
306
332
  figsize: If ax is None, a new matplotlib Figure is created. This argument specifies
307
333
  the (width, height) dimension of the figure in inches. If ax is not None, this
308
334
  argument is ignored. If None, the default matplotlib figure size is used.
335
+ show: If True, call plt.show() after plotting. If False, do not call plt.show(). If
336
+ None (default), try to guess based on the environment and do not show in case of
337
+ doubt.
309
338
  Returns:
310
339
  A tuple with the left and right TreeArtist objects.
340
+
341
+ NOTE: If your plots are now showing to screen, try passing show=True.
311
342
  """
343
+ if show is None:
344
+ show = _heuristic_show()
345
+
346
+ if kwargs_left is None:
347
+ kwargs_left = {}
348
+ if "show" not in kwargs_left:
349
+ kwargs_left["show"] = False
350
+ if kwargs_right is None:
351
+ kwargs_right = {}
352
+ if "show" not in kwargs_right:
353
+ kwargs_right["show"] = False
354
+
312
355
  artist1 = tree(
313
356
  tree_left,
314
357
  layout="horizontal",
@@ -316,14 +359,11 @@ def doubletree(
316
359
  ax=ax,
317
360
  strip_axes=False,
318
361
  figsize=figsize,
319
- **kwargs_left or {},
362
+ **kwargs_left,
320
363
  )
321
364
 
322
365
  ax = artist1.axes
323
366
 
324
- if kwargs_right is None:
325
- kwargs_right = {}
326
-
327
367
  had_layout_start = "layout_start" in kwargs_right
328
368
 
329
369
  artist2 = tree(
@@ -348,6 +388,9 @@ def doubletree(
348
388
 
349
389
  _postprocess_axes(ax, [artist1, artist2], strip=strip_axes, ignore_previous=True)
350
390
 
391
+ if show:
392
+ plt.show()
393
+
351
394
  return (artist1, artist2)
352
395
 
353
396
 
@@ -282,3 +282,8 @@ def _get_data_scale(X, Y, Z):
282
282
  ptp_y = Y.max() - Y.min()
283
283
  ptp_z = Z.max() - Z.min()
284
284
  return np.sqrt(ptp_x**2 + ptp_y**2 + ptp_z**2)
285
+
286
+
287
+ def _heuristic_show():
288
+ """Try guessing whether plt.show() should be called automatically."""
289
+ return False
iplotx/version.py CHANGED
@@ -2,4 +2,4 @@
2
2
  iplotx version information module.
3
3
  """
4
4
 
5
- __version__ = "1.5.1"
5
+ __version__ = "1.7.0"
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iplotx
3
- Version: 1.5.1
4
- Summary: Plot networkx from igraph and networkx.
3
+ Version: 1.7.0
4
+ Summary: Universal network and tree visualisation library.
5
5
  Project-URL: Homepage, https://github.com/fabilab/iplotx
6
6
  Project-URL: Documentation, https://readthedocs.org/iplotx
7
7
  Project-URL: Repository, https://github.com/fabilab/iplotx.git
@@ -41,7 +41,7 @@ Description-Content-Type: text/markdown
41
41
  [![RTD](https://readthedocs.org/projects/iplotx/badge/?version=latest)](https://iplotx.readthedocs.io/en/latest/)
42
42
  [![Coverage Status](https://coveralls.io/repos/github/fabilab/iplotx/badge.svg?branch=main)](https://coveralls.io/github/fabilab/iplotx?branch=main)
43
43
  ![pylint](assets/pylint.svg)
44
- [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.16599333.svg)](https://doi.org/10.5281/zenodo.16599333)
44
+ [DOI](https://f1000research.com/articles/14-1377)
45
45
 
46
46
 
47
47
  # iplotx
@@ -90,10 +90,10 @@ See [readthedocs](https://iplotx.readthedocs.io/en/latest/) for the full documen
90
90
  See [gallery](https://iplotx.readthedocs.io/en/latest/gallery/index.html).
91
91
 
92
92
  ## Citation
93
- If you use `iplotx` for publication figures, please cite the [zenodo preprint](https://doi.org/10.5281/zenodo.16599333):
93
+ If you use `iplotx` for publication figures, please cite:
94
94
 
95
95
  ```
96
- F. Zanini. (2025). Unified network visualisation in Python. Zenodo [PREPRINT]. https://doi.org/10.5281/zenodo.16599333
96
+ F. Zanini. A universal tool for visualisation of networks and trees in Python. F1000Research 2025, 14:1377. https://doi.org/10.12688/f1000research.173131.1
97
97
  ```
98
98
 
99
99
  ## Features
@@ -1,17 +1,17 @@
1
1
  iplotx/__init__.py,sha256=RKlRSSEAv2qECd6rCiovdLDu-4k1eXMGCOCPt0xwpFA,523
2
2
  iplotx/artists.py,sha256=2dBDT240zGwKb6tIc_y9pXeyU3LuYeF9wjj2tvi4KJo,730
3
3
  iplotx/label.py,sha256=7eS8ByadrhdIFOZz19U4VrS-oXY_ndFYNB-D4RZbFqI,9573
4
- iplotx/plotting.py,sha256=RyAdvaHSpuyJkf8DF3SJBvEXBrPmJEdovUyAlBWQvqU,16228
4
+ iplotx/plotting.py,sha256=QlXCh3t1J9YmzkqrS6ozwSilFxZ1hwBHHWW-kpd-7zM,17679
5
5
  iplotx/typing.py,sha256=QLdzV358IiD1CFe88MVp0D77FSx5sSAVUmM_2WPPE8I,1463
6
- iplotx/version.py,sha256=2-ElWE7kiH17_8qfp3S7cxPYli-UBakrm7tAh8DbG2E,66
6
+ iplotx/version.py,sha256=7dTkHVHx2G_FnFiWdcEX1gkeNeCO9nu53SE10IwwwKM,66
7
7
  iplotx/vertex.py,sha256=Ta48M_6ZT8xKQWdI5XHiRxTt2LlJ9vshiDk34OzKYlY,16585
8
8
  iplotx/art3d/vertex.py,sha256=Xf8Um30X2doCd8KdNN7332F6BxC4k72Mb_GeRAuzQfQ,2545
9
9
  iplotx/art3d/edge/__init__.py,sha256=uw1U_mMXqcZAvea-7JbU1PUKULQD1CMMrbwY02tiWRQ,8529
10
10
  iplotx/art3d/edge/arrow.py,sha256=14BFXY9kDOUGPZl2fMD9gRVGyaaN5kyd-l6ikBg6WHU,3601
11
11
  iplotx/art3d/edge/geometry.py,sha256=76VUmpPG-4Mls7x_994dMwdDPrWWnjT7nHJsHfwK_hA,2467
12
- iplotx/edge/__init__.py,sha256=8iHtkrEaxseh308VWlTgbZ7OJECqkRwSq-oJzejxH5U,26837
12
+ iplotx/edge/__init__.py,sha256=mp_JRGeJWPXZNpQ6vTgTdzgVO1YxcZMKuVKarJGuLnY,27522
13
13
  iplotx/edge/arrow.py,sha256=ymup2YT_0GVYMtZw_DSKrZqFHG_ysYteEhmoL6T8Mu4,17563
14
- iplotx/edge/geometry.py,sha256=Vt1Y_wH2Fto_rgrQbuhXUzsfBpjQLti8Qws-oAGLcUw,19745
14
+ iplotx/edge/geometry.py,sha256=Qyi7Q7sOGAFXU6gFeWFLm6OoGetEasrfv8HzgSWO2gY,20210
15
15
  iplotx/edge/leaf.py,sha256=SyGMv2PIOoH0pey8-aMVaZheK3hNe1Qz_okcyWbc4E4,4268
16
16
  iplotx/edge/ports.py,sha256=BpkbiEhX4mPBBAhOv4jcKFG4Y8hxXz5GRtVLCC0jbtI,1235
17
17
  iplotx/ingest/__init__.py,sha256=k1Q-7lSdotMR4RkF1x0t19RFsTknohX0L507Dw69WyU,5035
@@ -41,8 +41,8 @@ iplotx/tree/cascades.py,sha256=Wwqhy46QGeb4LNGUuz_-bgNWUMz6PFzs_dIxIb1dtqc,8394
41
41
  iplotx/tree/scalebar.py,sha256=Yxt_kF8JdTwKGa8Jzqt3qVePPK5ZBG8P0EiONrsh3E8,11863
42
42
  iplotx/utils/geometry.py,sha256=6RrC6qaB0-1vIk1LhGA4CfsiMd-9JNniSPyL_l9mshE,9245
43
43
  iplotx/utils/internal.py,sha256=WWfcZDGK8Ut1y_tOHRGg9wSqY1bwSeLQO7dHM_8Tvwo,107
44
- iplotx/utils/matplotlib.py,sha256=p_53Oamof0RI4mtV8HrdDtZbgVqUxeUZ_KDvLZSiBUQ,8604
44
+ iplotx/utils/matplotlib.py,sha256=T-jiqy8KxF1Q4BofT1rZbbdtmSC-j_kjNRcOg_IZpYM,8720
45
45
  iplotx/utils/style.py,sha256=vyNP80nDYVinqm6_9ltCJCtjK35ZcGlHvOskNv3eQBc,4225
46
- iplotx-1.5.1.dist-info/METADATA,sha256=8-x0TGoqdL4oRbC3MtMnYii8ZNbiRZmATGze3RbW3mE,5407
47
- iplotx-1.5.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
48
- iplotx-1.5.1.dist-info/RECORD,,
46
+ iplotx-1.7.0.dist-info/METADATA,sha256=gItmBkiLmtBY73aY3IIycXX61yghAdv0wBmMXsDBpSw,5333
47
+ iplotx-1.7.0.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
48
+ iplotx-1.7.0.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.27.0
2
+ Generator: hatchling 1.28.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any