iplotx 0.8.0__tar.gz → 0.10.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 (235) hide show
  1. {iplotx-0.8.0 → iplotx-0.10.0}/.github/workflows/test.yml +1 -4
  2. {iplotx-0.8.0 → iplotx-0.10.0}/PKG-INFO +1 -2
  3. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/sg_execution_times.rst +21 -18
  4. iplotx-0.10.0/gallery/basic/plot_3d.py +29 -0
  5. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/__init__.py +3 -3
  6. iplotx-0.10.0/iplotx/art3d/edge.py +65 -0
  7. iplotx-0.10.0/iplotx/art3d/vertex.py +69 -0
  8. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/artists.py +4 -0
  9. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/edge/__init__.py +10 -0
  10. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/edge/geometry.py +34 -1
  11. iplotx-0.10.0/iplotx/edge/geometry3d.py +113 -0
  12. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/groups.py +19 -1
  13. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/providers/network/igraph.py +9 -10
  14. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/providers/network/networkx.py +12 -14
  15. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/label.py +11 -0
  16. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/network.py +57 -3
  17. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/plotting.py +111 -41
  18. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/version.py +1 -1
  19. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/vertex.py +23 -1
  20. {iplotx-0.8.0 → iplotx-0.10.0}/pyproject.toml +2 -1
  21. iplotx-0.10.0/tests/baseline_images/test_igraph_3d/undirected.png +0 -0
  22. iplotx-0.10.0/tests/test_3d_mock.py +87 -0
  23. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_igraph.py +14 -14
  24. iplotx-0.10.0/tests/test_igraph_3d.py +40 -0
  25. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_networkx.py +12 -12
  26. {iplotx-0.8.0 → iplotx-0.10.0}/uv.lock +6 -2
  27. {iplotx-0.8.0 → iplotx-0.10.0}/.github/workflows/publish.yml +0 -0
  28. {iplotx-0.8.0 → iplotx-0.10.0}/.gitignore +0 -0
  29. {iplotx-0.8.0 → iplotx-0.10.0}/.pre-commit-config.yaml +0 -0
  30. {iplotx-0.8.0 → iplotx-0.10.0}/.readthedocs.yaml +0 -0
  31. {iplotx-0.8.0 → iplotx-0.10.0}/LICENSE +0 -0
  32. {iplotx-0.8.0 → iplotx-0.10.0}/MANIFEST.in +0 -0
  33. {iplotx-0.8.0 → iplotx-0.10.0}/README.md +0 -0
  34. {iplotx-0.8.0 → iplotx-0.10.0}/assets/pylint.svg +0 -0
  35. {iplotx-0.8.0 → iplotx-0.10.0}/docs/Makefile +0 -0
  36. {iplotx-0.8.0 → iplotx-0.10.0}/docs/make.bat +0 -0
  37. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/_static/banner.png +0 -0
  38. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/_static/graph_basic.png +0 -0
  39. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/_templates/layout.html +0 -0
  40. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/api/artists.md +0 -0
  41. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/api/complete_style_specification.md +0 -0
  42. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/api/plotting.md +0 -0
  43. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/api/providers.md +0 -0
  44. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/api/style.md +0 -0
  45. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/api.md +0 -0
  46. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/conf.py +0 -0
  47. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/images/sphx_glr_plot_basic_001.png +0 -0
  48. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/images/thumb/sphx_glr_plot_basic_thumb.png +0 -0
  49. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/index.md +0 -0
  50. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/providers.md +0 -0
  51. {iplotx-0.8.0 → iplotx-0.10.0}/docs/source/style.md +0 -0
  52. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/GALLERY_HEADER.rst +0 -0
  53. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/basic/GALLERY_HEADER.rst +0 -0
  54. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/basic/plot_basic.py +0 -0
  55. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/basic/plot_big_curves.py +0 -0
  56. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/basic/plot_dag.py +0 -0
  57. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/basic/plot_directed.py +0 -0
  58. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/basic/plot_grouping.py +0 -0
  59. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/basic/plot_house.py +0 -0
  60. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/basic/plot_loops.py +0 -0
  61. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/basic/plot_simple_path.py +0 -0
  62. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/GALLERY_HEADER.rst +0 -0
  63. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/data/80201010000000001.mst +0 -0
  64. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/data/GN-tree.json +0 -0
  65. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/data/breast_cancer_string_interactions_short.tsv +0 -0
  66. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/data/breast_cancer_string_network_coordinates.tsv +0 -0
  67. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/data/cell_cycle_arrest_string_interactions_short.tsv +0 -0
  68. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/data/cell_cycle_arrest_string_network_coordinates.tsv +0 -0
  69. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/data/fevo-08-588430_DataSheet1_S1.csv +0 -0
  70. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/plot_animal_phylogeny.py +0 -0
  71. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/plot_antibody_clone.py +0 -0
  72. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/plot_breast_cancer_ppi.py +0 -0
  73. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/plot_cell_cycle_arrest.py +0 -0
  74. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/plot_food_network.py +0 -0
  75. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/plot_foraging_table.py +0 -0
  76. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/plot_pollinators.py +0 -0
  77. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/plot_ppi.py +0 -0
  78. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/biology/plot_tca_cycle.py +0 -0
  79. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/GALLERY_HEADER.rst +0 -0
  80. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/data/chess_masters_WCC.pgn.bz2 +0 -0
  81. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/data/knuth_miles.txt.gz +0 -0
  82. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_arrowlawn.py +0 -0
  83. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_chess_masters.py +0 -0
  84. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_cliques.py +0 -0
  85. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_cluster_layout.py +0 -0
  86. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_company_structure.py +0 -0
  87. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_complex.py +0 -0
  88. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_financial_network.py +0 -0
  89. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_knuth_miles.py +0 -0
  90. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_labels_and_colors.py +0 -0
  91. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_max_bipartite_matching.py +0 -0
  92. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_minimum_spanning_trees.py +0 -0
  93. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_multipartite_layout.py +0 -0
  94. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_parallel_igraph_networkx.py +0 -0
  95. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_redblack.py +0 -0
  96. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_shortest_path.py +0 -0
  97. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_simple_networkx.py +0 -0
  98. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_social_network_circles.py +0 -0
  99. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_traveling_salesman.py +0 -0
  100. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/network_science/plot_with_colorbar.py +0 -0
  101. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/other/GALLERY_HEADER.rst +0 -0
  102. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/other/plot_animation.py +0 -0
  103. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/other/plot_edit_artists.py +0 -0
  104. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/other/plot_feedbacks.py +0 -0
  105. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/other/plot_graph.py +0 -0
  106. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/other/plot_mouse_hover.py +0 -0
  107. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/other/plot_train.py +0 -0
  108. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/GALLERY_HEADER.rst +0 -0
  109. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_arrows.py +0 -0
  110. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_edgepadding.py +0 -0
  111. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_elements.py +0 -0
  112. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_four_grids.py +0 -0
  113. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_halfarrows.py +0 -0
  114. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_multistyle.py +0 -0
  115. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_ports.py +0 -0
  116. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_style.py +0 -0
  117. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_tension.py +0 -0
  118. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_vertexmarkers.py +0 -0
  119. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_voronoi.py +0 -0
  120. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/style/plot_waypoints.py +0 -0
  121. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/GALLERY_HEADER.rst +0 -0
  122. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/data/tree-with-support.json +0 -0
  123. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_angular_waypoints.py +0 -0
  124. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_biopython_tree.py +0 -0
  125. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_cladeedges.py +0 -0
  126. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_cogent3_layouts.py +0 -0
  127. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_cogent3_tree.py +0 -0
  128. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_elements_tree.py +0 -0
  129. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_ete4.py +0 -0
  130. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_leafedges.py +0 -0
  131. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_leafedges_and_cascades.py +0 -0
  132. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_skbio_tree.py +0 -0
  133. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_split_edges.py +0 -0
  134. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_style_tree.py +0 -0
  135. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_support.py +0 -0
  136. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_tree_node_background.py +0 -0
  137. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_tree_style_clades.py +0 -0
  138. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/tree/plot_trees_of_trees.py +0 -0
  139. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/zero_dependency/GALLERY_HEADER.rst +0 -0
  140. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/zero_dependency/plot_simplenetworkdataprovider.py +0 -0
  141. {iplotx-0.8.0 → iplotx-0.10.0}/gallery/zero_dependency/plot_simpletreedataprovider.py +0 -0
  142. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/cascades.py +0 -0
  143. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/edge/arrow.py +0 -0
  144. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/edge/leaf.py +0 -0
  145. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/edge/ports.py +0 -0
  146. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/__init__.py +0 -0
  147. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/heuristics.py +0 -0
  148. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/providers/network/simple.py +0 -0
  149. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/providers/tree/biopython.py +0 -0
  150. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/providers/tree/cogent3.py +0 -0
  151. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/providers/tree/ete4.py +0 -0
  152. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/providers/tree/simple.py +0 -0
  153. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/providers/tree/skbio.py +0 -0
  154. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/ingest/typing.py +0 -0
  155. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/layout.py +0 -0
  156. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/style/__init__.py +0 -0
  157. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/style/leaf_info.py +0 -0
  158. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/style/library.py +0 -0
  159. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/tree.py +0 -0
  160. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/typing.py +0 -0
  161. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/utils/geometry.py +0 -0
  162. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/utils/internal.py +0 -0
  163. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/utils/matplotlib.py +0 -0
  164. {iplotx-0.8.0 → iplotx-0.10.0}/iplotx/utils/style.py +0 -0
  165. {iplotx-0.8.0 → iplotx-0.10.0}/scripts/copy_github_release_into_version.sh +0 -0
  166. {iplotx-0.8.0 → iplotx-0.10.0}/scripts/make_banner.py +0 -0
  167. {iplotx-0.8.0 → iplotx-0.10.0}/scripts/update_pylint_badge.sh +0 -0
  168. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_biopython/cascades.png +0 -0
  169. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_biopython/directed_child.png +0 -0
  170. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_biopython/leaf_labels.png +0 -0
  171. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_biopython/leaf_labels_hmargin.png +0 -0
  172. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_biopython/leafedges.png +0 -0
  173. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_biopython/show_support.png +0 -0
  174. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_biopython/tree_basic.png +0 -0
  175. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_biopython/tree_radial.png +0 -0
  176. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_cogent3/leaf_labels.png +0 -0
  177. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_cogent3/leaf_labels_hmargin.png +0 -0
  178. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_cogent3/tree_basic.png +0 -0
  179. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_cogent3/tree_radial.png +0 -0
  180. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_ete4/leaf_labels.png +0 -0
  181. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_ete4/leaf_labels_hmargin.png +0 -0
  182. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_ete4/split_edges.png +0 -0
  183. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_ete4/tree_basic.png +0 -0
  184. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_ete4/tree_radial.png +0 -0
  185. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/clustering_directed.png +0 -0
  186. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/clustering_directed_large.png +0 -0
  187. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/graph_basic.png +0 -0
  188. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/graph_directed.png +0 -0
  189. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/graph_directed_curved_loops.png +0 -0
  190. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/graph_edit_children.png +0 -0
  191. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/graph_labels.png +0 -0
  192. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/graph_layout_attribute.png +0 -0
  193. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/graph_null.png +0 -0
  194. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/graph_squares_directed.png +0 -0
  195. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/graph_vertexsize.png +0 -0
  196. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/graph_with_curved_edges.png +0 -0
  197. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/igraph_layout_object.png +0 -0
  198. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_igraph/multigraph_with_curved_edges_undirected.png +0 -0
  199. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/cluster-layout.png +0 -0
  200. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/complex.png +0 -0
  201. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/complex_rotatelabels.png +0 -0
  202. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/directed_graph.png +0 -0
  203. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/directed_graph_with_colorbar.png +0 -0
  204. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/empty_graph.png +0 -0
  205. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/flat_style.png +0 -0
  206. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/house_with_colors.png +0 -0
  207. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/labels_and_colors.png +0 -0
  208. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/shortest_path.png +0 -0
  209. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_networkx/simple_graph.png +0 -0
  210. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_simple_network_provider/graph_basic.png +0 -0
  211. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_simple_network_provider/graph_directed.png +0 -0
  212. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_simple_network_provider/graph_labels.png +0 -0
  213. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_skbio/leaf_labels.png +0 -0
  214. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_skbio/leaf_labels_hmargin.png +0 -0
  215. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_skbio/tree_basic.png +0 -0
  216. {iplotx-0.8.0 → iplotx-0.10.0}/tests/baseline_images/test_skbio/tree_radial.png +0 -0
  217. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_arrows.py +0 -0
  218. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_biopython.py +0 -0
  219. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_cascades.py +0 -0
  220. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_cogent3.py +0 -0
  221. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_edge.py +0 -0
  222. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_edge_geometry.py +0 -0
  223. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_ete4.py +0 -0
  224. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_geometry.py +0 -0
  225. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_heuristics.py +0 -0
  226. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_ingest_protocols.py +0 -0
  227. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_matplotlib_utils.py +0 -0
  228. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_network_hotload.py +0 -0
  229. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_ports.py +0 -0
  230. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_simple_network_provider.py +0 -0
  231. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_simple_tree_provider.py +0 -0
  232. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_skbio.py +0 -0
  233. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_style.py +0 -0
  234. {iplotx-0.8.0 → iplotx-0.10.0}/tests/test_vertex.py +0 -0
  235. {iplotx-0.8.0 → iplotx-0.10.0}/tests/utils.py +0 -0
