iplotx 0.2.0__tar.gz → 0.3.0__tar.gz

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.
Files changed (157) hide show
  1. {iplotx-0.2.0 → iplotx-0.3.0}/.github/workflows/publish.yml +20 -7
  2. {iplotx-0.2.0 → iplotx-0.3.0}/PKG-INFO +16 -3
  3. {iplotx-0.2.0 → iplotx-0.3.0}/README.md +7 -2
  4. iplotx-0.3.0/assets/pylint.svg +23 -0
  5. {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/conf.py +2 -0
  6. {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/index.md +3 -1
  7. {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/sg_execution_times.rst +22 -4
  8. iplotx-0.3.0/gallery/plot_animation.py +61 -0
  9. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_biopython_tree.py +1 -0
  10. iplotx-0.3.0/gallery/plot_company_structure.py +72 -0
  11. iplotx-0.3.0/gallery/plot_edit_artists.py +60 -0
  12. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_ete4.py +15 -2
  13. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_loops.py +4 -4
  14. iplotx-0.3.0/gallery/plot_mouse_hover.py +67 -0
  15. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_simple_path.py +2 -2
  16. iplotx-0.3.0/gallery/plot_tree_node_background.py +55 -0
  17. iplotx-0.3.0/gallery/plot_trees_of_trees.py +83 -0
  18. iplotx-0.3.0/iplotx/cascades.py +223 -0
  19. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/edge/__init__.py +180 -420
  20. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/edge/arrow.py +20 -20
  21. iplotx-0.3.0/iplotx/edge/geometry.py +448 -0
  22. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/edge/ports.py +7 -2
  23. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/groups.py +24 -14
  24. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/ingest/__init__.py +12 -4
  25. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/ingest/heuristics.py +1 -3
  26. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/ingest/providers/network/igraph.py +4 -2
  27. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/ingest/providers/network/networkx.py +4 -2
  28. iplotx-0.3.0/iplotx/ingest/providers/tree/biopython.py +47 -0
  29. iplotx-0.3.0/iplotx/ingest/providers/tree/cogent3.py +41 -0
  30. iplotx-0.3.0/iplotx/ingest/providers/tree/ete4.py +44 -0
  31. iplotx-0.3.0/iplotx/ingest/providers/tree/skbio.py +41 -0
  32. iplotx-0.3.0/iplotx/ingest/typing.py +303 -0
  33. iplotx-0.3.0/iplotx/label.py +209 -0
  34. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/layout.py +57 -36
  35. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/network.py +9 -8
  36. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/plotting.py +6 -3
  37. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/style.py +36 -10
  38. iplotx-0.3.0/iplotx/tree.py +493 -0
  39. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/typing.py +19 -0
  40. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/version.py +1 -1
  41. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/vertex.py +122 -35
  42. {iplotx-0.2.0 → iplotx-0.3.0}/pyproject.toml +8 -0
  43. iplotx-0.3.0/scripts/update_pylint_badge.sh +12 -0
  44. iplotx-0.3.0/tests/baseline_images/test_biopython/leaf_labels.png +0 -0
  45. iplotx-0.3.0/tests/baseline_images/test_biopython/leaf_labels_hmargin.png +0 -0
  46. iplotx-0.3.0/tests/baseline_images/test_biopython/tree_radial.png +0 -0
  47. iplotx-0.3.0/tests/baseline_images/test_cogent3/leaf_labels.png +0 -0
  48. iplotx-0.3.0/tests/baseline_images/test_cogent3/leaf_labels_hmargin.png +0 -0
  49. iplotx-0.3.0/tests/baseline_images/test_cogent3/tree_radial.png +0 -0
  50. iplotx-0.3.0/tests/baseline_images/test_ete4/leaf_labels.png +0 -0
  51. iplotx-0.3.0/tests/baseline_images/test_ete4/leaf_labels_hmargin.png +0 -0
  52. iplotx-0.3.0/tests/baseline_images/test_ete4/tree_radial.png +0 -0
  53. iplotx-0.3.0/tests/baseline_images/test_networkx/simple_graph.png +0 -0
  54. iplotx-0.3.0/tests/baseline_images/test_skbio/leaf_labels.png +0 -0
  55. iplotx-0.3.0/tests/baseline_images/test_skbio/leaf_labels_hmargin.png +0 -0
  56. iplotx-0.3.0/tests/baseline_images/test_skbio/tree_radial.png +0 -0
  57. {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_biopython.py +1 -1
  58. {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_cogent3.py +1 -1
  59. {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_ete4.py +1 -1
  60. {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_igraph.py +2 -2
  61. {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_networkx.py +1 -1
  62. {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_skbio.py +1 -1
  63. iplotx-0.2.0/iplotx/ingest/providers/tree/biopython.py +0 -105
  64. iplotx-0.2.0/iplotx/ingest/providers/tree/cogent3.py +0 -112
  65. iplotx-0.2.0/iplotx/ingest/providers/tree/ete4.py +0 -112
  66. iplotx-0.2.0/iplotx/ingest/providers/tree/skbio.py +0 -112
  67. iplotx-0.2.0/iplotx/ingest/typing.py +0 -100
  68. iplotx-0.2.0/iplotx/label.py +0 -127
  69. iplotx-0.2.0/iplotx/tree.py +0 -285
  70. iplotx-0.2.0/tests/baseline_images/test_biopython/leaf_labels.png +0 -0
  71. iplotx-0.2.0/tests/baseline_images/test_biopython/leaf_labels_hmargin.png +0 -0
  72. iplotx-0.2.0/tests/baseline_images/test_biopython/tree_radial.png +0 -0
  73. iplotx-0.2.0/tests/baseline_images/test_cogent3/leaf_labels.png +0 -0
  74. iplotx-0.2.0/tests/baseline_images/test_cogent3/leaf_labels_hmargin.png +0 -0
  75. iplotx-0.2.0/tests/baseline_images/test_cogent3/tree_radial.png +0 -0
  76. iplotx-0.2.0/tests/baseline_images/test_ete4/leaf_labels.png +0 -0
  77. iplotx-0.2.0/tests/baseline_images/test_ete4/leaf_labels_hmargin.png +0 -0
  78. iplotx-0.2.0/tests/baseline_images/test_ete4/tree_radial.png +0 -0
  79. iplotx-0.2.0/tests/baseline_images/test_networkx/simple_graph.png +0 -0
  80. iplotx-0.2.0/tests/baseline_images/test_skbio/leaf_labels.png +0 -0
  81. iplotx-0.2.0/tests/baseline_images/test_skbio/leaf_labels_hmargin.png +0 -0
  82. iplotx-0.2.0/tests/baseline_images/test_skbio/tree_radial.png +0 -0
  83. {iplotx-0.2.0 → iplotx-0.3.0}/.github/workflows/test.yml +0 -0
  84. {iplotx-0.2.0 → iplotx-0.3.0}/.gitignore +0 -0
  85. {iplotx-0.2.0 → iplotx-0.3.0}/.readthedocs.yaml +0 -0
  86. {iplotx-0.2.0 → iplotx-0.3.0}/LICENSE +0 -0
  87. {iplotx-0.2.0 → iplotx-0.3.0}/MANIFEST.in +0 -0
  88. {iplotx-0.2.0 → iplotx-0.3.0}/docs/Makefile +0 -0
  89. {iplotx-0.2.0 → iplotx-0.3.0}/docs/make.bat +0 -0
  90. {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/_static/graph_basic.png +0 -0
  91. {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/_templates/layout.html +0 -0
  92. {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/api.md +0 -0
  93. {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/images/sphx_glr_plot_basic_001.png +0 -0
  94. {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/images/thumb/sphx_glr_plot_basic_thumb.png +0 -0
  95. {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/style.md +0 -0
  96. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/GALLERY_HEADER.rst +0 -0
  97. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/chess_masters_WCC.pgn.bz2 +0 -0
  98. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/knuth_miles.txt.gz +0 -0
  99. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_basic.py +0 -0
  100. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_big_curves.py +0 -0
  101. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_chess_masters.py +0 -0
  102. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_cliques.py +0 -0
  103. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_cluster_layout.py +0 -0
  104. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_cogent3_tree.py +0 -0
  105. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_complex.py +0 -0
  106. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_dag.py +0 -0
  107. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_directed.py +0 -0
  108. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_four_grids.py +0 -0
  109. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_grouping.py +0 -0
  110. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_house.py +0 -0
  111. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_knuth_miles.py +0 -0
  112. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_labels_and_colors.py +0 -0
  113. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_max_bipartite_matching.py +0 -0
  114. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_minimum_spanning_trees.py +0 -0
  115. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_multipartite_layout.py +0 -0
  116. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_parallel_igraph_networkx.py +0 -0
  117. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_ports.py +0 -0
  118. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_shortest_path.py +0 -0
  119. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_simple_networkx.py +0 -0
  120. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_skbio_tree.py +0 -0
  121. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_style.py +0 -0
  122. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_traveling_salesman.py +0 -0
  123. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_voronoi.py +0 -0
  124. {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_with_colorbar.py +0 -0
  125. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/__init__.py +0 -0
  126. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/utils/geometry.py +0 -0
  127. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/utils/internal.py +0 -0
  128. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/utils/matplotlib.py +0 -0
  129. {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/utils/style.py +0 -0
  130. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_biopython/tree_basic.png +0 -0
  131. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_cogent3/tree_basic.png +0 -0
  132. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_ete4/tree_basic.png +0 -0
  133. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/clustering_directed.png +0 -0
  134. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/clustering_directed_large.png +0 -0
  135. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_basic.png +0 -0
  136. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_directed.png +0 -0
  137. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_directed_curved_loops.png +0 -0
  138. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_edit_children.png +0 -0
  139. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_labels.png +0 -0
  140. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_layout_attribute.png +0 -0
  141. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_null.png +0 -0
  142. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_squares_directed.png +0 -0
  143. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/igraph_layout_object.png +0 -0
  144. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/multigraph_with_curved_edges_undirected.png +0 -0
  145. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/cluster-layout.png +0 -0
  146. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/complex.png +0 -0
  147. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/directed_graph.png +0 -0
  148. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/directed_graph_with_colorbar.png +0 -0
  149. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/empty_graph.png +0 -0
  150. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/flat_style.png +0 -0
  151. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/house_with_colors.png +0 -0
  152. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/labels_and_colors.png +0 -0
  153. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/shortest_path.png +0 -0
  154. {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_skbio/tree_basic.png +0 -0
  155. {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_style.py +0 -0
  156. {iplotx-0.2.0 → iplotx-0.3.0}/tests/utils.py +0 -0
  157. {iplotx-0.2.0 → iplotx-0.3.0}/uv.lock +0 -0
@@ -19,18 +19,31 @@ jobs:
19
19
  release-build:
20
20
  runs-on: ubuntu-latest
21
21
 
22
+ strategy:
23
+ matrix:
24
+ python-version: ["3.11"]
25
+
22
26
  steps:
23
27
  - uses: actions/checkout@v4
24
28
 
25
- - uses: actions/setup-python@v5
29
+ - name: Install uv
30
+ uses: astral-sh/setup-uv@v5
31
+ with:
32
+ python-version: ${{ matrix.python-version }}
33
+
34
+ - name: Set up Python ${{ matrix.python-version }}
35
+ uses: actions/setup-python@v5
26
36
  with:
27
- python-version: "3.x"
37
+ python-version: ${{ matrix.python-version }}
28
38
 
29
- - name: Build release distributions
39
+ - name: Install the project
30
40
  run: |
31
- # NOTE: put your own distribution build steps here.
32
- python -m pip install build
33
- python -m build
41
+ # Make sure you are in the right environment
42
+ uv sync
43
+ # Clean dist/
44
+ rm -f dist/*
45
+ # Build into dist/
46
+ uv build
34
47
 
35
48
  - name: Upload distributions
36
49
  uses: actions/upload-artifact@v4
@@ -51,7 +64,7 @@ jobs:
51
64
  environment:
52
65
  name: pypi
53
66
  # OPTIONAL: uncomment and update to include your PyPI project URL in the deployment status:
54
- # url: https://pypi.org/p/YOURPROJECT
67
+ url: https://pypi.org/p/iplotx
55
68
  #
56
69
  # ALTERNATIVE: if your GitHub Release name is the PyPI project version string
57
70
  # ALTERNATIVE: exactly, uncomment the following line instead:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iplotx
3
- Version: 0.2.0
3
+ Version: 0.3.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
@@ -11,12 +11,20 @@ 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
13
  Keywords: graph,network,plotting,visualisation
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: Education
17
+ Classifier: Intended Audience :: Science/Research
14
18
  Classifier: License :: OSI Approved :: MIT License
19
+ Classifier: Natural Language :: English
15
20
  Classifier: Operating System :: OS Independent
16
21
  Classifier: Programming Language :: Python :: 3
17
22
  Classifier: Programming Language :: Python :: 3.11
18
23
  Classifier: Programming Language :: Python :: 3.12
19
24
  Classifier: Programming Language :: Python :: 3.13
25
+ Classifier: Topic :: Scientific/Engineering :: Visualization
26
+ Classifier: Topic :: System :: Networking
27
+ Classifier: Typing :: Typed
20
28
  Requires-Python: >=3.11
21
29
  Requires-Dist: matplotlib>=2.0.0
22
30
  Requires-Dist: numpy>=2.0.0
@@ -31,11 +39,12 @@ Description-Content-Type: text/markdown
31
39
  ![Github Actions](https://github.com/fabilab/iplotx/actions/workflows/test.yml/badge.svg)
32
40
  ![PyPI - Version](https://img.shields.io/pypi/v/iplotx)
33
41
  ![RTD](https://readthedocs.org/projects/iplotx/badge/?version=latest)
42
+ ![pylint](assets/pylint.svg)
34
43
 
35
44
  # iplotx
36
45
  Plotting networks from igraph and networkx.
37
46
 
38
- **NOTE**: This is currently alpha quality software. The API and functionality will break constantly, so use at your own risk. That said, if you have things you would like to see improved, please open a GitHub issue.
47
+ **NOTE**: This is currently beta quality software. The API and functionality are settling in and might break occasionally.
39
48
 
40
49
  ## Installation
41
50
  ```bash
@@ -68,9 +77,13 @@ See [gallery](https://iplotx.readthedocs.io/en/latest/gallery/index.html).
68
77
  - Support storing the plot to disk thanks to the many matplotlib backends (SVG, PNG, PDF, etc.). ✅
69
78
  - Support flexible yet easy styling. ✅
70
79
  - Efficient plotting of large graphs using matplotlib's collection functionality. ✅
80
+ - Support editing plotting elements after the plot is created, e.g. changing node colors, labels, etc. ✅
81
+ - Support animations, e.g. showing the evolution of a network over time. ✅
82
+ - Support mouse interaction, e.g. hovering over or clicking on nodes and edges to get information about them. ✅
71
83
  - Support trees from special libraries such as ete3, biopython, etc. This will need a dedicated function and layouting. ✅
72
- - Support animations, e.g. showing the evolution of a network over time. 🏗️
73
84
  - Support uni- and bi-directional communication between graph object and plot object.🏗️
74
85
 
86
+ **NOTE:** The last item can probably be achieved already by using `matplotlib`'s existing callback functionality. It is currently untested, but if you manage to get it to work on your graph let me know and I'll add it to the examples (with credit).
87
+
75
88
  ## Authors
76
89
  Fabio Zanini (https://fabilab.org)
@@ -1,11 +1,12 @@
1
1
  ![Github Actions](https://github.com/fabilab/iplotx/actions/workflows/test.yml/badge.svg)
2
2
  ![PyPI - Version](https://img.shields.io/pypi/v/iplotx)
3
3
  ![RTD](https://readthedocs.org/projects/iplotx/badge/?version=latest)
4
+ ![pylint](assets/pylint.svg)
4
5
 
5
6
  # iplotx
6
7
  Plotting networks from igraph and networkx.
7
8
 
8
- **NOTE**: This is currently alpha quality software. The API and functionality will break constantly, so use at your own risk. That said, if you have things you would like to see improved, please open a GitHub issue.
9
+ **NOTE**: This is currently beta quality software. The API and functionality are settling in and might break occasionally.
9
10
 
10
11
  ## Installation
11
12
  ```bash
@@ -38,9 +39,13 @@ See [gallery](https://iplotx.readthedocs.io/en/latest/gallery/index.html).
38
39
  - Support storing the plot to disk thanks to the many matplotlib backends (SVG, PNG, PDF, etc.). ✅
39
40
  - Support flexible yet easy styling. ✅
40
41
  - Efficient plotting of large graphs using matplotlib's collection functionality. ✅
42
+ - Support editing plotting elements after the plot is created, e.g. changing node colors, labels, etc. ✅
43
+ - Support animations, e.g. showing the evolution of a network over time. ✅
44
+ - Support mouse interaction, e.g. hovering over or clicking on nodes and edges to get information about them. ✅
41
45
  - Support trees from special libraries such as ete3, biopython, etc. This will need a dedicated function and layouting. ✅
42
- - Support animations, e.g. showing the evolution of a network over time. 🏗️
43
46
  - Support uni- and bi-directional communication between graph object and plot object.🏗️
44
47
 
48
+ **NOTE:** The last item can probably be achieved already by using `matplotlib`'s existing callback functionality. It is currently untested, but if you manage to get it to work on your graph let me know and I'll add it to the examples (with credit).
49
+
45
50
  ## Authors
46
51
  Fabio Zanini (https://fabilab.org)
@@ -0,0 +1,23 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg xmlns="http://www.w3.org/2000/svg" width="80" height="20">
3
+ <linearGradient id="b" x2="0" y2="100%">
4
+ <stop offset="0" stop-color="#bbb" stop-opacity=".1"/>
5
+ <stop offset="1" stop-opacity=".1"/>
6
+ </linearGradient>
7
+ <mask id="anybadge_1">
8
+ <rect width="80" height="20" rx="3" fill="#fff"/>
9
+ </mask>
10
+ <g mask="url(#anybadge_1)">
11
+ <path fill="#555" d="M0 0h44v20H0z"/>
12
+ <path fill="#4C1" d="M44 0h36v20H44z"/>
13
+ <path fill="url(#b)" d="M0 0h80v20H0z"/>
14
+ </g>
15
+ <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
16
+ <text x="23.0" y="15" fill="#010101" fill-opacity=".3">pylint</text>
17
+ <text x="22.0" y="14">pylint</text>
18
+ </g>
19
+ <g fill="#fff" text-anchor="middle" font-family="DejaVu Sans,Verdana,Geneva,sans-serif" font-size="11">
20
+ <text x="63.0" y="15" fill="#010101" fill-opacity=".3">9.13</text>
21
+ <text x="62.0" y="14">9.13</text>
22
+ </g>
23
+ </svg>
@@ -49,6 +49,8 @@ myst_enable_extensions = ["colon_fence"]
49
49
  sphinx_gallery_conf = {
50
50
  "examples_dirs": "../../gallery", # path to your example scripts
51
51
  "gallery_dirs": "./gallery", # path to where to save gallery generated output
52
+ #'matplotlib_animations': (True, 'mp4'),
53
+ "matplotlib_animations": True,
52
54
  }
53
55
 
54
56
  source_suffix = {
@@ -74,13 +74,15 @@ See <project:gallery/index.rst> for examples of plots made with `iplotx`. Feel f
74
74
  - compatibility with many GUI frameworks (e.g. Qt, GTK, Tkinter) thanks to `matplotlib`
75
75
  - data-driven axes autoscaling
76
76
  - consistent behaviour upon zooming and panning
77
- - correct HiDPI scaling (e.g. retina screens)
77
+ - correct HiDPI scaling (e.g. retina screens) including for vertex sizes, arrow sizes, and edge offsets
78
78
  - a consistent `matplotlib` artist hierarchy
79
79
  - post-plot editability (e.g. for animations)
80
80
  - plays well with other charting tools (e.g. `seaborn`)
81
81
  - chainable style contexts
82
82
  - vertex clusterings and covers with convex hulls and rounding
83
83
  - a plugin mechanism for additional libraries (WIP)
84
+ - animations (see <project:gallery/plot_animation.rst>)
85
+ - mouse/keyboard interaction and events (e.g. hover, click, see <project:gallery/plot_mouse_hover.rst>)
84
86
  - ... and probably more by the time you read this.
85
87
 
86
88
  ## Styles
@@ -6,7 +6,7 @@
6
6
 
7
7
  Computation times
8
8
  =================
9
- **00:00.061** total execution time for 30 files **from all galleries**:
9
+ **00:01.212** total execution time for 36 files **from all galleries**:
10
10
 
11
11
  .. container::
12
12
 
@@ -32,8 +32,11 @@ Computation times
32
32
  * - Example
33
33
  - Time
34
34
  - Mem (MB)
35
- * - :ref:`sphx_glr_gallery_plot_ports.py` (``../../gallery/plot_ports.py``)
36
- - 00:00.061
35
+ * - :ref:`sphx_glr_gallery_plot_ete4.py` (``../../gallery/plot_ete4.py``)
36
+ - 00:01.212
37
+ - 0.0
38
+ * - :ref:`sphx_glr_gallery_plot_animation.py` (``../../gallery/plot_animation.py``)
39
+ - 00:00.000
37
40
  - 0.0
38
41
  * - :ref:`sphx_glr_gallery_plot_basic.py` (``../../gallery/plot_basic.py``)
39
42
  - 00:00.000
@@ -56,6 +59,9 @@ Computation times
56
59
  * - :ref:`sphx_glr_gallery_plot_cogent3_tree.py` (``../../gallery/plot_cogent3_tree.py``)
57
60
  - 00:00.000
58
61
  - 0.0
62
+ * - :ref:`sphx_glr_gallery_plot_company_structure.py` (``../../gallery/plot_company_structure.py``)
63
+ - 00:00.000
64
+ - 0.0
59
65
  * - :ref:`sphx_glr_gallery_plot_complex.py` (``../../gallery/plot_complex.py``)
60
66
  - 00:00.000
61
67
  - 0.0
@@ -65,7 +71,7 @@ Computation times
65
71
  * - :ref:`sphx_glr_gallery_plot_directed.py` (``../../gallery/plot_directed.py``)
66
72
  - 00:00.000
67
73
  - 0.0
68
- * - :ref:`sphx_glr_gallery_plot_ete4.py` (``../../gallery/plot_ete4.py``)
74
+ * - :ref:`sphx_glr_gallery_plot_edit_artists.py` (``../../gallery/plot_edit_artists.py``)
69
75
  - 00:00.000
70
76
  - 0.0
71
77
  * - :ref:`sphx_glr_gallery_plot_four_grids.py` (``../../gallery/plot_four_grids.py``)
@@ -92,12 +98,18 @@ Computation times
92
98
  * - :ref:`sphx_glr_gallery_plot_minimum_spanning_trees.py` (``../../gallery/plot_minimum_spanning_trees.py``)
93
99
  - 00:00.000
94
100
  - 0.0
101
+ * - :ref:`sphx_glr_gallery_plot_mouse_hover.py` (``../../gallery/plot_mouse_hover.py``)
102
+ - 00:00.000
103
+ - 0.0
95
104
  * - :ref:`sphx_glr_gallery_plot_multipartite_layout.py` (``../../gallery/plot_multipartite_layout.py``)
96
105
  - 00:00.000
97
106
  - 0.0
98
107
  * - :ref:`sphx_glr_gallery_plot_parallel_igraph_networkx.py` (``../../gallery/plot_parallel_igraph_networkx.py``)
99
108
  - 00:00.000
100
109
  - 0.0
110
+ * - :ref:`sphx_glr_gallery_plot_ports.py` (``../../gallery/plot_ports.py``)
111
+ - 00:00.000
112
+ - 0.0
101
113
  * - :ref:`sphx_glr_gallery_plot_shortest_path.py` (``../../gallery/plot_shortest_path.py``)
102
114
  - 00:00.000
103
115
  - 0.0
@@ -116,6 +128,12 @@ Computation times
116
128
  * - :ref:`sphx_glr_gallery_plot_traveling_salesman.py` (``../../gallery/plot_traveling_salesman.py``)
117
129
  - 00:00.000
118
130
  - 0.0
131
+ * - :ref:`sphx_glr_gallery_plot_tree_node_background.py` (``../../gallery/plot_tree_node_background.py``)
132
+ - 00:00.000
133
+ - 0.0
134
+ * - :ref:`sphx_glr_gallery_plot_trees_of_trees.py` (``../../gallery/plot_trees_of_trees.py``)
135
+ - 00:00.000
136
+ - 0.0
119
137
  * - :ref:`sphx_glr_gallery_plot_voronoi.py` (``../../gallery/plot_voronoi.py``)
120
138
  - 00:00.000
121
139
  - 0.0
@@ -0,0 +1,61 @@
1
+ """
2
+ Animations
3
+ ==========
4
+
5
+ This tutorial shows how to animate `iplotx` visualizations using `matplotlib.animation.FuncAnimation`.
6
+
7
+ For illustration purposes, we will animate a simple directed graph, rotating it around its center. We also modify the opacity of the vertices and edges, just for fun.
8
+ """
9
+
10
+ import matplotlib.pyplot as plt
11
+ import numpy as np
12
+ import matplotlib.animation as animation
13
+ import igraph as ig
14
+ import iplotx as ipx
15
+
16
+ g = ig.Graph.Ring(3, directed=True)
17
+ layout = np.asarray(g.layout("circle").coords)
18
+
19
+ # The animation will rotate the layout of the graph
20
+ thetas = np.linspace(0, 2 * np.pi, 101)[:-1]
21
+
22
+ fig, ax = plt.subplots()
23
+ art = ipx.network(g, ax=ax, layout=layout, aspect=1)[0]
24
+ ax.set(xlim=[-2, 2], ylim=[-2, 2])
25
+
26
+
27
+ def rotate(vector, theta):
28
+ """Rotate a 2D vector by an angle theta (in radians) clockwise."""
29
+ return vector @ np.array(
30
+ [
31
+ [np.cos(theta), -np.sin(theta)],
32
+ [np.sin(theta), np.cos(theta)],
33
+ ],
34
+ )
35
+
36
+
37
+ def update(frame):
38
+ # for each frame, update the vertex positions
39
+ theta = thetas[frame]
40
+
41
+ # The new layout is the old layout rotated by theta, clockwise
42
+ layout_new = rotate(layout, theta)
43
+
44
+ # Also change transparency, slower
45
+ alpha_vertices = 1 - np.abs(np.sin(theta / 2))
46
+ alpha_edges = 0.25 + 0.75 * np.abs(np.sin(theta / 2))
47
+
48
+ # Edit the vertices' positions
49
+ art.get_vertices().set_offsets(layout_new)
50
+ art.get_vertices().set_alpha(alpha_vertices)
51
+ art.get_edges().set_alpha(alpha_edges)
52
+ return (art.get_vertices(), art.get_edges())
53
+
54
+
55
+ # Run the animation
56
+ ani = animation.FuncAnimation(
57
+ fig=fig,
58
+ func=update,
59
+ frames=len(thetas),
60
+ interval=30,
61
+ )
@@ -28,6 +28,7 @@ ipx.plotting.tree(
28
28
  # Moreover, the plot can be customised further using hmargin (horizontal label margin)
29
29
  # and some `matplotlib` settings.
30
30
 
31
+ # sphinx_gallery_thumbnail_number = 2
31
32
  leaf_labels = {leaf: f"Species {i+1}" for i, leaf in enumerate(tree.get_terminals())}
32
33
  fig, ax = plt.subplots(figsize=(4, 4))
33
34
  ipx.plotting.tree(
@@ -0,0 +1,72 @@
1
+ """
2
+ Company structure
3
+ =================
4
+
5
+ This example shows how to use `iplotx` to visualise simple logical relationships, for instance the organisational chart of a company.
6
+ """
7
+
8
+ import networkx as nx
9
+ import matplotlib.pyplot as plt
10
+ import iplotx as ipx
11
+
12
+ g = nx.DiGraph()
13
+ g.add_edges_from(
14
+ [
15
+ ("CEO", "Manager 1"),
16
+ ("CEO", "Manager 2"),
17
+ ("CEO", "Manager 3"),
18
+ ("Manager 1", "Employee 1"),
19
+ ("Manager 1", "Employee 2"),
20
+ ("Manager 2", "Employee 3"),
21
+ ("Manager 2", "Employee 4"),
22
+ ("Manager 3", "Employee 4"),
23
+ ]
24
+ )
25
+ layout = {
26
+ "CEO": [0, 0],
27
+ "Manager 1": [1, -1],
28
+ "Manager 2": [1, 0],
29
+ "Manager 3": [1, 1],
30
+ "Employee 1": [2, -1],
31
+ "Employee 2": [2, -0.5],
32
+ "Employee 3": [2, 0],
33
+ "Employee 4": [2, 0.5],
34
+ }
35
+ fig, ax = plt.subplots()
36
+ ipx.network(
37
+ g,
38
+ layout=layout,
39
+ ax=ax,
40
+ vertex_labels=True,
41
+ style="hollow",
42
+ vertex_marker="r",
43
+ edge_ports=[("e", "w")] * 8,
44
+ edge_curved=True,
45
+ edge_tension=[0.65] * 3 + [0.6] * 5,
46
+ margins=(0.08, 0.05),
47
+ )
48
+ # Show the layout top to bottom for clarity
49
+ ax.invert_yaxis()
50
+
51
+ # %%
52
+ # If you prefer a more squared look, you can use S-style waypoints with per-edge offsets:
53
+
54
+ fig, ax = plt.subplots()
55
+ ipx.network(
56
+ g,
57
+ layout=layout,
58
+ ax=ax,
59
+ vertex_labels=True,
60
+ style="hollow",
61
+ vertex_marker="r",
62
+ edge_ports=[("e", "w")] * 8,
63
+ edge_waypoints="xmidy0,xmidy1",
64
+ edge_offset=[(0, 0)] * 7 + [(0, -6)],
65
+ margins=(0.08, 0.05),
66
+ edge_linestyle=["-"] * 7 + ["--"],
67
+ )
68
+ ax.invert_yaxis()
69
+
70
+ # %%
71
+ # The `offset` edge style bypasses any layout coordinate system and acts in figure points directly.
72
+ # Combining edge offsets with noncartesian layout coordinate systems (e.g. `polar`) can lead to unexpected results.
@@ -0,0 +1,60 @@
1
+ """
2
+ Editing artists after plotting
3
+ ==============================
4
+
5
+ One of the strengths of `iplotx` is the support for editing artists after they have been plotted the first time without making a whole new figure.
6
+
7
+ In this example, we will change vertices, edges, arrows, etc. and check out how they look like.
8
+ """
9
+
10
+ # %%
11
+ # This is the vanilla version, taken from the "Ports" gallery example:
12
+
13
+ import igraph as ig
14
+ import numpy as np
15
+ import matplotlib.pyplot as plt
16
+ import iplotx as ipx
17
+
18
+ g = ig.Graph.Ring(3, directed=True)
19
+
20
+ artist = ipx.network(
21
+ g,
22
+ layout="circle",
23
+ edge_curved=True,
24
+ edge_ports=[
25
+ ("n", "w"), # exit from the top, enter from the left
26
+ ("e", "s"), # exit from the right, enter from the bottom
27
+ ("n", "s"), # exit from the top, enter from the bottom
28
+ ],
29
+ edge_tension=[1.5, 1.8, 0.8],
30
+ edge_color=["tomato", "steelblue", "purple"],
31
+ )[0]
32
+
33
+ # %%
34
+ # Now we can change the vertex sizes:
35
+
36
+ # sphinx_gallery_thumbnail_number = 2
37
+ # SAME BLOCK AS BEFORE, ONLY NEEDED TO MAKE A NEW FIGURE
38
+ artist = ipx.network(
39
+ g,
40
+ layout="circle",
41
+ edge_curved=True,
42
+ edge_ports=[
43
+ ("n", "w"), # exit from the top, enter from the left
44
+ ("e", "s"), # exit from the right, enter from the bottom
45
+ ("n", "s"), # exit from the top, enter from the bottom
46
+ ],
47
+ edge_tension=[1.5, 1.8, 0.8],
48
+ edge_color=["tomato", "steelblue", "purple"],
49
+ )[0]
50
+ # END OF SAME BLOCK
51
+
52
+ artist.get_vertices().set_sizes([5, 5, 40])
53
+ artist.get_edges().set_ports(
54
+ [
55
+ ("n", "n"),
56
+ ("w", None),
57
+ ("e", "s"),
58
+ ]
59
+ )
60
+ artist.get_edges().set_tension([1.3, 0.3, 0.5])
@@ -21,19 +21,32 @@ ipx.plotting.tree(
21
21
 
22
22
  # %%
23
23
  # `iplotx` can compute a radial tree layout as well, and usual style modifications
24
- # work for trees same as networks:
24
+ # work for trees same as networks. Moreover, trees have a layout style option to
25
+ # choose the starting angle and angular span of the radial layout.
25
26
 
27
+ # sphinx_gallery_thumbnail_number = 2
26
28
  ipx.plotting.tree(
27
29
  tree,
28
30
  layout="radial",
31
+ orientation="right",
29
32
  style=[
30
33
  "tree",
31
34
  {
32
35
  "edge": {
33
- "color": "black",
36
+ "color": "deeppink",
34
37
  "linewidth": 4,
35
38
  },
39
+ "layout": {
40
+ "start": -180,
41
+ "span": 180,
42
+ },
43
+ "vertex": {
44
+ "label": {
45
+ "hmargin": 15,
46
+ }
47
+ },
36
48
  },
37
49
  ],
50
+ vertex_labels={leaf: str(i + 1) for i, leaf in enumerate(tree.leaves())},
38
51
  aspect=1,
39
52
  )
@@ -37,7 +37,7 @@ ipx.plot(
37
37
  },
38
38
  "edge": {
39
39
  "linestyle": linestyle,
40
- "offset": 0,
40
+ "paralleloffset": 0,
41
41
  "looptension": 3.5,
42
42
  "arrow": {
43
43
  "marker": "|>",
@@ -61,7 +61,7 @@ ipx.plot(
61
61
  vertex_edgecolor="none",
62
62
  vertex_label_color="black",
63
63
  edge_linestyle=linestyle,
64
- edge_offset=0,
64
+ edge_paralleloffset=0,
65
65
  edge_looptension=3.5,
66
66
  edge_arrow_marker="|>",
67
67
  ),
@@ -80,7 +80,7 @@ ipx.plot(
80
80
  vertex_edgecolor="none",
81
81
  vertex_label_color="black",
82
82
  edge_linestyle=linestyle,
83
- edge_offset=0,
83
+ edge_paralleloffset=0,
84
84
  edge_looptension=3.5,
85
85
  edge_arrow_marker="|>",
86
86
  )
@@ -94,7 +94,7 @@ with ipx.style.context(
94
94
  vertex_edgecolor="none",
95
95
  vertex_label_color="black",
96
96
  edge_linestyle=linestyle,
97
- edge_offset=0,
97
+ edge_paralleloffset=0,
98
98
  edge_looptension=3.5,
99
99
  edge_arrow_marker="|>",
100
100
  ):
@@ -0,0 +1,67 @@
1
+ """
2
+ Mouse event handling
3
+ ====================
4
+
5
+ This example shows how to interact with mouse events (e.g. hovering) in `iplotx`.
6
+
7
+ .. warning::
8
+ This example will run in a Python, IPython, or Jupyter session, however the
9
+ interactive functionality is not visible on the HTML page. Download the code
10
+ at the end of this page and run it in a local Python environment to see
11
+ the results.
12
+ """
13
+
14
+ import matplotlib.pyplot as plt
15
+ import numpy as np
16
+ import igraph as ig
17
+ import iplotx as ipx
18
+
19
+ g = ig.Graph.Ring(3, directed=True)
20
+
21
+ fig, ax = plt.subplots()
22
+ art = ipx.network(
23
+ g,
24
+ layout="circle",
25
+ ax=ax,
26
+ aspect=1,
27
+ )[0]
28
+ vertex_artist = art.get_vertices()
29
+
30
+ # Prepare an invisible annotation for hovering
31
+ annot = ax.annotate(
32
+ "",
33
+ xy=(0, 0),
34
+ xytext=(20, 20),
35
+ textcoords="offset points",
36
+ bbox=dict(boxstyle="round", fc=(0, 0, 0, 0.2)),
37
+ arrowprops=dict(arrowstyle="->"),
38
+ )
39
+ annot.set_visible(False)
40
+
41
+
42
+ def hover_callback(event):
43
+ """React to mouse hovering over vertices."""
44
+ if event.inaxes == ax:
45
+ vc = art.get_vertices()
46
+ cont, ind = vc.contains(event)
47
+ # If mouse is over a vertex, show the buble
48
+ if cont:
49
+ i = ind["ind"][0]
50
+ annot.xy = vc.get_offsets()[i]
51
+ annot.set_text(f"{i+1}")
52
+ annot.set_visible(True)
53
+ # Otherwise, hide the bubble
54
+ elif annot.get_visible():
55
+ annot.set_visible(False)
56
+ # If nothing changed, no need to redraw
57
+ else:
58
+ return
59
+
60
+ # Redraw to show/hide the bubble
61
+ fig.canvas.draw_idle()
62
+
63
+
64
+ fig.canvas.mpl_connect(
65
+ "motion_notify_event",
66
+ hover_callback,
67
+ )
@@ -10,12 +10,12 @@ import iplotx as ipx
10
10
 
11
11
  G = nx.path_graph(8)
12
12
  pos = nx.spring_layout(G, seed=47) # Seed layout for reproducibility
13
- ipx.plot(G, layout=pos)
13
+ ipx.network(G, layout=pos)
14
14
 
15
15
  # %%
16
16
  # We can change the color of the vertices and edges with a touch of style:
17
17
 
18
- ipx.plot(
18
+ ipx.network(
19
19
  G,
20
20
  layout=pos,
21
21
  style={
@@ -0,0 +1,55 @@
1
+ """
2
+ Tree cascades
3
+ =============
4
+
5
+ This example shows how to use `iplotx` to add cascading backgrounds to trees.
6
+ "Cascading" here means that each patch (rectangle/wedge/etc.) will cover a node
7
+ and all descendants, down to the leaves.
8
+ """
9
+
10
+ from Bio import Phylo
11
+ from io import StringIO
12
+ import matplotlib.pyplot as plt
13
+ import iplotx as ipx
14
+
15
+ # Make a tree from a string in Newick format
16
+ tree = next(
17
+ Phylo.NewickIO.parse(
18
+ StringIO(
19
+ "(()(()((()())(()()))))",
20
+ )
21
+ )
22
+ )
23
+
24
+ backgrounds = {
25
+ tree.get_nonterminals()[3]: "turquoise",
26
+ tree.get_terminals()[0]: "tomato",
27
+ tree.get_terminals()[1]: "purple",
28
+ }
29
+
30
+ ipx.plotting.tree(
31
+ tree,
32
+ vertex_cascade_facecolor=backgrounds,
33
+ )
34
+
35
+ # %%
36
+ # Cascading patches have a style option "extend" which affects whether the patches extend to the end of the deepest leaf:
37
+
38
+ ipx.plotting.tree(
39
+ tree,
40
+ layout="vertical",
41
+ vertex_cascade_facecolor=backgrounds,
42
+ vertex_cascade_extend=True,
43
+ )
44
+
45
+ # %%
46
+ # Cascading patches work with radial layouts as well:
47
+
48
+ # sphinx_gallery_thumbnail_number = 3
49
+ ipx.plotting.tree(
50
+ tree,
51
+ layout="radial",
52
+ vertex_cascade_facecolor=backgrounds,
53
+ vertex_cascade_extend=True,
54
+ aspect=1,
55
+ )