iplotx 1.3.0__tar.gz → 1.4.1__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-1.3.0 → iplotx-1.4.1}/PKG-INFO +1 -1
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/api/complete_style_specification.md +8 -3
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/installing.md +9 -31
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/sg_execution_times.rst +9 -3
- iplotx-1.4.1/gallery/basic/plot_arcs.py +47 -0
- iplotx-1.4.1/gallery/style/plot_edge_geometries.py +61 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/edge/__init__.py +8 -1
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/edge/geometry.py +113 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/layout/tree/unrooted.py +118 -57
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/style/leaf_info.py +1 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/version.py +1 -1
- iplotx-1.4.1/tests/baseline_images/test_igraph/arcs.png +0 -0
- iplotx-1.4.1/tests/baseline_images/test_igraph/directed_arcs.png +0 -0
- iplotx-1.4.1/tests/baseline_images/test_igraph/large_arcs.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_igraph.py +44 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/.github/workflows/publish.yml +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/.github/workflows/test.yml +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/.gitignore +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/.pre-commit-config.yaml +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/.readthedocs.yaml +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/LICENSE +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/MANIFEST.in +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/README.md +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/assets/pylint.svg +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/Makefile +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/make.bat +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/_static/banner.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/_static/custom-icons.js +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/_static/custom.css +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/_static/graph_basic.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/_templates/layout.html +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/api/artists.md +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/api/plotting.md +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/api/providers.md +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/api/style.md +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/api.md +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/code_of_conduct.rst +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/conf.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/images/sphx_glr_plot_basic_001.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/images/thumb/sphx_glr_plot_basic_thumb.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/index.md +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/providers.md +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/docs/source/style.md +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/GALLERY_HEADER.rst +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/basic/GALLERY_HEADER.rst +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/basic/plot_3d.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/basic/plot_basic.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/basic/plot_big_curves.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/basic/plot_dag.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/basic/plot_directed.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/basic/plot_grouping.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/basic/plot_house.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/basic/plot_loops.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/basic/plot_simple_path.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/GALLERY_HEADER.rst +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/data/80201010000000001.mst +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/data/GN-tree.json +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/data/breast_cancer_string_interactions_short.tsv +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/data/breast_cancer_string_network_coordinates.tsv +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/data/cell_cycle_arrest_string_interactions_short.tsv +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/data/cell_cycle_arrest_string_network_coordinates.tsv +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/data/fevo-08-588430_DataSheet1_S1.csv +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/plot_animal_phylogeny.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/plot_antibody_clone.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/plot_breast_cancer_ppi.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/plot_cell_cycle_arrest.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/plot_food_network.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/plot_foraging_table.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/plot_pollinators.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/plot_ppi.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/biology/plot_tca_cycle.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/GALLERY_HEADER.rst +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/data/chess_masters_WCC.pgn.bz2 +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/data/knuth_miles.txt.gz +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_arrowlawn.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_chess_masters.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_cliques.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_cluster_layout.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_company_structure.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_complex.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_financial_network.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_knuth_miles.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_labels_and_colors.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_max_bipartite_matching.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_minimum_spanning_trees.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_multipartite_layout.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_parallel_igraph_networkx.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_redblack.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_shortest_path.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_simple_networkx.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_social_network_circles.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_traveling_salesman.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/network_science/plot_with_colorbar.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/other/GALLERY_HEADER.rst +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/other/plot_animation.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/other/plot_edit_artists.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/other/plot_feedbacks.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/other/plot_graph.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/other/plot_mouse_hover.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/other/plot_train.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/GALLERY_HEADER.rst +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_arrows.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_depthshade.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_edgepadding.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_elements.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_four_grids.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_halfarrows.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_multistyle.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_ports.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_style.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_tension.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_vertexmarkers.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_voronoi.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/style/plot_waypoints.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/GALLERY_HEADER.rst +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/data/tree-with-support.json +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_angular_waypoints.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_biopython_tree.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_cladeedges.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_cogent3_layouts.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_cogent3_tree.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_dendropy.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_double_tree.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_elements_tree.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_equalangle.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_ete4.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_leafedges.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_leafedges_and_cascades.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_scalebar.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_skbio_tree.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_split_edges.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_style_tree.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_support.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_tree_node_background.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_tree_style_clades.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/tree/plot_trees_of_trees.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/zero_dependency/GALLERY_HEADER.rst +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/zero_dependency/plot_simplenetworkdataprovider.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/gallery/zero_dependency/plot_simpletreedataprovider.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/__init__.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/art3d/edge/__init__.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/art3d/edge/arrow.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/art3d/edge/geometry.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/art3d/vertex.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/artists.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/edge/arrow.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/edge/leaf.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/edge/ports.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/__init__.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/heuristics.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/providers/network/graph_tool.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/providers/network/igraph.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/providers/network/networkx.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/providers/network/simple.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/providers/tree/biopython.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/providers/tree/cogent3.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/providers/tree/dendropy.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/providers/tree/ete4.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/providers/tree/simple.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/providers/tree/skbio.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/ingest/typing.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/label.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/layout/__init__.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/layout/tree/__init__.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/layout/tree/rooted.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/network/__init__.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/network/groups.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/plotting.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/style/__init__.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/style/library.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/tree/__init__.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/tree/cascades.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/tree/scalebar.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/typing.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/utils/geometry.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/utils/internal.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/utils/matplotlib.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/utils/style.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/iplotx/vertex.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/pyproject.toml +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/scripts/copy_github_release_into_version.sh +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/scripts/make_banner.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/scripts/update_pylint_badge.sh +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_biopython/cascades.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_biopython/directed_child.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_biopython/leaf_labels.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_biopython/leaf_labels_hmargin.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_biopython/leafedges.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_biopython/show_support.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_biopython/tree_basic.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_biopython/tree_radial.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_cogent3/leaf_labels.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_cogent3/leaf_labels_hmargin.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_cogent3/tree_basic.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_cogent3/tree_radial.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_dendropy/cascades.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_dendropy/directed_child.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_dendropy/leaf_labels.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_dendropy/leaf_labels_hmargin.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_dendropy/leafedges.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_dendropy/tree_basic.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_dendropy/tree_radial.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_doubletree/tree_gap.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_doubletree/tree_nogap.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_ete4/equalangle_layout.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_ete4/leaf_labels.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_ete4/leaf_labels_hmargin.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_ete4/split_edges.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_ete4/tree_basic.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_ete4/tree_radial.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_graph_tool/graph_basic.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_graph_tool/graph_directed.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/clustering_directed.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/clustering_directed_large.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/graph_basic.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/graph_directed.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/graph_directed_curved_loops.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/graph_edit_children.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/graph_labels.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/graph_layout_attribute.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/graph_null.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/graph_squares_directed.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/graph_vertexsize.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/graph_with_curved_edges.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/igraph_layout_object.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph/multigraph_with_curved_edges_undirected.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph_3d/directed.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph_3d/undirected.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_igraph_3d/vertex_labels.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/cluster-layout.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/complex.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/complex_rotatelabels.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/directed_graph.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/directed_graph_with_colorbar.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/empty_graph.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/flat_style.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/house_with_colors.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/labels_and_colors.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/shortest_path.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_networkx/simple_graph.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_simple_network_provider/graph_basic.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_simple_network_provider/graph_directed.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_simple_network_provider/graph_labels.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_skbio/leaf_labels.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_skbio/leaf_labels_hmargin.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_skbio/tree_basic.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/baseline_images/test_skbio/tree_radial.png +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_arrows.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_biopython.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_cascades.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_cogent3.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_dendropy.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_doubletree.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_edge.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_edge_geometry.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_ete4.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_geometry.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_graph_tool.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_heuristics.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_igraph_3d.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_ingest_protocols.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_matplotlib_utils.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_network_hotload.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_networkx.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_ports.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_simple_network_provider.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_simple_tree_provider.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_skbio.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_style.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/test_vertex.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/tests/utils.py +0 -0
- {iplotx-1.3.0 → iplotx-1.4.1}/uv.lock +0 -0
|
@@ -102,9 +102,14 @@
|
|
|
102
102
|
|
|
103
103
|
"curved": bool, # Whether the edge is curved (True) or straight (False)
|
|
104
104
|
|
|
105
|
-
# Tension for curved edges
|
|
106
|
-
# Bezier
|
|
105
|
+
# Tension for curved edges and arcs.
|
|
106
|
+
# For Bezier (curved) edges, 0.0 means straight, higher values position the
|
|
107
|
+
# Bezier control points further away from the nodes, creating more wiggly lines.
|
|
107
108
|
# Negative values bend the curve on the other side of the straight line.
|
|
109
|
+
# For arc edges, 0.0 means straight, higher values draw larger arcs. 1.0
|
|
110
|
+
# means a semicircle, and numbers above 5 create very large arcs, almost full
|
|
111
|
+
# circles. The exact definition of tension for arcs is the tangent of a
|
|
112
|
+
# quarter of the angle spanned by the arc.
|
|
108
113
|
"tension": float,
|
|
109
114
|
|
|
110
115
|
# Tension for self-loops (higher values create more bigger loops).
|
|
@@ -281,7 +286,7 @@
|
|
|
281
286
|
# For horizontal and vertical layouts:
|
|
282
287
|
# start: Starting position in data units (tuple of two floats)
|
|
283
288
|
# span: Breadth in data units (float)
|
|
284
|
-
"start": float | tuple[float,
|
|
289
|
+
"start": float | tuple[float margins=0.2,
|
|
285
290
|
"span": float,
|
|
286
291
|
},
|
|
287
292
|
############################################################################
|
|
@@ -11,13 +11,11 @@ pip install iplotx
|
|
|
11
11
|
|
|
12
12
|
```
|
|
13
13
|
import igraph as ig
|
|
14
|
-
import matplotlib.pyplot as plt
|
|
15
14
|
import iplotx as ipx
|
|
16
15
|
|
|
17
16
|
g = ig.Graph.Ring(5)
|
|
18
17
|
layout = g.layout("circle").coords
|
|
19
|
-
|
|
20
|
-
ipx.plot(g, ax=ax, layout=layout)
|
|
18
|
+
ipx.network(g, layout)
|
|
21
19
|
```
|
|
22
20
|
|
|
23
21
|
|
|
@@ -27,13 +25,11 @@ ipx.plot(g, ax=ax, layout=layout)
|
|
|
27
25
|
:::{tab-item} networkx
|
|
28
26
|
```
|
|
29
27
|
import networkx as nx
|
|
30
|
-
import matplotlib.pyplot as plt
|
|
31
28
|
import iplotx as ipx
|
|
32
29
|
|
|
33
30
|
g = nx.Graph([(0, 1), (1, 2), (2, 3), (3, 4), (4, 0)])
|
|
34
31
|
layout = nx.layout.circular_layout(g)
|
|
35
|
-
|
|
36
|
-
ipx.plot(g, ax=ax, layout=layout)
|
|
32
|
+
ipx.network(g, layout)
|
|
37
33
|
```
|
|
38
34
|
|
|
39
35
|
:::
|
|
@@ -44,9 +40,6 @@ Either way, the result is the same:
|
|
|
44
40
|
|
|
45
41
|

|
|
46
42
|
|
|
47
|
-
## Gallery
|
|
48
|
-
See <project:gallery/index.rst> for examples of plots made with `iplotx`. Feel free to suggest new examples on GitHub by opening a new issue or pull request!
|
|
49
|
-
|
|
50
43
|
## Features
|
|
51
44
|
`iplotx`'s features' include:
|
|
52
45
|
- per-edge and per-vertex styling using sequences or dictionaries
|
|
@@ -72,32 +65,17 @@ See <project:gallery/index.rst> for examples of plots made with `iplotx`. Feel f
|
|
|
72
65
|
- animations (see <project:gallery/other/plot_animation.rst>)
|
|
73
66
|
- 3D visualisations
|
|
74
67
|
- mouse/keyboard interaction and events (e.g. hover, click, see <project:gallery/other/plot_mouse_hover.rst>)
|
|
75
|
-
- ... and
|
|
68
|
+
- ... and many more.
|
|
76
69
|
|
|
77
|
-
##
|
|
78
|
-
|
|
70
|
+
## Rationale
|
|
71
|
+
We believe graph **analysis**, graph **layouting**, and graph **visualisation** to be three separate tasks. `iplotx` currently focuses on visualisation. It can also compute simple tree layouts and might expand towards network layouts in the future.
|
|
79
72
|
|
|
80
|
-
|
|
73
|
+
## Citation
|
|
74
|
+
If you use `iplotx` for publication figures, please cite the [zenodo preprint](https://doi.org/10.5281/zenodo.16599333):
|
|
81
75
|
|
|
82
|
-
```python
|
|
83
|
-
import iplotx as ipx
|
|
84
|
-
with ipx.style.context({
|
|
85
|
-
'vertex': {
|
|
86
|
-
'size': 30,
|
|
87
|
-
'facecolor': 'red',
|
|
88
|
-
'edgecolor': 'none',
|
|
89
|
-
}
|
|
90
|
-
}):
|
|
91
|
-
ipx.plot(...)
|
|
92
76
|
```
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
## Reference API
|
|
97
|
-
See <project:api.md> for reference documentation of all functions and classes in `iplotx`.
|
|
98
|
-
|
|
99
|
-
## Rationale
|
|
100
|
-
We believe graph **analysis**, graph **layouting**, and graph **visualisation** to be three separate tasks. `iplotx` currently focuses on visualisation. It can also compute simple tree layouts and might expand towards network layouts in the future.
|
|
77
|
+
F. Zanini. (2025). Unified network visualisation in Python. Zenodo [PREPRINT]. https://doi.org/10.5281/zenodo.16599333
|
|
78
|
+
```
|
|
101
79
|
|
|
102
80
|
## Contributing
|
|
103
81
|
Open an [issue on GitHub](https://github.com/fabilab/iplotx/issues) to request features, report bugs, or show intention in contributing. Pull requests are very welcome.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
Computation times
|
|
8
8
|
=================
|
|
9
|
-
**00:00.
|
|
9
|
+
**00:00.158** total execution time for 80 files **from all galleries**:
|
|
10
10
|
|
|
11
11
|
.. container::
|
|
12
12
|
|
|
@@ -32,12 +32,15 @@ Computation times
|
|
|
32
32
|
* - Example
|
|
33
33
|
- Time
|
|
34
34
|
- Mem (MB)
|
|
35
|
-
* - :ref:`
|
|
36
|
-
- 00:00.
|
|
35
|
+
* - :ref:`sphx_glr_gallery_style_plot_edge_geometries.py` (``../../gallery/style/plot_edge_geometries.py``)
|
|
36
|
+
- 00:00.158
|
|
37
37
|
- 0.0
|
|
38
38
|
* - :ref:`sphx_glr_gallery_basic_plot_3d.py` (``../../gallery/basic/plot_3d.py``)
|
|
39
39
|
- 00:00.000
|
|
40
40
|
- 0.0
|
|
41
|
+
* - :ref:`sphx_glr_gallery_basic_plot_arcs.py` (``../../gallery/basic/plot_arcs.py``)
|
|
42
|
+
- 00:00.000
|
|
43
|
+
- 0.0
|
|
41
44
|
* - :ref:`sphx_glr_gallery_basic_plot_basic.py` (``../../gallery/basic/plot_basic.py``)
|
|
42
45
|
- 00:00.000
|
|
43
46
|
- 0.0
|
|
@@ -227,6 +230,9 @@ Computation times
|
|
|
227
230
|
* - :ref:`sphx_glr_gallery_tree_plot_elements_tree.py` (``../../gallery/tree/plot_elements_tree.py``)
|
|
228
231
|
- 00:00.000
|
|
229
232
|
- 0.0
|
|
233
|
+
* - :ref:`sphx_glr_gallery_tree_plot_equalangle.py` (``../../gallery/tree/plot_equalangle.py``)
|
|
234
|
+
- 00:00.000
|
|
235
|
+
- 0.0
|
|
230
236
|
* - :ref:`sphx_glr_gallery_tree_plot_ete4.py` (``../../gallery/tree/plot_ete4.py``)
|
|
231
237
|
- 00:00.000
|
|
232
238
|
- 0.0
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Arcs
|
|
3
|
+
====
|
|
4
|
+
|
|
5
|
+
This example showcases the ability of `iplotx` to curve edges into arcs, using tension to define the angular span of the arc.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import igraph as ig
|
|
9
|
+
import matplotlib.pyplot as plt
|
|
10
|
+
import iplotx as ipx
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
g = ig.Graph.Full(4)
|
|
14
|
+
layout = [[0, 0], [1, 0], [2, 0], [3, 0]]
|
|
15
|
+
|
|
16
|
+
fig, ax = plt.subplots()
|
|
17
|
+
ipx.plot(
|
|
18
|
+
g,
|
|
19
|
+
layout=layout,
|
|
20
|
+
ax=ax,
|
|
21
|
+
edge_arc=True,
|
|
22
|
+
edge_tension=-1,
|
|
23
|
+
)
|
|
24
|
+
|
|
25
|
+
# %%
|
|
26
|
+
#
|
|
27
|
+
# Other values of tension can be used to create different arc shapes:
|
|
28
|
+
|
|
29
|
+
fig, axs = plt.subplots(2, 2, figsize=(8, 8))
|
|
30
|
+
for tension, ax in zip([0.5, 2.5, -0.5, -2.5], axs.ravel()):
|
|
31
|
+
ipx.plot(
|
|
32
|
+
g,
|
|
33
|
+
layout=layout,
|
|
34
|
+
ax=ax,
|
|
35
|
+
edge_arc=True,
|
|
36
|
+
edge_tension=tension,
|
|
37
|
+
margins=0.15,
|
|
38
|
+
title=f"Edge tension = {tension:.2f}",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# %%
|
|
42
|
+
# .. tip::
|
|
43
|
+
# Tension is defined as the tangent of the quarter of the angle spanned by the arc. A tension of 0 gives
|
|
44
|
+
# a straight line, a tension of 1 gives a semicircle, and higher tensions give increasingly larger arcs. A tension of
|
|
45
|
+
# infinity would give you a straight line away from the target vertex, but is not accepted by the library. Negative
|
|
46
|
+
# tensions result in arcs curving in the opposite direction.
|
|
47
|
+
#
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Edge geometries
|
|
3
|
+
===============
|
|
4
|
+
|
|
5
|
+
This example shows how to use edge geometries and tension to achieve different visualisation styles.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
import igraph as ig
|
|
10
|
+
import matplotlib.pyplot as plt
|
|
11
|
+
import iplotx as ipx
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
g = ig.Graph.Full(2)
|
|
15
|
+
layout = [[0, 0], [1, 0]]
|
|
16
|
+
|
|
17
|
+
fig, axs = plt.subplots(3, 3, figsize=(6, 6), sharex=True, sharey=True)
|
|
18
|
+
tensions = [
|
|
19
|
+
[1, 5, 10],
|
|
20
|
+
[0.2, 1, 2],
|
|
21
|
+
]
|
|
22
|
+
for edge_arc, axrow, tensionrow in zip([False, True], axs, tensions):
|
|
23
|
+
kwargs = {}
|
|
24
|
+
if not edge_arc:
|
|
25
|
+
kwargs["edge_curved"] = True
|
|
26
|
+
for tension, ax in zip(tensionrow, axrow):
|
|
27
|
+
ipx.plot(
|
|
28
|
+
g,
|
|
29
|
+
layout=layout,
|
|
30
|
+
ax=ax,
|
|
31
|
+
edge_arc=edge_arc,
|
|
32
|
+
edge_tension=tension,
|
|
33
|
+
title=f"Tension {tension:.1f}",
|
|
34
|
+
node_size=10,
|
|
35
|
+
**kwargs,
|
|
36
|
+
)
|
|
37
|
+
axs[0, 0].set_ylabel("Bezier", fontsize=12)
|
|
38
|
+
axs[1, 0].set_ylabel("Arc", fontsize=12)
|
|
39
|
+
ipx.plot(
|
|
40
|
+
g,
|
|
41
|
+
layout,
|
|
42
|
+
ax=axs[2, 0],
|
|
43
|
+
node_size=10,
|
|
44
|
+
)
|
|
45
|
+
axs[2, 0].set_ylabel("Straight", fontsize=12)
|
|
46
|
+
ipx.plot(
|
|
47
|
+
g,
|
|
48
|
+
layout,
|
|
49
|
+
ax=axs[2, 1],
|
|
50
|
+
node_size=10,
|
|
51
|
+
edge_waypoints=[[0.5, -0.15]],
|
|
52
|
+
)
|
|
53
|
+
ipx.plot(
|
|
54
|
+
g,
|
|
55
|
+
layout,
|
|
56
|
+
ax=axs[2, 2],
|
|
57
|
+
node_size=10,
|
|
58
|
+
edge_waypoints=[[[0.25, -0.15], [0.75, -0.15]]],
|
|
59
|
+
)
|
|
60
|
+
axs[2, 1].set_ylabel("Waypoints", fontsize=12)
|
|
61
|
+
fig.tight_layout()
|
|
@@ -370,6 +370,9 @@ class EdgeCollection(mpl.collections.PatchCollection):
|
|
|
370
370
|
if edge_stylei.get("curved", False):
|
|
371
371
|
tension = edge_stylei.get("tension", 5)
|
|
372
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
|
|
373
376
|
else:
|
|
374
377
|
tension = 0
|
|
375
378
|
ports = None
|
|
@@ -391,6 +394,8 @@ class EdgeCollection(mpl.collections.PatchCollection):
|
|
|
391
394
|
if waypoints != "none":
|
|
392
395
|
ports = edge_stylei.get("ports", (None, None))
|
|
393
396
|
|
|
397
|
+
arc = edge_stylei.get("arc", False)
|
|
398
|
+
|
|
394
399
|
# Compute actual edge path
|
|
395
400
|
path, angles = _compute_edge_path(
|
|
396
401
|
vcoord_data,
|
|
@@ -401,6 +406,7 @@ class EdgeCollection(mpl.collections.PatchCollection):
|
|
|
401
406
|
tension=tension,
|
|
402
407
|
waypoints=waypoints,
|
|
403
408
|
ports=ports,
|
|
409
|
+
arc=arc,
|
|
404
410
|
layout_coordinate_system=self._vertex_collection.get_layout_coordinate_system(),
|
|
405
411
|
shrink=shrink,
|
|
406
412
|
)
|
|
@@ -447,7 +453,7 @@ class EdgeCollection(mpl.collections.PatchCollection):
|
|
|
447
453
|
# If none found, empty the dictionary already
|
|
448
454
|
if (len(parallel_edges) == 0) or (max(parallel_edges.values(), key=len) == 1):
|
|
449
455
|
parallel_edges = {}
|
|
450
|
-
if not self._style.get("curved", False):
|
|
456
|
+
if (not self._style.get("curved", False)) and (not self._style.get("arc", False)):
|
|
451
457
|
while len(parallel_edges) > 0:
|
|
452
458
|
(v1, v2), indices = parallel_edges.popitem()
|
|
453
459
|
indices_inv = parallel_edges.pop((v2, v1), [])
|
|
@@ -712,6 +718,7 @@ def make_stub_patch(**kwargs):
|
|
|
712
718
|
"split",
|
|
713
719
|
"shrink",
|
|
714
720
|
"depthshade",
|
|
721
|
+
"arc",
|
|
715
722
|
# DEPRECATED
|
|
716
723
|
"padding",
|
|
717
724
|
]
|
|
@@ -393,6 +393,108 @@ def _compute_edge_path_waypoints(
|
|
|
393
393
|
return path, angles
|
|
394
394
|
|
|
395
395
|
|
|
396
|
+
def _compute_edge_path_arc(
|
|
397
|
+
tension,
|
|
398
|
+
vcoord_data,
|
|
399
|
+
vpath_fig,
|
|
400
|
+
vsize_fig,
|
|
401
|
+
trans,
|
|
402
|
+
trans_inv,
|
|
403
|
+
ports: Pair[Optional[str]] = (None, None),
|
|
404
|
+
shrink: float = 0,
|
|
405
|
+
):
|
|
406
|
+
"""Shorten the edge path along an arc.
|
|
407
|
+
|
|
408
|
+
Parameters:
|
|
409
|
+
tension: the tension of the arc. This is defined, for this function, as the tangent
|
|
410
|
+
of the angle spanning the arc. For instance, for a semicircle, the angle is
|
|
411
|
+
180 degrees, so the tension is +-1 (depending on the orientation).
|
|
412
|
+
"""
|
|
413
|
+
|
|
414
|
+
# Coordinates in figure (default) coords
|
|
415
|
+
vcoord_fig = trans(vcoord_data)
|
|
416
|
+
|
|
417
|
+
dv = vcoord_fig[1] - vcoord_fig[0]
|
|
418
|
+
|
|
419
|
+
# Tension is the fraction of the semicircle covered by the
|
|
420
|
+
# arc. Values are clipped between -1 (left-hand semicircle)
|
|
421
|
+
# and 1 (right-hand semicircle). 0 means a straight line,
|
|
422
|
+
# which is a (degenerate) arc too.
|
|
423
|
+
if tension == 0:
|
|
424
|
+
vs = [None, None]
|
|
425
|
+
thetas = [atan2(dv[1], dv[0])]
|
|
426
|
+
thetas.append(-thetas[0])
|
|
427
|
+
for i in range(2):
|
|
428
|
+
vs[i] = (
|
|
429
|
+
_get_shorter_edge_coords(vpath_fig[i], vsize_fig[i], thetas[i], shrink)
|
|
430
|
+
+ vcoord_fig[i]
|
|
431
|
+
)
|
|
432
|
+
auxs = []
|
|
433
|
+
|
|
434
|
+
else:
|
|
435
|
+
edge_straight_length = np.sqrt((dv**2).sum())
|
|
436
|
+
theta_straight = atan2(dv[1], dv[0])
|
|
437
|
+
theta_tension = 4 * np.arctan(tension)
|
|
438
|
+
# print(f"theta_straight: {np.degrees(theta_straight):.2f}")
|
|
439
|
+
# print(f"theta_tension: {np.degrees(theta_tension):.2f}")
|
|
440
|
+
# NOTE: positive tension means an arc shooting off to the right of the straight
|
|
441
|
+
# line, same convensio as for tension elsewhere in the codebase.
|
|
442
|
+
thetas = [theta_straight - theta_tension / 2, np.pi + theta_straight + theta_tension / 2]
|
|
443
|
+
# This is guaranteed to be finite because tension == 0 is taken care of above,
|
|
444
|
+
# and tension = np.inf is not allowed.
|
|
445
|
+
mid = vcoord_fig.mean(axis=0)
|
|
446
|
+
# print(f"theta_s: {thetas}")
|
|
447
|
+
# print(f"mid: {mid}")
|
|
448
|
+
theta_offset = theta_straight + np.pi / 2
|
|
449
|
+
if np.abs(tension) <= 1:
|
|
450
|
+
offset_length = edge_straight_length / 2 / np.tan(theta_tension / 2)
|
|
451
|
+
else:
|
|
452
|
+
# print("Large tension arc")
|
|
453
|
+
offset_length = -edge_straight_length / 2 * np.tan(theta_tension / 2 - np.pi / 2)
|
|
454
|
+
# print(f"theta_offset: {np.degrees(theta_offset):.2f}")
|
|
455
|
+
offset = offset_length * np.array([np.cos(theta_offset), np.sin(theta_offset)])
|
|
456
|
+
# print(f"offset: {offset}")
|
|
457
|
+
center = mid + offset
|
|
458
|
+
# print(f"center: {center}")
|
|
459
|
+
|
|
460
|
+
# Compute shorter start and end points
|
|
461
|
+
vs = [None, None]
|
|
462
|
+
for i in range(2):
|
|
463
|
+
vs[i] = (
|
|
464
|
+
_get_shorter_edge_coords(vpath_fig[i], vsize_fig[i], thetas[i], shrink)
|
|
465
|
+
+ vcoord_fig[i]
|
|
466
|
+
)
|
|
467
|
+
angle_start = atan2(*(vs[0] - center)[::-1])
|
|
468
|
+
angle_end = atan2(*(vs[1] - center)[::-1])
|
|
469
|
+
if (np.abs(tension) > 1) and (np.abs(angle_end - angle_start) < np.pi):
|
|
470
|
+
if angle_end > angle_start:
|
|
471
|
+
angle_start += 2 * np.pi
|
|
472
|
+
else:
|
|
473
|
+
angle_end += 2 * np.pi
|
|
474
|
+
# print(f"angle_start: {np.degrees(angle_start):.2f}")
|
|
475
|
+
# print(f"angle_end: {np.degrees(angle_end):.2f}")
|
|
476
|
+
|
|
477
|
+
naux = 30
|
|
478
|
+
angles = np.linspace(angle_start, angle_end, naux + 2)[1:-1]
|
|
479
|
+
auxs = center + np.array([np.cos(angles), np.sin(angles)]).T * np.linalg.norm(
|
|
480
|
+
vs[0] - center
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
path = {
|
|
484
|
+
"vertices": [vs[0]] + list(auxs) + [vs[1]],
|
|
485
|
+
"codes": ["MOVETO"] + ["LINETO"] * (len(auxs) + 1),
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
path = mpl.path.Path(
|
|
489
|
+
path["vertices"],
|
|
490
|
+
codes=[getattr(mpl.path.Path, x) for x in path["codes"]],
|
|
491
|
+
)
|
|
492
|
+
|
|
493
|
+
# Return to data transform
|
|
494
|
+
path.vertices = trans_inv(path.vertices)
|
|
495
|
+
return path, tuple(thetas)
|
|
496
|
+
|
|
497
|
+
|
|
396
498
|
def _compute_edge_path_curved(
|
|
397
499
|
tension,
|
|
398
500
|
vcoord_data,
|
|
@@ -483,12 +585,15 @@ def _compute_edge_path(
|
|
|
483
585
|
tension: float = 0,
|
|
484
586
|
waypoints: str | tuple[float, float] | Sequence[tuple[float, float]] | np.ndarray = "none",
|
|
485
587
|
ports: Pair[Optional[str]] = (None, None),
|
|
588
|
+
arc: bool = False,
|
|
486
589
|
layout_coordinate_system: str = "cartesian",
|
|
487
590
|
**kwargs,
|
|
488
591
|
):
|
|
489
592
|
"""Compute the edge path in a few different ways."""
|
|
490
593
|
if (waypoints != "none") and (tension != 0):
|
|
491
594
|
raise ValueError("Waypoints not supported for curved edges.")
|
|
595
|
+
if (waypoints != "none") and arc:
|
|
596
|
+
raise ValueError("Waypoint not supported for arc edges.")
|
|
492
597
|
|
|
493
598
|
if waypoints != "none":
|
|
494
599
|
return _compute_edge_path_waypoints(
|
|
@@ -506,6 +611,14 @@ def _compute_edge_path(
|
|
|
506
611
|
**kwargs,
|
|
507
612
|
)
|
|
508
613
|
|
|
614
|
+
if arc:
|
|
615
|
+
return _compute_edge_path_arc(
|
|
616
|
+
tension,
|
|
617
|
+
*args,
|
|
618
|
+
ports=ports,
|
|
619
|
+
**kwargs,
|
|
620
|
+
)
|
|
621
|
+
|
|
509
622
|
return _compute_edge_path_curved(
|
|
510
623
|
tension,
|
|
511
624
|
*args,
|