@@ -4,10 +4,7 @@
4
4
  name: Python package
5
5
 
6
6
  on:
7
- push:
8
- branches: [ "main" ]
9
- pull_request:
10
- branches: [ "main" ]
7
+ [push, pull_request]
11
8
 
12
9
  jobs:
13
10
  build:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: iplotx
3
- Version: 0.8.0
3
+ Version: 0.10.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
@@ -29,7 +29,6 @@ Requires-Python: >=3.11
29
29
  Requires-Dist: matplotlib>=2.0.0
30
30
  Requires-Dist: numpy>=2.0.0
31
31
  Requires-Dist: pandas>=2.0.0
32
- Requires-Dist: pylint>=3.3.7
33
32
  Provides-Extra: igraph
34
33
  Requires-Dist: igraph>=0.11.0; extra == 'igraph'
35
34
  Provides-Extra: networkx
@@ -6,7 +6,7 @@
6
6
 
7
7
  Computation times
8
8
  =================
9
- **00:00.798** total execution time for 72 files **from all galleries**:
9
+ **00:00.060** total execution time for 73 files **from all galleries**:
10
10
 
11
11
  .. container::
12
12
 
@@ -32,23 +32,8 @@ Computation times
32
32
  * - Example
33
33
  - Time
34
34
  - Mem (MB)
