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.
- {iplotx-0.2.0 → iplotx-0.3.0}/.github/workflows/publish.yml +20 -7
- {iplotx-0.2.0 → iplotx-0.3.0}/PKG-INFO +16 -3
- {iplotx-0.2.0 → iplotx-0.3.0}/README.md +7 -2
- iplotx-0.3.0/assets/pylint.svg +23 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/conf.py +2 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/index.md +3 -1
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/sg_execution_times.rst +22 -4
- iplotx-0.3.0/gallery/plot_animation.py +61 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_biopython_tree.py +1 -0
- iplotx-0.3.0/gallery/plot_company_structure.py +72 -0
- iplotx-0.3.0/gallery/plot_edit_artists.py +60 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_ete4.py +15 -2
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_loops.py +4 -4
- iplotx-0.3.0/gallery/plot_mouse_hover.py +67 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_simple_path.py +2 -2
- iplotx-0.3.0/gallery/plot_tree_node_background.py +55 -0
- iplotx-0.3.0/gallery/plot_trees_of_trees.py +83 -0
- iplotx-0.3.0/iplotx/cascades.py +223 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/edge/__init__.py +180 -420
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/edge/arrow.py +20 -20
- iplotx-0.3.0/iplotx/edge/geometry.py +448 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/edge/ports.py +7 -2
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/groups.py +24 -14
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/ingest/__init__.py +12 -4
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/ingest/heuristics.py +1 -3
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/ingest/providers/network/igraph.py +4 -2
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/ingest/providers/network/networkx.py +4 -2
- iplotx-0.3.0/iplotx/ingest/providers/tree/biopython.py +47 -0
- iplotx-0.3.0/iplotx/ingest/providers/tree/cogent3.py +41 -0
- iplotx-0.3.0/iplotx/ingest/providers/tree/ete4.py +44 -0
- iplotx-0.3.0/iplotx/ingest/providers/tree/skbio.py +41 -0
- iplotx-0.3.0/iplotx/ingest/typing.py +303 -0
- iplotx-0.3.0/iplotx/label.py +209 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/layout.py +57 -36
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/network.py +9 -8
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/plotting.py +6 -3
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/style.py +36 -10
- iplotx-0.3.0/iplotx/tree.py +493 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/typing.py +19 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/version.py +1 -1
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/vertex.py +122 -35
- {iplotx-0.2.0 → iplotx-0.3.0}/pyproject.toml +8 -0
- iplotx-0.3.0/scripts/update_pylint_badge.sh +12 -0
- iplotx-0.3.0/tests/baseline_images/test_biopython/leaf_labels.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_biopython/leaf_labels_hmargin.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_biopython/tree_radial.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_cogent3/leaf_labels.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_cogent3/leaf_labels_hmargin.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_cogent3/tree_radial.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_ete4/leaf_labels.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_ete4/leaf_labels_hmargin.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_ete4/tree_radial.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_networkx/simple_graph.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_skbio/leaf_labels.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_skbio/leaf_labels_hmargin.png +0 -0
- iplotx-0.3.0/tests/baseline_images/test_skbio/tree_radial.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_biopython.py +1 -1
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_cogent3.py +1 -1
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_ete4.py +1 -1
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_igraph.py +2 -2
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_networkx.py +1 -1
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_skbio.py +1 -1
- iplotx-0.2.0/iplotx/ingest/providers/tree/biopython.py +0 -105
- iplotx-0.2.0/iplotx/ingest/providers/tree/cogent3.py +0 -112
- iplotx-0.2.0/iplotx/ingest/providers/tree/ete4.py +0 -112
- iplotx-0.2.0/iplotx/ingest/providers/tree/skbio.py +0 -112
- iplotx-0.2.0/iplotx/ingest/typing.py +0 -100
- iplotx-0.2.0/iplotx/label.py +0 -127
- iplotx-0.2.0/iplotx/tree.py +0 -285
- iplotx-0.2.0/tests/baseline_images/test_biopython/leaf_labels.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_biopython/leaf_labels_hmargin.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_biopython/tree_radial.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_cogent3/leaf_labels.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_cogent3/leaf_labels_hmargin.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_cogent3/tree_radial.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_ete4/leaf_labels.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_ete4/leaf_labels_hmargin.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_ete4/tree_radial.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_networkx/simple_graph.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_skbio/leaf_labels.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_skbio/leaf_labels_hmargin.png +0 -0
- iplotx-0.2.0/tests/baseline_images/test_skbio/tree_radial.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/.github/workflows/test.yml +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/.gitignore +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/.readthedocs.yaml +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/LICENSE +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/MANIFEST.in +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/Makefile +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/make.bat +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/_static/graph_basic.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/_templates/layout.html +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/api.md +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/images/sphx_glr_plot_basic_001.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/images/thumb/sphx_glr_plot_basic_thumb.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/docs/source/style.md +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/GALLERY_HEADER.rst +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/chess_masters_WCC.pgn.bz2 +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/knuth_miles.txt.gz +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_basic.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_big_curves.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_chess_masters.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_cliques.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_cluster_layout.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_cogent3_tree.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_complex.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_dag.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_directed.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_four_grids.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_grouping.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_house.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_knuth_miles.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_labels_and_colors.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_max_bipartite_matching.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_minimum_spanning_trees.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_multipartite_layout.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_parallel_igraph_networkx.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_ports.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_shortest_path.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_simple_networkx.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_skbio_tree.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_style.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_traveling_salesman.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_voronoi.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/gallery/plot_with_colorbar.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/__init__.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/utils/geometry.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/utils/internal.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/utils/matplotlib.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/iplotx/utils/style.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_biopython/tree_basic.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_cogent3/tree_basic.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_ete4/tree_basic.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/clustering_directed.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/clustering_directed_large.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_basic.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_directed.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_directed_curved_loops.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_edit_children.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_labels.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_layout_attribute.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_null.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/graph_squares_directed.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/igraph_layout_object.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_igraph/multigraph_with_curved_edges_undirected.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/cluster-layout.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/complex.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/directed_graph.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/directed_graph_with_colorbar.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/empty_graph.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/flat_style.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/house_with_colors.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/labels_and_colors.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_networkx/shortest_path.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/baseline_images/test_skbio/tree_basic.png +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/test_style.py +0 -0
- {iplotx-0.2.0 → iplotx-0.3.0}/tests/utils.py +0 -0
- {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
|
-
-
|
|
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:
|
|
37
|
+
python-version: ${{ matrix.python-version }}
|
|
28
38
|
|
|
29
|
-
- name:
|
|
39
|
+
- name: Install the project
|
|
30
40
|
run: |
|
|
31
|
-
#
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
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.
|
|
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
|

|
|
32
40
|

|
|
33
41
|

|
|
42
|
+

|
|
34
43
|
|
|
35
44
|
# iplotx
|
|
36
45
|
Plotting networks from igraph and networkx.
|
|
37
46
|
|
|
38
|
-
**NOTE**: This is currently
|
|
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
|

|
|
2
2
|

|
|
3
3
|

|
|
4
|
+

|
|
4
5
|
|
|
5
6
|
# iplotx
|
|
6
7
|
Plotting networks from igraph and networkx.
|
|
7
8
|
|
|
8
|
-
**NOTE**: This is currently
|
|
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:
|
|
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:`
|
|
36
|
-
- 00:
|
|
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:`
|
|
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": "
|
|
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
|
-
"
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
+
)
|