35
- * - :ref:`sphx_glr_gallery_biology_plot_animal_phylogeny.py` (``../../gallery/biology/plot_animal_phylogeny.py``)
36
- - 00:00.614
37
- - 0.0
38
- * - :ref:`sphx_glr_gallery_network_science_plot_social_network_circles.py` (``../../gallery/network_science/plot_social_network_circles.py``)
39
- - 00:00.051
40
- - 0.0
41
- * - :ref:`sphx_glr_gallery_basic_plot_house.py` (``../../gallery/basic/plot_house.py``)
42
- - 00:00.049
43
- - 0.0
44
- * - :ref:`sphx_glr_gallery_style_plot_arrows.py` (``../../gallery/style/plot_arrows.py``)
45
- - 00:00.037
46
- - 0.0
47
- * - :ref:`sphx_glr_gallery_other_plot_feedbacks.py` (``../../gallery/other/plot_feedbacks.py``)
48
- - 00:00.025
49
- - 0.0
50
- * - :ref:`sphx_glr_gallery_style_plot_edgepadding.py` (``../../gallery/style/plot_edgepadding.py``)
51
- - 00:00.021
35
+ * - :ref:`sphx_glr_gallery_basic_plot_3d.py` (``../../gallery/basic/plot_3d.py``)
36
+ - 00:00.060
52
37
  - 0.0
53
38
  * - :ref:`sphx_glr_gallery_basic_plot_basic.py` (``../../gallery/basic/plot_basic.py``)
54
39
  - 00:00.000
@@ -65,12 +50,18 @@ Computation times
65
50
  * - :ref:`sphx_glr_gallery_basic_plot_grouping.py` (``../../gallery/basic/plot_grouping.py``)
66
51
  - 00:00.000
67
52
  - 0.0
53
+ * - :ref:`sphx_glr_gallery_basic_plot_house.py` (``../../gallery/basic/plot_house.py``)
54
+ - 00:00.000
55
+ - 0.0
68
56
  * - :ref:`sphx_glr_gallery_basic_plot_loops.py` (``../../gallery/basic/plot_loops.py``)
69
57
  - 00:00.000
70
58
  - 0.0
71
59
  * - :ref:`sphx_glr_gallery_basic_plot_simple_path.py` (``../../gallery/basic/plot_simple_path.py``)
72
60
  - 00:00.000
73
61
  - 0.0
62
+ * - :ref:`sphx_glr_gallery_biology_plot_animal_phylogeny.py` (``../../gallery/biology/plot_animal_phylogeny.py``)
63
+ - 00:00.000
64
+ - 0.0
74
65
  * - :ref:`sphx_glr_gallery_biology_plot_antibody_clone.py` (``../../gallery/biology/plot_antibody_clone.py``)
75
66
  - 00:00.000
76
67
  - 0.0
@@ -143,6 +134,9 @@ Computation times
143
134
  * - :ref:`sphx_glr_gallery_network_science_plot_simple_networkx.py` (``../../gallery/network_science/plot_simple_networkx.py``)
144
135
  - 00:00.000
145
136
  - 0.0
137
+ * - :ref:`sphx_glr_gallery_network_science_plot_social_network_circles.py` (``../../gallery/network_science/plot_social_network_circles.py``)
138
+ - 00:00.000
139
+ - 0.0
146
140
  * - :ref:`sphx_glr_gallery_network_science_plot_traveling_salesman.py` (``../../gallery/network_science/plot_traveling_salesman.py``)
147
141
  - 00:00.000
148
142
  - 0.0
@@ -155,6 +149,9 @@ Computation times
155
149
  * - :ref:`sphx_glr_gallery_other_plot_edit_artists.py` (``../../gallery/other/plot_edit_artists.py``)
156
150
  - 00:00.000
157
151
  - 0.0
152
+ * - :ref:`sphx_glr_gallery_other_plot_feedbacks.py` (``../../gallery/other/plot_feedbacks.py``)
153
+ - 00:00.000
154
+ - 0.0
158
155
  * - :ref:`sphx_glr_gallery_other_plot_graph.py` (``../../gallery/other/plot_graph.py``)
159
156
  - 00:00.000
160
157
  - 0.0
@@ -164,6 +161,12 @@ Computation times
164
161
  * - :ref:`sphx_glr_gallery_other_plot_train.py` (``../../gallery/other/plot_train.py``)
165
162
  - 00:00.000
166
163
  - 0.0
164
+ * - :ref:`sphx_glr_gallery_style_plot_arrows.py` (``../../gallery/style/plot_arrows.py``)
165
+ - 00:00.000
166
+ - 0.0
167
+ * - :ref:`sphx_glr_gallery_style_plot_edgepadding.py` (``../../gallery/style/plot_edgepadding.py``)
168
+ - 00:00.000
169
+ - 0.0
167
170
  * - :ref:`sphx_glr_gallery_style_plot_elements.py` (``../../gallery/style/plot_elements.py``)
168
171
  - 00:00.000
169
172
  - 0.0
@@ -0,0 +1,29 @@
1
+ """
2
+ 3D layouts
3
+ ==========
4
+
5
+ This example shows how to visualise graphs or networks in 3D using `iplotx`. Of course, a 3D layout is needed
6
+ for this. Here, we use the Fruchterman-Reingold layout algorithm from ``igraph`` to generate a 3D layout.
7
+
8
+ .. warning::
9
+ 3D visualisation does not support all features of 2D visualisation yet. Curved edges, waypoints, and labels
10
+ are currently unsupported. PRs are welcome!
11
+ """
12
+
13
+ import igraph as ig
14
+ import iplotx as ipx
15
+
16
+ # Make the graph
17
+ g = ig.Graph.Erdos_Renyi(30, m=50)
18
+
19
+ # Make a 3D layout
20
+ layout = g.layout_fruchterman_reingold_3d()
21
+
22
+ # Visualise the graph in 3D
23
+ ipx.network(
24
+ g,
25
+ layout,
26
+ vertex_alpha=0.7,
27
+ edge_alpha=0.4,
28
+ figsize=(8, 8),
29
+ )
@@ -9,19 +9,19 @@ library was used to construct the network.
9
9
  from .version import __version__
10
10
  from .plotting import (
11
11
  network,
12
+ graph,
12
13
  tree,
14
+ plot,
13
15
  )
14
16
  import iplotx.artists as artists
15
17
  import iplotx.style as style
16
18
 
17
19
 
18
- # Shortcut to iplotx.plotting.network
19
- plot = network
20
-
21
20
  __all__ = [
22
21
  "network",
23
22
  "tree",
24
23
  "plot",
24
+ "graph",
25
25
  "artists",
26
26
  "style",
27
27
  "__version__",
@@ -0,0 +1,65 @@
1
+ """
2
+ Module containing code to manipulate edge visualisations in 3D, especially the Edge3DCollection class.
3
+ """
4
+
5
+ from mpl_toolkits.mplot3d.art3d import (
6
+ Line3DCollection,
7
+ )
8
+
9
+ from ..utils.matplotlib import (
10
+ _forwarder,
11
+ )
12
+ from ..edge import (
13
+ EdgeCollection,
14
+ )
15
+
16
+
17
+ @_forwarder(
18
+ (
19
+ "set_clip_path",
20
+ "set_clip_box",
21
+ "set_snap",
22
+ "set_sketch_params",
23
+ "set_animated",
24
+ "set_picker",
25
+ )
26
+ )
27
+ class Edge3DCollection(Line3DCollection):
28
+ """Collection of vertex patches for plotting."""
29
+
30
+ pass
31
+
32
+
33
+ def edge_collection_2d_to_3d(
34
+ col: EdgeCollection,
35
+ zdir: str = "z",
36
+ depthshade: bool = True,
37
+ axlim_clip: bool = False,
38
+ ):
39
+ """Convert a 2D EdgeCollection to a 3D Edge3DCollection.
40
+
41
+ Parameters:
42
+ col: The 2D EdgeCollection to convert.
43
+ zs: The z coordinate(s) to use for the 3D vertices.
44
+ zdir: The axis to use as the z axis (default is "z").
45
+ depthshade: Whether to apply depth shading (default is True).
46
+ axlim_clip: Whether to clip the vertices to the axes limits (default is False).
47
+ """
48
+ if not isinstance(col, EdgeCollection):
49
+ raise TypeError("vertices must be a VertexCollection")
50
+
51
+ # TODO: if we make Edge3DCollection a dynamic drawer, this will need to change
52
+ # fundamentally. Also, this currently does not handle labels properly.
53
+ vinfo = col._get_adjacent_vertices_info()
54
+
55
+ segments3d = []
56
+ for offset1, offset2 in vinfo["offsets"]:
57
+ segment = [tuple(offset1), tuple(offset2)]
58
+ segments3d.append(segment)
59
+
60
+ # NOTE: after this line, none of the EdgeCollection methods will work
61
+ # It's become a static drawer now
62
+ col.__class__ = Edge3DCollection
63
+
64
+ col.set_segments(segments3d)
65
+ col._axlim_clip = axlim_clip
@@ -0,0 +1,69 @@
1
+ """
2
+ Module containing code to manipulate vertex visualisations in 3D, especially the Vertex3DCollection class.
3
+ """
4
+
5
+ from typing import (
6
+ Sequence,
7
+ )
8
+ import numpy as np
9
+ from matplotlib import (
10
+ cbook,
11
+ )
12
+ from mpl_toolkits.mplot3d.art3d import Path3DCollection
13
+
14
+ from ..utils.matplotlib import (
15
+ _forwarder,
16
+ )
17
+ from ..vertex import (
18
+ VertexCollection,
19
+ )
20
+
21
+
22
+ @_forwarder(
23
+ (
24
+ "set_clip_path",
25
+ "set_clip_box",
26
+ "set_snap",
27
+ "set_sketch_params",
28
+ "set_animated",
29
+ "set_picker",
30
+ )
31
+ )
32
+ class Vertex3DCollection(VertexCollection, Path3DCollection):
33
+ """Collection of vertex patches for plotting."""
34
+
35
+ def draw(self, renderer) -> None:
36
+ """Draw the collection of vertices in 3D.
37
+
38
+ Parameters:
39
+ renderer: The renderer to use for drawing.
40
+ """
41
+ with self._use_zordered_offset():
42
+ with cbook._setattr_cm(self, _in_draw=True):
43
+ VertexCollection.draw(self, renderer)
44
+
45
+
46
+ def vertex_collection_2d_to_3d(
47
+ col: VertexCollection,
48
+ zs: np.ndarray | float | Sequence[float] = 0,
49
+ zdir: str = "z",
50
+ depthshade: bool = True,
51
+ axlim_clip: bool = False,
52
+ ):
53
+ """Convert a 2D VertexCollection to a 3D Vertex3DCollection.
54
+
55
+ Parameters:
56
+ col: The 2D VertexCollection to convert.
57
+ zs: The z coordinate(s) to use for the 3D vertices.
58
+ zdir: The axis to use as the z axis (default is "z").
59
+ depthshade: Whether to apply depth shading (default is True).
60
+ axlim_clip: Whether to clip the vertices to the axes limits (default is False).
61
+ """
62
+ if not isinstance(col, VertexCollection):
63
+ raise TypeError("vertices must be a VertexCollection")
64
+
65
+ col.__class__ = Vertex3DCollection
66
+ col._offset_zordered = None
67
+ col._depthshade = depthshade
68
+ col._in_draw = False
69
+ col.set_3d_properties(zs, zdir, axlim_clip)
@@ -10,6 +10,8 @@ from .label import LabelCollection
10
10
  from .edge.arrow import EdgeArrowCollection
11
11
  from .edge.leaf import LeafEdgeCollection
12
12
  from .cascades import CascadeCollection
13
+ from .art3d.vertex import Vertex3DCollection
14
+ from .art3d.edge import Edge3DCollection
13
15
 
14
16
 
15
17
  ___all__ = (
@@ -21,4 +23,6 @@ ___all__ = (
21
23
  LabelCollection,
22
24
  EdgeArrowCollection,
23
25
  CascadeCollection,
26
+ Vertex3DCollection,
27
+ Edge3DCollection,
24
28
  )
@@ -193,6 +193,16 @@ class EdgeCollection(mpl.collections.PatchCollection):
193
193
  self._update_arrows()
194
194
  self._update_labels()
195
195
 
196
+ def set_transform(self, transform: mpl.transforms.Transform) -> None:
197
+ """Set the transform for the edges and their children."""
198
+ super().set_transform(transform)
199
+ if hasattr(self, "_subedges"):
200
+ self._subedges.set_transform(transform)
201
+ if hasattr(self, "_arrows"):
202
+ self._arrows.set_offset_transform(transform)
203
+ if hasattr(self, "_label_collection"):
204
+ self._label_collection.set_transform(transform)
205
+
196
206
  @property
197
207
  def directed(self) -> bool:
198
208
  """Whether the network is directed."""
@@ -1,5 +1,7 @@
1
1
  """
2
2
  Support module with geometry- and path-related functions for edges.
3
+
4
+ 3D geometry is in its separate module :mod:`.geometry3d`.
3
5
  """
4
6
 
5
7
  from typing import (
@@ -14,6 +16,7 @@ from ..typing import (
14
16
  Pair,
15
17
  )
16
18
  from .ports import _get_port_unit_vector
19
+ from .geometry3d import _compute_edge_path_3d
17
20
 
18
21
 
19
22
  def _compute_loops_per_angle(nloops, angles):
@@ -65,6 +68,14 @@ def _compute_loops_per_angle(nloops, angles):
65
68
 
66
69
 
67
70
  def _get_shorter_edge_coords(vpath, vsize, theta, shrink=0):
71
+ """Get the coordinates of an edge tip such that it touches the vertex border.
72
+
73
+ Parameters:
74
+ vpath: The vertex path, in figure coordinates (so scaled by dpi).
75
+ vsize: The vertex max size, in figure coordinates (so scaled by dpi).
76
+ theta: The angle of the edge inpinging into the vertex, in radians, in figure coordinates.
77
+ shrink: Additional shrinking of the edge, in figure coordinates (so scaled by dpi).
78
+ """
68
79
  # Bound theta from -pi to pi (why is that not guaranteed?)
69
80
  theta = (theta + pi) % (2 * pi) - pi
70
81
 
@@ -468,7 +479,7 @@ def _compute_edge_path_curved(
468
479
  return path, tuple(thetas)
469
480
 
470
481
 
471
- def _compute_edge_path(
482
+ def _compute_edge_path_2d(
472
483
  *args,
473
484
  tension: float = 0,
474
485
  waypoints: str | tuple[float, float] | Sequence[tuple[float, float]] | np.ndarray = "none",
@@ -502,3 +513,25 @@ def _compute_edge_path(
502
513
  ports=ports,
503
514
  **kwargs,
504
515
  )
516
+
517
+
518
+ def _compute_edge_path(
519
+ vcoord_data,
520
+ *args,
521
+ **kwargs,
522
+ ):
523
+ """Compute the edge path in either 2D or 3D.
524
+
525
+ Parameters:
526
+ vcoord_data: The vertex coordinates in data coordinates. This is used to
527
+ determine the dimensionality of the layout.
528
+ *args: Additional arguments passed to the internal functions.
529
+ **kwargs: Additional keyword arguments passed to the internal functions.
530
+
531
+ Returns:
532
+ The computed edge path and the angles at the start and end of the edge.
533
+ """
534
+ ndim = len(vcoord_data[0])
535
+ if ndim == 2:
536
+ return _compute_edge_path_2d(vcoord_data, *args, **kwargs)
537
+ return _compute_edge_path_3d(vcoord_data, *args, **kwargs)
@@ -0,0 +1,113 @@
1
+ """
2
+ Support for computing edge paths in 3D.
3
+ """
4
+
5
+ from typing import (
6
+ Optional,
7
+ Sequence,
8
+ )
9
+ import numpy as np
10
+ import matplotlib as mpl
11
+
12
+ from ..typing import (
13
+ Pair,
14
+ )
15
+
16
+
17
+ def _compute_edge_path_straight(
18
+ vcoord_data,
19
+ vpath_fig,
20
+ vsize_fig,
21
+ trans,
22
+ trans_inv,
23
+ layout_coordinate_system: str = "cartesian",
24
+ shrink: float = 0,
25
+ **kwargs,
26
+ ):
27
+ """Compute straight edge path between two vertices, in 3D.
28
+
29
+ Parameters:
30
+ vcoord_data: Vertex coordinates in data coordinates, shape (2, 3).
31
+ vpath_fig: Vertex path in figure coordinates.
32
+ vsize_fig: Vertex size in figure coordinates.
33
+ trans: Transformation from data to figure coordinates.
34
+ trans_inv: Inverse transformation from figure to data coordinates.
35
+ layout_coordinate_system: The coordinate system of the layout.
36
+ shrink: Amount to shorten the edge at each end, in figure coordinates.
37
+ **kwargs: Additional keyword arguments (not used).
38
+ Returns:
39
+ A pair with the path and a tuple of angles of exit and entry, in radians.
40
+
41
+ """
42
+
43
+ if layout_coordinate_system not in ("cartesian"):
44
+ raise ValueError(
45
+ f"Layout coordinate system not supported for straight edges in 3D: {layout_coordinate_system}.",
46
+ )
47
+
48
+ vcoord_data_cart = vcoord_data
49
+
50
+ # Coordinates in figure (default) coords
51
+ vcoord_fig = trans(vcoord_data_cart)
52
+
53
+ points = []
54
+
55
+ # Angles of the straight line
56
+ # FIXME: In 2D, this is only used to make space for loops
57
+ # let's ignore for now
58
+ # theta = atan2(*((vcoord_fig[1] - vcoord_fig[0])[::-1]))
59
+ theta = 0
60
+
61
+ # TODO: Shorten at starting vertex (?)
62
+ vs = vcoord_fig[0]
63
+ points.append(vs)
64
+
65
+ # TODO: Shorten at end vertex (?)
66
+ ve = vcoord_fig[1]
67
+ points.append(ve)
68
+
69
+ codes = ["MOVETO", "LINETO"]
70
+ path = mpl.path.Path(
71
+ points,
72
+ codes=[getattr(mpl.path.Path, x) for x in codes],
73
+ )
74
+ path.vertices = trans_inv(path.vertices)
75
+ return path, (theta, theta + np.pi)
76
+
77
+
78
+ def _compute_edge_path_3d(
79
+ *args,
80
+ tension: float = 0,
81
+ waypoints: str | tuple[float, float] | Sequence[tuple[float, float]] | np.ndarray = "none",
82
+ ports: Pair[Optional[str]] = (None, None),
83
+ layout_coordinate_system: str = "cartesian",
84
+ **kwargs,
85
+ ):
86
+ """Compute the edge path in a few different ways."""
87
+ if (waypoints != "none") and (tension != 0):
88
+ raise ValueError("Waypoints not supported for curved edges.")
89
+
90
+ if waypoints != "none":
91
+ raise NotImplementedError("Waypoints not implemented for 3D edges.")
92
+ # return _compute_edge_path_waypoints(
93
+ # waypoints,
94
+ # *args,
95
+ # layout_coordinate_system=layout_coordinate_system,
96
+ # ports=ports,
97
+ # **kwargs,
98
+ # )
99
+
100
+ if np.isscalar(tension) and (tension == 0):
101
+ return _compute_edge_path_straight(
102
+ *args,
103
+ layout_coordinate_system=layout_coordinate_system,
104
+ **kwargs,
105
+ )
106
+
107
+ raise NotImplementedError("Curved edges not implemented for 3D edges.")
108
+ # return _compute_edge_path_curved(
109
+ # tension,
110
+ # *args,
111
+ # ports=ports,
112
+ # **kwargs,
113
+ # )
@@ -4,6 +4,7 @@ Module for vertex groupings code, especially the GroupingArtist class.
4
4
 
5
5
  from typing import Union
6
6
  import numpy as np
7
+ import pandas as pd
7
8
  import matplotlib as mpl
8
9
  from matplotlib.collections import PatchCollection
9
10
 
@@ -64,6 +65,9 @@ class GroupingArtist(PatchCollection):
64
65
  self._points_per_curve = points_per_curve
65
66
 
66
67
  network = kwargs.pop("network", None)
68
+ self.layout = normalise_layout(layout, network=network)
69
+ self.ndim = layout.shape[1]
70
+
67
71
  patches, grouping, coords_hulls = self._create_patches(
68
72
  grouping,
69
73
  layout,
@@ -89,6 +93,21 @@ class GroupingArtist(PatchCollection):
89
93
  self._compute_paths(self.get_figure(root=True).dpi)
90
94
  return ret
91
95
 
96
+ @property
97
+ def axes(self):
98
+ return PatchCollection.axes.__get__(self)
99
+
100
+ @axes.setter
101
+ def axes(self, new_axes):
102
+ PatchCollection.axes.__set__(self, new_axes)
103
+ for child in self.get_children():
104
+ child.axes = new_axes
105
+ self.set_figure(new_axes.figure)
106
+
107
+ def get_layout(self) -> pd.DataFrame:
108
+ """Get the layout used for this grouping."""
109
+ return self.layout
110
+
92
111
  def get_vertexpadding(self) -> float:
93
112
  """Get the vertex padding of each group."""
94
113
  return self._vertexpadding
@@ -98,7 +117,6 @@ class GroupingArtist(PatchCollection):
98
117
  return self.get_vertexpadding() * dpi / 72.0 * self._factor
99
118
 
100
119
  def _create_patches(self, grouping, layout, network, **kwargs):
101
- layout = normalise_layout(layout, network=network)
102
120
  grouping = normalise_grouping(grouping, layout)
103
121
  style = get_style(".grouping")
104
122
  style.pop("vertexpadding", None)
@@ -30,23 +30,22 @@ class IGraphDataProvider(NetworkDataProvider):
30
30
  edge_labels: Optional[Sequence[str] | dict[str]] = None,
31
31
  ) -> NetworkData:
32
32
  """Create network data object for iplotx from an igraph object."""
33
- network = self.network
34
- directed = self.is_directed()
35
33
 
36
- # Recast vertex_labels=False as vertex_labels=None
37
- if np.isscalar(vertex_labels) and (not vertex_labels):
38
- vertex_labels = None
39
-
40
- # Vertices are ordered integers, no gaps
34
+ # Get layout
41
35
  vertex_df = normalise_layout(
42
36
  layout,
43
- network=network,
37
+ network=self.network,
44
38
  nvertices=self.number_of_vertices(),
45
39
  )
46
40
  ndim = vertex_df.shape[1]
47
41
  vertex_df.columns = _make_layout_columns(ndim)
48
42
 
43
+ # Vertices are ordered integers, no gaps
44
+
49
45
  # Vertex labels
46
+ # Recast vertex_labels=False as vertex_labels=None
47
+ if np.isscalar(vertex_labels) and (not vertex_labels):
48
+ vertex_labels = None
50
49
  if vertex_labels is not None:
51
50
  if np.isscalar(vertex_labels):
52
51
  vertex_df["label"] = vertex_df.index.astype(str)
@@ -57,7 +56,7 @@ class IGraphDataProvider(NetworkDataProvider):
57
56
 
58
57
  # Edges are a list of tuples, because of multiedges
59
58
  tmp = []
60
- for edge in network.es:
59
+ for edge in self.network.es:
61
60
  row = {"_ipx_source": edge.source, "_ipx_target": edge.target}
62
61
  row.update(edge.attributes())
63
62
  tmp.append(row)
@@ -76,7 +75,7 @@ class IGraphDataProvider(NetworkDataProvider):
76
75
  network_data = {
77
76
  "vertex_df": vertex_df,
78
77
  "edge_df": edge_df,
79
- "directed": directed,
78
+ "directed": self.is_directed(),
80
79
  "ndim": ndim,
81
80
  }
82
81
  return network_data
@@ -33,25 +33,20 @@ class NetworkXDataProvider(NetworkDataProvider):
33
33
 
34
34
  import networkx as nx
35
35
 
36
- network = self.network
37
-
38
- directed = self.is_directed()
39
-
40
- # Recast vertex_labels=False as vertex_labels=None
41
- if np.isscalar(vertex_labels) and (not vertex_labels):
42
- vertex_labels = None
43
-
44
- # Vertices are indexed by node ID
36
+ # Get layout
45
37
  vertex_df = normalise_layout(
46
38
  layout,
47
- network=network,
39
+ network=self.network,
48
40
  nvertices=self.number_of_vertices(),
49
- ).loc[pd.Index(network.nodes)]
41
+ )
50
42
  ndim = vertex_df.shape[1]
51
43
  vertex_df.columns = _make_layout_columns(ndim)
52
44
 
45
+ # Vertices are indexed by node ID
46
+ vertex_df = vertex_df.loc[pd.Index(self.network.nodes)]
47
+
53
48
  # Vertex internal properties
54
- tmp = pd.DataFrame(dict(network.nodes.data())).T
49
+ tmp = pd.DataFrame(dict(self.network.nodes.data())).T
55
50
  # Arrays become a single column, which we have already anyway
56
51
  if isinstance(layout, str) and (layout in tmp.columns):
57
52
  del tmp[layout]
@@ -60,6 +55,9 @@ class NetworkXDataProvider(NetworkDataProvider):
60
55
  del tmp
61
56
 
62
57
  # Vertex labels
58
+ # Recast vertex_labels=False as vertex_labels=None
59
+ if np.isscalar(vertex_labels) and (not vertex_labels):
60
+ vertex_labels = None
63
61
  if vertex_labels is None:
64
62
  if "label" in vertex_df:
65
63
  del vertex_df["label"]
@@ -78,7 +76,7 @@ class NetworkXDataProvider(NetworkDataProvider):
78
76
 
79
77
  # Edges are a list of tuples, because of multiedges
80
78
  tmp = []
81
- for u, v, d in network.edges.data():
79
+ for u, v, d in self.network.edges.data():
82
80
  row = {"_ipx_source": u, "_ipx_target": v}
83
81
  row.update(d)
84
82
  tmp.append(row)
@@ -112,7 +110,7 @@ class NetworkXDataProvider(NetworkDataProvider):
112
110
  network_data = {
113
111
  "vertex_df": vertex_df,
114
112
  "edge_df": edge_df,
115
- "directed": directed,
113
+ "directed": self.is_directed(),
116
114
  "ndim": ndim,
117
115
  }
118
116
  return network_data
@@ -77,6 +77,17 @@ class LabelCollection(mpl.artist.Artist):
77
77
  child.set_figure(fig)
78
78
  self._update_offsets(dpi=fig.dpi)
79
79
 
80
+ def set_transform(self, transform: mpl.transforms.Transform) -> None:
81
+ """Set the transform for this artist and children.
82
+
83
+ Parameters:
84
+ transform: The transform to set.
85
+ """
86
+ super().set_transform(transform)
87
+ if hasattr(self, "_labelartists"):
88
+ for art in self._labelartists:
89
+ art.set_transform(transform)
90
+
80
91
  def get_texts(self):
81
92
  """Get the texts of the labels."""
82
93
  return [child.get_text() for child in self.get_children()]