okstra 0.108.0 → 0.110.0
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.
- package/README.kr.md +1 -1
- package/README.md +1 -1
- package/docs/kr/architecture.md +3 -3
- package/docs/kr/cli.md +2 -2
- package/docs/project-structure-overview.md +3 -3
- package/package.json +1 -1
- package/runtime/BUILD.json +2 -2
- package/runtime/prompts/profiles/_common-contract.md +1 -1
- package/runtime/python/okstra_ctl/graphify_cmd.py +225 -0
- package/runtime/python/okstra_ctl/resolve_task_key.py +15 -9
- package/runtime/python/okstra_ctl/worktree.py +14 -13
- package/runtime/python/okstra_project/__init__.py +2 -0
- package/runtime/python/okstra_project/state.py +36 -0
- package/runtime/python/okstra_vendor/__init__.py +41 -0
- package/runtime/python/okstra_vendor/graphify/.vendored-version +1 -0
- package/runtime/python/okstra_vendor/graphify/__init__.py +28 -0
- package/runtime/python/okstra_vendor/graphify/__main__.py +1371 -0
- package/runtime/python/okstra_vendor/graphify/analyze.py +540 -0
- package/runtime/python/okstra_vendor/graphify/benchmark.py +129 -0
- package/runtime/python/okstra_vendor/graphify/build.py +107 -0
- package/runtime/python/okstra_vendor/graphify/cache.py +169 -0
- package/runtime/python/okstra_vendor/graphify/cluster.py +137 -0
- package/runtime/python/okstra_vendor/graphify/detect.py +510 -0
- package/runtime/python/okstra_vendor/graphify/export.py +1014 -0
- package/runtime/python/okstra_vendor/graphify/extract.py +3277 -0
- package/runtime/python/okstra_vendor/graphify/hooks.py +220 -0
- package/runtime/python/okstra_vendor/graphify/ingest.py +297 -0
- package/runtime/python/okstra_vendor/graphify/manifest.py +4 -0
- package/runtime/python/okstra_vendor/graphify/report.py +175 -0
- package/runtime/python/okstra_vendor/graphify/security.py +203 -0
- package/runtime/python/okstra_vendor/graphify/serve.py +373 -0
- package/runtime/python/okstra_vendor/graphify/skill-aider.md +1184 -0
- package/runtime/python/okstra_vendor/graphify/skill-claw.md +1184 -0
- package/runtime/python/okstra_vendor/graphify/skill-codex.md +1242 -0
- package/runtime/python/okstra_vendor/graphify/skill-copilot.md +1268 -0
- package/runtime/python/okstra_vendor/graphify/skill-droid.md +1239 -0
- package/runtime/python/okstra_vendor/graphify/skill-kiro.md +1183 -0
- package/runtime/python/okstra_vendor/graphify/skill-opencode.md +1238 -0
- package/runtime/python/okstra_vendor/graphify/skill-trae.md +1208 -0
- package/runtime/python/okstra_vendor/graphify/skill-vscode.md +253 -0
- package/runtime/python/okstra_vendor/graphify/skill-windows.md +1245 -0
- package/runtime/python/okstra_vendor/graphify/skill.md +1319 -0
- package/runtime/python/okstra_vendor/graphify/transcribe.py +182 -0
- package/runtime/python/okstra_vendor/graphify/validate.py +72 -0
- package/runtime/python/okstra_vendor/graphify/watch.py +188 -0
- package/runtime/python/okstra_vendor/graphify/wiki.py +214 -0
- package/runtime/python/okstra_vendor/networkx/__init__.py +62 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/__init__.py +134 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/__init__.py +26 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clique.py +259 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/clustering_coefficient.py +71 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/connectivity.py +412 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/density.py +396 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/distance_measures.py +150 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/dominating_set.py +149 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/kcomponents.py +369 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/matching.py +44 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/maxcut.py +143 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/ramsey.py +53 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/steinertree.py +265 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_approx_clust_coeff.py +41 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_clique.py +112 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_connectivity.py +199 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_density.py +146 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_distance_measures.py +59 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_dominating_set.py +78 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_kcomponents.py +303 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_matching.py +8 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_maxcut.py +94 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_ramsey.py +31 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_steinertree.py +306 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_traveling_salesman.py +1014 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_treewidth.py +274 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/tests/test_vertex_cover.py +68 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/traveling_salesman.py +1508 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/treewidth.py +255 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/approximation/vertex_cover.py +83 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/__init__.py +5 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/connectivity.py +122 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/correlation.py +302 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/mixing.py +255 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/neighbor_degree.py +160 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/pairs.py +127 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/base_test.py +81 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_connectivity.py +143 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_correlation.py +122 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_mixing.py +174 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_neighbor_degree.py +107 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/assortativity/tests/test_pairs.py +87 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/asteroidal.py +164 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/__init__.py +88 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/basic.py +322 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/centrality.py +290 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/cluster.py +289 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/covering.py +57 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/edgelist.py +360 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/extendability.py +105 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/generators.py +603 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/link_analysis.py +316 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matching.py +590 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/matrix.py +232 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/projection.py +526 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/redundancy.py +112 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/spectral.py +69 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_basic.py +125 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_centrality.py +192 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_cluster.py +84 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_covering.py +33 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_edgelist.py +240 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_extendability.py +334 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_generators.py +407 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_link_analysis.py +218 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matching.py +327 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_matrix.py +138 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_project.py +409 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_redundancy.py +35 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bipartite/tests/test_spectral_bipartivity.py +80 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/boundary.py +168 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/bridges.py +205 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/broadcasting.py +164 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/__init__.py +20 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness.py +591 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/betweenness_subset.py +236 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/closeness.py +282 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness.py +364 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_betweenness_subset.py +227 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/current_flow_closeness.py +96 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/degree_alg.py +150 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/dispersion.py +107 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/eigenvector.py +357 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/flow_matrix.py +130 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/group.py +787 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/harmonic.py +88 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/katz.py +331 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/laplacian.py +150 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/load.py +200 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/percolation.py +128 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/reaching.py +209 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/second_order.py +141 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/subgraph_alg.py +361 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality.py +923 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_betweenness_centrality_subset.py +354 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_closeness_centrality.py +274 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality.py +259 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_betweenness_centrality_subset.py +147 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_current_flow_closeness.py +43 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_degree_centrality.py +144 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_dispersion.py +73 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_eigenvector_centrality.py +186 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_group.py +277 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_harmonic_centrality.py +122 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_katz_centrality.py +345 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_laplacian_centrality.py +220 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_load_centrality.py +344 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_percolation_centrality.py +87 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_reaching.py +140 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_second_order_centrality.py +82 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_subgraph.py +110 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_trophic.py +302 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/tests/test_voterank.py +64 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/trophic.py +181 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/centrality/voterank_alg.py +95 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/chains.py +172 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/chordal.py +443 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/clique.py +818 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/cluster.py +732 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/__init__.py +4 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/equitable_coloring.py +505 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/greedy_coloring.py +565 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/coloring/tests/test_coloring.py +863 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/communicability_alg.py +163 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/__init__.py +28 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/asyn_fluid.py +153 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/bipartitions.py +354 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/centrality.py +171 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/community_utils.py +30 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/divisive.py +216 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/kclique.py +79 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/label_propagation.py +338 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/leiden.py +162 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/local.py +220 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/louvain.py +384 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/lukes.py +227 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/modularity_max.py +452 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/quality.py +347 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_asyn_fluid.py +147 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_bipartitions.py +157 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_centrality.py +85 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_divisive.py +106 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_kclique.py +91 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_label_propagation.py +241 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_leiden.py +138 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_local.py +76 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_louvain.py +264 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_lukes.py +152 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_modularity_max.py +340 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_quality.py +139 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/community/tests/test_utils.py +26 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/__init__.py +6 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/attracting.py +115 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/biconnected.py +394 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/connected.py +282 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/semiconnected.py +71 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/strongly_connected.py +359 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_attracting.py +70 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_biconnected.py +248 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_connected.py +138 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_semiconnected.py +55 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_strongly_connected.py +193 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/tests/test_weakly_connected.py +96 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/components/weakly_connected.py +196 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/__init__.py +11 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/connectivity.py +811 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/cuts.py +616 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/disjoint_paths.py +408 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_augmentation.py +1270 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/edge_kcomponents.py +592 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcomponents.py +220 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/kcutsets.py +235 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/stoerwagner.py +152 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_connectivity.py +421 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_cuts.py +309 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_disjoint_paths.py +249 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_augmentation.py +502 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_edge_kcomponents.py +488 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcomponents.py +323 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_kcutsets.py +280 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/tests/test_stoer_wagner.py +102 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/connectivity/utils.py +88 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/core.py +588 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/covering.py +142 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/cuts.py +416 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/cycles.py +1234 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/d_separation.py +677 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/dag.py +1392 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/distance_measures.py +1095 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/distance_regular.py +272 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/dominance.py +142 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/dominating.py +268 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/efficiency_measures.py +167 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/euler.py +470 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/__init__.py +11 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/boykovkolmogorov.py +370 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/capacityscaling.py +407 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/dinitz_alg.py +238 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/edmondskarp.py +241 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/gomory_hu.py +178 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/maxflow.py +611 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/mincost.py +356 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/networksimplex.py +662 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/preflowpush.py +425 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/shortestaugmentingpath.py +300 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gl1.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/gw1.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/netgen-2.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_gomory_hu.py +128 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow.py +573 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_maxflow_large_graph.py +155 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_mincost.py +475 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/test_networksimplex.py +481 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/tests/wlm3.gpickle.bz2 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/flow/utils.py +194 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/graph_hashing.py +435 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/graphical.py +483 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/hierarchy.py +57 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/hybrid.py +196 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isolate.py +107 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/__init__.py +7 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/ismags.py +1306 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorph.py +336 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/isomorphvf2.py +1262 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/matchhelpers.py +352 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/temporalisomorphvf2.py +308 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.A99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/iso_r01_s80.B99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.A99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/si2_b06_m200.B99 +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_ismags.py +719 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphism.py +103 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_isomorphvf2.py +490 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_match_helpers.py +64 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_temporalisomorphvf2.py +212 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_tree_isomorphism.py +202 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp.py +1655 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2pp_helpers.py +3118 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tests/test_vf2userfunc.py +196 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/tree_isomorphism.py +264 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2pp.py +1102 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/isomorphism/vf2userfunc.py +192 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/__init__.py +2 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/hits_alg.py +337 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/pagerank_alg.py +498 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_hits.py +77 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/link_analysis/tests/test_pagerank.py +213 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/link_prediction.py +687 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/lowest_common_ancestors.py +280 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/matching.py +1148 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/minors/__init__.py +27 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/minors/contraction.py +738 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/minors/tests/test_contraction.py +544 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/mis.py +78 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/moral.py +59 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/node_classification.py +219 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/non_randomness.py +155 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/__init__.py +4 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/all.py +324 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/binary.py +468 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/product.py +633 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_all.py +328 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_binary.py +451 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_product.py +491 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/tests/test_unary.py +55 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/operators/unary.py +77 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/perfect_graph.py +73 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/planar_drawing.py +464 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/planarity.py +1463 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/polynomials.py +306 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/reciprocity.py +98 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/regular.py +167 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/richclub.py +138 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/__init__.py +5 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/astar.py +239 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/dense.py +264 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/generic.py +716 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_astar.py +254 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense.py +212 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_dense_numpy.py +88 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_generic.py +511 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_unweighted.py +149 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/tests/test_weighted.py +983 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/unweighted.py +625 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/shortest_paths/weighted.py +2542 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/similarity.py +2107 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/simple_paths.py +966 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/smallworld.py +404 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/smetric.py +30 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/sparsifiers.py +296 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/structuralholes.py +374 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/summarization.py +564 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/swap.py +406 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_asteroidal.py +23 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_boundary.py +154 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_bridges.py +144 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_broadcasting.py +109 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chains.py +136 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_chordal.py +129 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_clique.py +300 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cluster.py +678 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_communicability.py +80 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_core.py +266 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_covering.py +85 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cuts.py +171 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_cycles.py +984 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_d_separation.py +340 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dag.py +835 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_measures.py +831 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_distance_regular.py +85 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominance.py +299 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_dominating.py +115 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_efficiency.py +58 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_euler.py +314 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graph_hashing.py +872 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_graphical.py +163 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hierarchy.py +46 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_hybrid.py +24 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_isolate.py +26 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_link_prediction.py +615 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_lowest_common_ancestors.py +459 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_matching.py +556 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_max_weight_clique.py +179 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_mis.py +62 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_moral.py +15 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_node_classification.py +140 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_non_randomness.py +60 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_perfect_graph.py +27 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planar_drawing.py +274 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_planarity.py +556 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_polynomials.py +57 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_reciprocity.py +37 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_regular.py +88 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_richclub.py +149 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_similarity.py +1158 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_simple_paths.py +803 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smallworld.py +76 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_smetric.py +8 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_sparsifiers.py +138 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_structuralholes.py +191 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_summarization.py +642 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_swap.py +179 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_threshold.py +270 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_time_dependent.py +431 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_tournament.py +161 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_triads.py +248 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_vitality.py +41 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_voronoi.py +103 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_walks.py +54 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tests/test_wiener.py +157 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/threshold.py +981 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/time_dependent.py +142 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tournament.py +406 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/__init__.py +5 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/beamsearch.py +90 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/breadth_first_search.py +576 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/depth_first_search.py +529 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgebfs.py +185 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/edgedfs.py +182 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_beamsearch.py +25 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_bfs.py +203 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_dfs.py +307 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgebfs.py +147 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/traversal/tests/test_edgedfs.py +131 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/__init__.py +7 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/branchings.py +1042 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/coding.py +413 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/decomposition.py +88 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/distance_measures.py +219 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/mst.py +1281 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/operations.py +106 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/recognition.py +273 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_branchings.py +624 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_coding.py +114 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_decomposition.py +79 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_distance_measures.py +99 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_mst.py +934 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_operations.py +53 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/tree/tests/test_recognition.py +174 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/triads.py +500 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/vitality.py +76 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/voronoi.py +86 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/walks.py +77 -0
- package/runtime/python/okstra_vendor/networkx/algorithms/wiener.py +278 -0
- package/runtime/python/okstra_vendor/networkx/classes/__init__.py +13 -0
- package/runtime/python/okstra_vendor/networkx/classes/coreviews.py +435 -0
- package/runtime/python/okstra_vendor/networkx/classes/digraph.py +1363 -0
- package/runtime/python/okstra_vendor/networkx/classes/filters.py +95 -0
- package/runtime/python/okstra_vendor/networkx/classes/function.py +1549 -0
- package/runtime/python/okstra_vendor/networkx/classes/graph.py +2082 -0
- package/runtime/python/okstra_vendor/networkx/classes/graphviews.py +269 -0
- package/runtime/python/okstra_vendor/networkx/classes/multidigraph.py +977 -0
- package/runtime/python/okstra_vendor/networkx/classes/multigraph.py +1294 -0
- package/runtime/python/okstra_vendor/networkx/classes/reportviews.py +1447 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/dispatch_interface.py +192 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/historical_tests.py +476 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_coreviews.py +362 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph.py +331 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_digraph_historical.py +110 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_filters.py +177 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_function.py +1045 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph.py +950 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_graph_historical.py +12 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_graphviews.py +349 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_multidigraph.py +459 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_multigraph.py +528 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_reportviews.py +1421 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_special.py +131 -0
- package/runtime/python/okstra_vendor/networkx/classes/tests/test_subgraphviews.py +371 -0
- package/runtime/python/okstra_vendor/networkx/conftest.py +261 -0
- package/runtime/python/okstra_vendor/networkx/convert.py +502 -0
- package/runtime/python/okstra_vendor/networkx/convert_matrix.py +1314 -0
- package/runtime/python/okstra_vendor/networkx/drawing/__init__.py +7 -0
- package/runtime/python/okstra_vendor/networkx/drawing/layout.py +2036 -0
- package/runtime/python/okstra_vendor/networkx/drawing/nx_agraph.py +470 -0
- package/runtime/python/okstra_vendor/networkx/drawing/nx_latex.py +570 -0
- package/runtime/python/okstra_vendor/networkx/drawing/nx_pydot.py +361 -0
- package/runtime/python/okstra_vendor/networkx/drawing/nx_pylab.py +2978 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_complex.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_empty_graph.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_house_with_colors.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_labels_and_colors.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_display_shortest_path.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/baseline/test_house_with_colors.png +0 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_agraph.py +237 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_image_comparison_pylab_mpl.py +229 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_latex.py +285 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_layout.py +631 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pydot.py +146 -0
- package/runtime/python/okstra_vendor/networkx/drawing/tests/test_pylab.py +1582 -0
- package/runtime/python/okstra_vendor/networkx/exception.py +131 -0
- package/runtime/python/okstra_vendor/networkx/generators/__init__.py +34 -0
- package/runtime/python/okstra_vendor/networkx/generators/atlas.dat.gz +0 -0
- package/runtime/python/okstra_vendor/networkx/generators/atlas.py +227 -0
- package/runtime/python/okstra_vendor/networkx/generators/classic.py +1091 -0
- package/runtime/python/okstra_vendor/networkx/generators/cographs.py +68 -0
- package/runtime/python/okstra_vendor/networkx/generators/community.py +1070 -0
- package/runtime/python/okstra_vendor/networkx/generators/degree_seq.py +886 -0
- package/runtime/python/okstra_vendor/networkx/generators/directed.py +572 -0
- package/runtime/python/okstra_vendor/networkx/generators/duplication.py +174 -0
- package/runtime/python/okstra_vendor/networkx/generators/ego.py +66 -0
- package/runtime/python/okstra_vendor/networkx/generators/expanders.py +499 -0
- package/runtime/python/okstra_vendor/networkx/generators/geometric.py +1037 -0
- package/runtime/python/okstra_vendor/networkx/generators/harary_graph.py +163 -0
- package/runtime/python/okstra_vendor/networkx/generators/internet_as_graphs.py +443 -0
- package/runtime/python/okstra_vendor/networkx/generators/intersection.py +125 -0
- package/runtime/python/okstra_vendor/networkx/generators/interval_graph.py +70 -0
- package/runtime/python/okstra_vendor/networkx/generators/joint_degree_seq.py +664 -0
- package/runtime/python/okstra_vendor/networkx/generators/lattice.py +405 -0
- package/runtime/python/okstra_vendor/networkx/generators/line.py +501 -0
- package/runtime/python/okstra_vendor/networkx/generators/mycielski.py +110 -0
- package/runtime/python/okstra_vendor/networkx/generators/nonisomorphic_trees.py +259 -0
- package/runtime/python/okstra_vendor/networkx/generators/random_clustered.py +117 -0
- package/runtime/python/okstra_vendor/networkx/generators/random_graphs.py +1416 -0
- package/runtime/python/okstra_vendor/networkx/generators/small.py +1070 -0
- package/runtime/python/okstra_vendor/networkx/generators/social.py +554 -0
- package/runtime/python/okstra_vendor/networkx/generators/spectral_graph_forge.py +120 -0
- package/runtime/python/okstra_vendor/networkx/generators/stochastic.py +54 -0
- package/runtime/python/okstra_vendor/networkx/generators/sudoku.py +131 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_atlas.py +75 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_classic.py +642 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_cographs.py +20 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_community.py +362 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_degree_seq.py +224 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_directed.py +189 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_duplication.py +103 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_ego.py +39 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_expanders.py +182 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_geometric.py +488 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_harary_graph.py +133 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_internet_as_graphs.py +221 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_intersection.py +28 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_interval_graph.py +144 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_joint_degree_seq.py +125 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_lattice.py +264 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_line.py +316 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_mycielski.py +30 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_nonisomorphic_trees.py +82 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_clustered.py +33 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_random_graphs.py +495 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_small.py +220 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_spectral_graph_forge.py +49 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_stochastic.py +72 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_sudoku.py +92 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_time_series.py +64 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_trees.py +195 -0
- package/runtime/python/okstra_vendor/networkx/generators/tests/test_triads.py +15 -0
- package/runtime/python/okstra_vendor/networkx/generators/time_series.py +74 -0
- package/runtime/python/okstra_vendor/networkx/generators/trees.py +1070 -0
- package/runtime/python/okstra_vendor/networkx/generators/triads.py +94 -0
- package/runtime/python/okstra_vendor/networkx/lazy_imports.py +188 -0
- package/runtime/python/okstra_vendor/networkx/linalg/__init__.py +13 -0
- package/runtime/python/okstra_vendor/networkx/linalg/algebraicconnectivity.py +650 -0
- package/runtime/python/okstra_vendor/networkx/linalg/attrmatrix.py +466 -0
- package/runtime/python/okstra_vendor/networkx/linalg/bethehessianmatrix.py +77 -0
- package/runtime/python/okstra_vendor/networkx/linalg/graphmatrix.py +168 -0
- package/runtime/python/okstra_vendor/networkx/linalg/laplacianmatrix.py +512 -0
- package/runtime/python/okstra_vendor/networkx/linalg/modularitymatrix.py +166 -0
- package/runtime/python/okstra_vendor/networkx/linalg/spectrum.py +186 -0
- package/runtime/python/okstra_vendor/networkx/linalg/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_algebraic_connectivity.py +400 -0
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_attrmatrix.py +108 -0
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_bethehessian.py +40 -0
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_graphmatrix.py +275 -0
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_laplacian.py +334 -0
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_modularity.py +86 -0
- package/runtime/python/okstra_vendor/networkx/linalg/tests/test_spectrum.py +70 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/__init__.py +17 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/adjlist.py +330 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/edgelist.py +489 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/gexf.py +1084 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/gml.py +879 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/graph6.py +427 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/graphml.py +1053 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/__init__.py +19 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/adjacency.py +156 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/cytoscape.py +190 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/node_link.py +261 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_adjacency.py +78 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_cytoscape.py +78 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_node_link.py +109 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tests/test_tree.py +48 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/json_graph/tree.py +137 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/leda.py +108 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/multiline_adjlist.py +393 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/p2g.py +113 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/pajek.py +286 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/sparse6.py +379 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_adjlist.py +354 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_edgelist.py +318 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gexf.py +612 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_gml.py +744 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graph6.py +181 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_graphml.py +1531 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_leda.py +30 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_p2g.py +63 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_pajek.py +128 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_sparse6.py +166 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/tests/test_text.py +1742 -0
- package/runtime/python/okstra_vendor/networkx/readwrite/text.py +851 -0
- package/runtime/python/okstra_vendor/networkx/relabel.py +285 -0
- package/runtime/python/okstra_vendor/networkx/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_all_random_functions.py +248 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_convert.py +321 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_convert_numpy.py +531 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_convert_pandas.py +349 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_convert_scipy.py +281 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_exceptions.py +40 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_import.py +11 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_lazy_imports.py +96 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_relabel.py +349 -0
- package/runtime/python/okstra_vendor/networkx/tests/test_removed_functions_exception_messages.py +8 -0
- package/runtime/python/okstra_vendor/networkx/utils/__init__.py +8 -0
- package/runtime/python/okstra_vendor/networkx/utils/backends.py +2171 -0
- package/runtime/python/okstra_vendor/networkx/utils/configs.py +396 -0
- package/runtime/python/okstra_vendor/networkx/utils/decorators.py +1233 -0
- package/runtime/python/okstra_vendor/networkx/utils/heaps.py +338 -0
- package/runtime/python/okstra_vendor/networkx/utils/mapped_queue.py +297 -0
- package/runtime/python/okstra_vendor/networkx/utils/misc.py +703 -0
- package/runtime/python/okstra_vendor/networkx/utils/random_sequence.py +198 -0
- package/runtime/python/okstra_vendor/networkx/utils/rcm.py +159 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/__init__.py +0 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test__init.py +11 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_backends.py +225 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_config.py +263 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_decorators.py +510 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_heaps.py +131 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_mapped_queue.py +268 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_misc.py +393 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_random_sequence.py +53 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_rcm.py +63 -0
- package/runtime/python/okstra_vendor/networkx/utils/tests/test_unionfind.py +55 -0
- package/runtime/python/okstra_vendor/networkx/utils/union_find.py +106 -0
- package/runtime/skills/okstra-graphify/SKILL.md +161 -0
- package/runtime/skills/okstra-inspect/SKILL.md +17 -9
- package/runtime/templates/reports/settings.template.json +4 -0
- package/src/cli-registry.mjs +7 -0
- package/src/commands/graphify.mjs +32 -0
- package/src/commands/lifecycle/doctor.mjs +9 -0
- package/src/lib/skill-catalog.mjs +1 -0
|
@@ -0,0 +1,1582 @@
|
|
|
1
|
+
"""Unit tests for matplotlib drawing functions."""
|
|
2
|
+
|
|
3
|
+
import itertools
|
|
4
|
+
import os
|
|
5
|
+
import warnings
|
|
6
|
+
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
import networkx as nx
|
|
10
|
+
|
|
11
|
+
mpl = pytest.importorskip("matplotlib")
|
|
12
|
+
np = pytest.importorskip("numpy")
|
|
13
|
+
mpl.use("PS")
|
|
14
|
+
plt = pytest.importorskip("matplotlib.pyplot")
|
|
15
|
+
plt.rcParams["text.usetex"] = False
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
barbell = nx.barbell_graph(4, 6)
|
|
19
|
+
|
|
20
|
+
defaults = {
|
|
21
|
+
"node_pos": None,
|
|
22
|
+
"node_visible": True,
|
|
23
|
+
"node_color": "#1f78b4",
|
|
24
|
+
"node_size": 300,
|
|
25
|
+
"node_label": {
|
|
26
|
+
"size": 12,
|
|
27
|
+
"color": "#000000",
|
|
28
|
+
"family": "sans-serif",
|
|
29
|
+
"weight": "normal",
|
|
30
|
+
"alpha": 1.0,
|
|
31
|
+
"background_color": None,
|
|
32
|
+
"background_alpha": None,
|
|
33
|
+
"h_align": "center",
|
|
34
|
+
"v_align": "center",
|
|
35
|
+
"bbox": None,
|
|
36
|
+
},
|
|
37
|
+
"node_shape": "o",
|
|
38
|
+
"node_alpha": 1.0,
|
|
39
|
+
"node_border_width": 1.0,
|
|
40
|
+
"node_border_color": "face",
|
|
41
|
+
"edge_visible": True,
|
|
42
|
+
"edge_width": 1.0,
|
|
43
|
+
"edge_color": "#000000",
|
|
44
|
+
"edge_label": {
|
|
45
|
+
"size": 12,
|
|
46
|
+
"color": "#000000",
|
|
47
|
+
"family": "sans-serif",
|
|
48
|
+
"weight": "normal",
|
|
49
|
+
"alpha": 1.0,
|
|
50
|
+
"bbox": {"boxstyle": "round", "ec": (1.0, 1.0, 1.0), "fc": (1.0, 1.0, 1.0)},
|
|
51
|
+
"h_align": "center",
|
|
52
|
+
"v_align": "center",
|
|
53
|
+
"pos": 0.5,
|
|
54
|
+
"rotate": True,
|
|
55
|
+
},
|
|
56
|
+
"edge_style": "-",
|
|
57
|
+
"edge_alpha": 1.0,
|
|
58
|
+
# These are for undirected-graphs. Directed graphs shouls use "-|>" and 10, respectively
|
|
59
|
+
"edge_arrowstyle": "-",
|
|
60
|
+
"edge_arrowsize": 0,
|
|
61
|
+
"edge_curvature": "arc3",
|
|
62
|
+
"edge_source_margin": 0,
|
|
63
|
+
"edge_target_margin": 0,
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@pytest.mark.parametrize(
|
|
68
|
+
("param_name", "param_value", "expected"),
|
|
69
|
+
(
|
|
70
|
+
("node_color", None, defaults["node_color"]),
|
|
71
|
+
("node_color", "#FF0000", "red"),
|
|
72
|
+
("node_color", "color", "lime"),
|
|
73
|
+
),
|
|
74
|
+
)
|
|
75
|
+
def test_display_arg_handling_node_color(param_name, param_value, expected):
|
|
76
|
+
G = nx.path_graph(4)
|
|
77
|
+
nx.set_node_attributes(G, "#00FF00", "color")
|
|
78
|
+
canvas = plt.figure().add_subplot(111)
|
|
79
|
+
nx.display(G, canvas=canvas, **{param_name: param_value})
|
|
80
|
+
assert mpl.colors.same_color(canvas.get_children()[0].get_edgecolors()[0], expected)
|
|
81
|
+
plt.close()
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@pytest.mark.parametrize(
|
|
85
|
+
("param_value", "expected"),
|
|
86
|
+
(
|
|
87
|
+
(None, (1, 1, 1, 1)), # default value
|
|
88
|
+
(0.5, (0.5, 0.5, 0.5, 0.5)),
|
|
89
|
+
("n_alpha", (1.0, 1 / 2, 1 / 3, 0.25)),
|
|
90
|
+
),
|
|
91
|
+
)
|
|
92
|
+
def test_display_arg_handling_node_alpha(param_value, expected):
|
|
93
|
+
G = nx.path_graph(4)
|
|
94
|
+
nx.set_node_attributes(G, {n: 1 / (n + 1) for n in G.nodes()}, "n_alpha")
|
|
95
|
+
canvas = plt.figure().add_subplot(111)
|
|
96
|
+
nx.display(G, canvas=canvas, node_alpha=param_value)
|
|
97
|
+
assert all(
|
|
98
|
+
canvas.get_children()[0].get_fc()[:, 3] == expected
|
|
99
|
+
) # Extract just the alpha from the node colors
|
|
100
|
+
plt.close()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def test_display_node_position():
|
|
104
|
+
G = nx.path_graph(4)
|
|
105
|
+
nx.set_node_attributes(G, {n: (n, n) for n in G.nodes()}, "pos")
|
|
106
|
+
canvas = plt.figure().add_subplot(111)
|
|
107
|
+
nx.display(G, canvas=canvas, node_pos="pos")
|
|
108
|
+
assert np.all(
|
|
109
|
+
canvas.get_children()[0].get_offsets().data == [[0, 0], [1, 1], [2, 2], [3, 3]]
|
|
110
|
+
)
|
|
111
|
+
plt.close()
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def test_display_line_collection():
|
|
115
|
+
G = nx.karate_club_graph()
|
|
116
|
+
nx.set_edge_attributes(
|
|
117
|
+
G, {(u, v): "-|>" if (u + v) % 2 else "-" for u, v in G.edges()}, "arrowstyle"
|
|
118
|
+
)
|
|
119
|
+
canvas = plt.figure().add_subplot(111)
|
|
120
|
+
nx.display(G, canvas=canvas, edge_arrowsize=10)
|
|
121
|
+
# There should only be one line collection in any given visualization
|
|
122
|
+
lc = [
|
|
123
|
+
l
|
|
124
|
+
for l in canvas.get_children()
|
|
125
|
+
if isinstance(l, mpl.collections.LineCollection)
|
|
126
|
+
][0]
|
|
127
|
+
assert len(lc.get_paths()) == sum([1 for u, v in G.edges() if (u + v) % 2])
|
|
128
|
+
plt.close()
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
@pytest.mark.parametrize(
|
|
132
|
+
("edge_color", "expected"),
|
|
133
|
+
(
|
|
134
|
+
(None, "black"),
|
|
135
|
+
("r", "red"),
|
|
136
|
+
((1.0, 1.0, 0.0), "yellow"),
|
|
137
|
+
((0, 1, 0, 1), "lime"),
|
|
138
|
+
("color", "blue"),
|
|
139
|
+
("#0000FF", "blue"),
|
|
140
|
+
),
|
|
141
|
+
)
|
|
142
|
+
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
|
143
|
+
def test_display_edge_single_color(edge_color, expected, graph_type):
|
|
144
|
+
G = nx.path_graph(3, create_using=graph_type)
|
|
145
|
+
nx.set_edge_attributes(G, "#0000FF", "color")
|
|
146
|
+
canvas = plt.figure().add_subplot(111)
|
|
147
|
+
nx.display(G, edge_color=edge_color, canvas=canvas)
|
|
148
|
+
if G.is_directed():
|
|
149
|
+
colors = [
|
|
150
|
+
f.get_fc()
|
|
151
|
+
for f in canvas.get_children()
|
|
152
|
+
if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
153
|
+
]
|
|
154
|
+
else:
|
|
155
|
+
colors = [
|
|
156
|
+
l
|
|
157
|
+
for l in canvas.collections
|
|
158
|
+
if isinstance(l, mpl.collections.LineCollection)
|
|
159
|
+
][0].get_colors()
|
|
160
|
+
assert all(mpl.colors.same_color(c, expected) for c in colors)
|
|
161
|
+
plt.close()
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
|
165
|
+
def test_display_edge_multiple_colors(graph_type):
|
|
166
|
+
G = nx.path_graph(3, create_using=graph_type)
|
|
167
|
+
nx.set_edge_attributes(G, {(0, 1): "#FF0000", (1, 2): (0, 0, 1)}, "color")
|
|
168
|
+
ax = plt.figure().add_subplot(111)
|
|
169
|
+
nx.display(G, canvas=ax)
|
|
170
|
+
expected = ["red", "blue"]
|
|
171
|
+
if G.is_directed():
|
|
172
|
+
colors = [
|
|
173
|
+
f.get_fc()
|
|
174
|
+
for f in ax.get_children()
|
|
175
|
+
if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
176
|
+
]
|
|
177
|
+
else:
|
|
178
|
+
colors = [
|
|
179
|
+
l for l in ax.collections if isinstance(l, mpl.collections.LineCollection)
|
|
180
|
+
][0].get_colors()
|
|
181
|
+
assert mpl.colors.same_color(colors, expected)
|
|
182
|
+
plt.close()
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
|
186
|
+
def test_display_edge_position(graph_type):
|
|
187
|
+
G = nx.path_graph(3, create_using=graph_type)
|
|
188
|
+
nx.set_node_attributes(G, {n: (n, n) for n in G.nodes()}, "pos")
|
|
189
|
+
ax = plt.figure().add_subplot(111)
|
|
190
|
+
nx.display(G, canvas=ax)
|
|
191
|
+
if G.is_directed():
|
|
192
|
+
end_points = [
|
|
193
|
+
(f.get_path().vertices[0, :], f.get_path().vertices[-2, :])
|
|
194
|
+
for f in ax.get_children()
|
|
195
|
+
if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
196
|
+
]
|
|
197
|
+
else:
|
|
198
|
+
line_collection = [
|
|
199
|
+
l for l in ax.collections if isinstance(l, mpl.collections.LineCollection)
|
|
200
|
+
][0]
|
|
201
|
+
end_points = [
|
|
202
|
+
(p.vertices[0, :], p.vertices[-1, :]) for p in line_collection.get_paths()
|
|
203
|
+
]
|
|
204
|
+
expected = [((0, 0), (1, 1)), ((1, 1), (2, 2))]
|
|
205
|
+
# Use the threshold to account for slight shifts in FancyArrowPatch margins to
|
|
206
|
+
# avoid covering the arrow head with the node.
|
|
207
|
+
threshold = 0.05
|
|
208
|
+
for a, e in zip(end_points, expected):
|
|
209
|
+
act_start, act_end = a
|
|
210
|
+
exp_start, exp_end = e
|
|
211
|
+
assert all(abs(act_start - exp_start) < (threshold, threshold)) and all(
|
|
212
|
+
abs(act_end - exp_end) < (threshold, threshold)
|
|
213
|
+
)
|
|
214
|
+
plt.close()
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def test_display_position_function():
|
|
218
|
+
G = nx.karate_club_graph()
|
|
219
|
+
|
|
220
|
+
def fixed_layout(G):
|
|
221
|
+
return nx.spring_layout(G, seed=314159)
|
|
222
|
+
|
|
223
|
+
pos = fixed_layout(G)
|
|
224
|
+
ax = plt.figure().add_subplot(111)
|
|
225
|
+
nx.display(G, node_pos=fixed_layout, canvas=ax)
|
|
226
|
+
# rebuild the position dictionary from the canvas
|
|
227
|
+
act_pos = {
|
|
228
|
+
n: tuple(p) for n, p in zip(G.nodes(), ax.get_children()[0].get_offsets().data)
|
|
229
|
+
}
|
|
230
|
+
for n in G.nodes():
|
|
231
|
+
assert all(pos[n] == act_pos[n])
|
|
232
|
+
plt.close()
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
|
236
|
+
def test_display_edge_colormaps(graph_type):
|
|
237
|
+
G = nx.path_graph(3, create_using=graph_type)
|
|
238
|
+
nx.set_edge_attributes(G, {(0, 1): 0, (1, 2): 1}, "weight")
|
|
239
|
+
cmap = mpl.colormaps["plasma"]
|
|
240
|
+
nx.apply_matplotlib_colors(G, "weight", "color", cmap, nodes=False)
|
|
241
|
+
canvas = plt.figure().add_subplot(111)
|
|
242
|
+
nx.display(G, canvas=canvas)
|
|
243
|
+
mapper = mpl.cm.ScalarMappable(cmap=cmap)
|
|
244
|
+
mapper.set_clim(0, 1)
|
|
245
|
+
expected = [mapper.to_rgba(0), mapper.to_rgba(1)]
|
|
246
|
+
if G.is_directed():
|
|
247
|
+
colors = [
|
|
248
|
+
f.get_facecolor()
|
|
249
|
+
for f in canvas.get_children()
|
|
250
|
+
if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
251
|
+
]
|
|
252
|
+
else:
|
|
253
|
+
colors = [
|
|
254
|
+
l
|
|
255
|
+
for l in canvas.collections
|
|
256
|
+
if isinstance(l, mpl.collections.LineCollection)
|
|
257
|
+
][0].get_colors()
|
|
258
|
+
assert mpl.colors.same_color(expected[0], G.edges[0, 1]["color"])
|
|
259
|
+
assert mpl.colors.same_color(expected[1], G.edges[1, 2]["color"])
|
|
260
|
+
assert mpl.colors.same_color(expected, colors)
|
|
261
|
+
plt.close()
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
|
265
|
+
def test_display_node_colormaps(graph_type):
|
|
266
|
+
G = nx.path_graph(3, create_using=graph_type)
|
|
267
|
+
nx.set_node_attributes(G, {0: 0, 1: 0.5, 2: 1}, "weight")
|
|
268
|
+
cmap = mpl.colormaps["plasma"]
|
|
269
|
+
nx.apply_matplotlib_colors(G, "weight", "color", cmap)
|
|
270
|
+
canvas = plt.figure().add_subplot(111)
|
|
271
|
+
nx.display(G, canvas=canvas)
|
|
272
|
+
mapper = mpl.cm.ScalarMappable(cmap=cmap)
|
|
273
|
+
mapper.set_clim(0, 1)
|
|
274
|
+
expected = [mapper.to_rgba(0), mapper.to_rgba(0.5), mapper.to_rgba(1)]
|
|
275
|
+
colors = [
|
|
276
|
+
s for s in canvas.collections if isinstance(s, mpl.collections.PathCollection)
|
|
277
|
+
][0].get_edgecolors()
|
|
278
|
+
assert mpl.colors.same_color(expected[0], G.nodes[0]["color"])
|
|
279
|
+
assert mpl.colors.same_color(expected[1], G.nodes[1]["color"])
|
|
280
|
+
assert mpl.colors.same_color(expected[2], G.nodes[2]["color"])
|
|
281
|
+
assert mpl.colors.same_color(expected, colors)
|
|
282
|
+
plt.close()
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
@pytest.mark.parametrize(
|
|
286
|
+
("param_value", "expected"),
|
|
287
|
+
(
|
|
288
|
+
(None, [defaults["edge_width"], defaults["edge_width"]]),
|
|
289
|
+
(5, [5, 5]),
|
|
290
|
+
("width", [5, 10]),
|
|
291
|
+
),
|
|
292
|
+
)
|
|
293
|
+
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
|
294
|
+
def test_display_edge_width(param_value, expected, graph_type):
|
|
295
|
+
G = nx.path_graph(3, create_using=graph_type)
|
|
296
|
+
nx.set_edge_attributes(G, {(0, 1): 5, (1, 2): 10}, "width")
|
|
297
|
+
canvas = plt.figure().add_subplot(111)
|
|
298
|
+
nx.display(G, edge_width=param_value, canvas=canvas)
|
|
299
|
+
if G.is_directed():
|
|
300
|
+
widths = [
|
|
301
|
+
f.get_linewidth()
|
|
302
|
+
for f in canvas.get_children()
|
|
303
|
+
if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
304
|
+
]
|
|
305
|
+
else:
|
|
306
|
+
widths = list(
|
|
307
|
+
[
|
|
308
|
+
l
|
|
309
|
+
for l in canvas.collections
|
|
310
|
+
if isinstance(l, mpl.collections.LineCollection)
|
|
311
|
+
][0].get_linewidths()
|
|
312
|
+
)
|
|
313
|
+
assert widths == expected
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
@pytest.mark.parametrize(
|
|
317
|
+
("param_value", "expected"),
|
|
318
|
+
(
|
|
319
|
+
(None, [defaults["edge_style"], defaults["edge_style"]]),
|
|
320
|
+
(":", [":", ":"]),
|
|
321
|
+
("style", ["-", ":"]),
|
|
322
|
+
),
|
|
323
|
+
)
|
|
324
|
+
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
|
325
|
+
def test_display_edge_style(param_value, expected, graph_type):
|
|
326
|
+
G = nx.path_graph(3, create_using=graph_type)
|
|
327
|
+
nx.set_edge_attributes(G, {(0, 1): "-", (1, 2): ":"}, "style")
|
|
328
|
+
canvas = plt.figure().add_subplot(111)
|
|
329
|
+
nx.display(G, edge_style=param_value, canvas=canvas)
|
|
330
|
+
if G.is_directed():
|
|
331
|
+
styles = [
|
|
332
|
+
f.get_linestyle()
|
|
333
|
+
for f in canvas.get_children()
|
|
334
|
+
if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
335
|
+
]
|
|
336
|
+
else:
|
|
337
|
+
# Convert back from tuple description to character form
|
|
338
|
+
linestyles = {(0, None): "-", (0, (1, 1.65)): ":"}
|
|
339
|
+
styles = [
|
|
340
|
+
linestyles[(s[0], tuple(s[1]) if s[1] is not None else None)]
|
|
341
|
+
for s in [
|
|
342
|
+
l
|
|
343
|
+
for l in canvas.collections
|
|
344
|
+
if isinstance(l, mpl.collections.LineCollection)
|
|
345
|
+
][0].get_linestyles()
|
|
346
|
+
]
|
|
347
|
+
assert styles == expected
|
|
348
|
+
plt.close()
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
def test_display_node_labels():
|
|
352
|
+
G = nx.path_graph(4)
|
|
353
|
+
canvas = plt.figure().add_subplot(111)
|
|
354
|
+
nx.display(G, canvas=canvas, node_label={"size": 20})
|
|
355
|
+
labels = [t for t in canvas.get_children() if isinstance(t, mpl.text.Text)]
|
|
356
|
+
for n, l in zip(G.nodes(), labels):
|
|
357
|
+
assert l.get_text() == str(n)
|
|
358
|
+
assert l.get_size() == 20.0
|
|
359
|
+
plt.close()
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def test_display_edge_labels():
|
|
363
|
+
G = nx.path_graph(4)
|
|
364
|
+
canvas = plt.figure().add_subplot(111)
|
|
365
|
+
# While we can pass in dicts for edge label defaults without errors,
|
|
366
|
+
# this isn't helpful unless we want one label for all edges.
|
|
367
|
+
nx.set_edge_attributes(G, {(u, v): {"label": u + v} for u, v in G.edges()})
|
|
368
|
+
nx.display(G, canvas=canvas, edge_label={"color": "r"}, node_label=None)
|
|
369
|
+
labels = [t for t in canvas.get_children() if isinstance(t, mpl.text.Text)]
|
|
370
|
+
print(labels)
|
|
371
|
+
for e, l in zip(G.edges(), labels):
|
|
372
|
+
assert l.get_text() == str(e[0] + e[1])
|
|
373
|
+
assert l.get_color() == "r"
|
|
374
|
+
plt.close()
|
|
375
|
+
|
|
376
|
+
|
|
377
|
+
def test_display_multigraph_non_integer_keys():
|
|
378
|
+
G = nx.MultiGraph()
|
|
379
|
+
G.add_nodes_from(["A", "B", "C", "D"])
|
|
380
|
+
G.add_edges_from(
|
|
381
|
+
[
|
|
382
|
+
("A", "B", "0"),
|
|
383
|
+
("A", "B", "1"),
|
|
384
|
+
("B", "C", "-1"),
|
|
385
|
+
("B", "C", "1"),
|
|
386
|
+
("C", "D", "-1"),
|
|
387
|
+
("C", "D", "0"),
|
|
388
|
+
]
|
|
389
|
+
)
|
|
390
|
+
nx.set_edge_attributes(
|
|
391
|
+
G, {e: f"arc3,rad={0.2 * int(e[2])}" for e in G.edges(keys=True)}, "curvature"
|
|
392
|
+
)
|
|
393
|
+
canvas = plt.figure().add_subplot(111)
|
|
394
|
+
nx.display(G, canvas=canvas)
|
|
395
|
+
rads = [
|
|
396
|
+
f.get_connectionstyle().rad
|
|
397
|
+
for f in canvas.get_children()
|
|
398
|
+
if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
399
|
+
]
|
|
400
|
+
assert rads == [0.0, 0.2, -0.2, 0.2, -0.2, 0.0]
|
|
401
|
+
plt.close()
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def test_display_raises_for_bad_arg():
|
|
405
|
+
G = nx.karate_club_graph()
|
|
406
|
+
with pytest.raises(nx.NetworkXError):
|
|
407
|
+
nx.display(G, bad_arg="bad_arg")
|
|
408
|
+
plt.close()
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def test_display_arrow_size():
|
|
412
|
+
G = nx.path_graph(4, create_using=nx.DiGraph)
|
|
413
|
+
nx.set_edge_attributes(
|
|
414
|
+
G, {(u, v): (u + v + 2) ** 2 for u, v in G.edges()}, "arrowsize"
|
|
415
|
+
)
|
|
416
|
+
ax = plt.axes()
|
|
417
|
+
nx.display(G, canvas=ax)
|
|
418
|
+
assert [9, 25, 49] == [
|
|
419
|
+
f.get_mutation_scale()
|
|
420
|
+
for f in ax.get_children()
|
|
421
|
+
if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
422
|
+
]
|
|
423
|
+
plt.close()
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
def test_display_mismatched_edge_position():
|
|
427
|
+
"""
|
|
428
|
+
This test ensures that a error is raised for incomplete position data.
|
|
429
|
+
"""
|
|
430
|
+
G = nx.path_graph(5)
|
|
431
|
+
# Notice that there is no position for node 3
|
|
432
|
+
nx.set_node_attributes(G, {0: (0, 0), 1: (1, 1), 2: (2, 2), 4: (4, 4)}, "pos")
|
|
433
|
+
# But that's not a problem since we don't want to show node 4, right?
|
|
434
|
+
nx.set_node_attributes(G, {n: n < 4 for n in G.nodes()}, "visible")
|
|
435
|
+
# However, if we try to visualize every edge (including 3 -> 4)...
|
|
436
|
+
# That's a problem since node 4 doesn't have a position
|
|
437
|
+
with pytest.raises(nx.NetworkXError):
|
|
438
|
+
nx.display(G)
|
|
439
|
+
|
|
440
|
+
|
|
441
|
+
# NOTE: parametrizing on marker to test both branches of internal
|
|
442
|
+
# to_marker_edge function
|
|
443
|
+
@pytest.mark.parametrize("node_shape", ("o", "s"))
|
|
444
|
+
def test_display_edge_margins(node_shape):
|
|
445
|
+
"""
|
|
446
|
+
Test that there is a wider gap between the node and the start of an
|
|
447
|
+
incident edge when min_source_margin is specified.
|
|
448
|
+
|
|
449
|
+
This test checks that the use os min_{source/target}_margin edge
|
|
450
|
+
attributes result is shorter (more padding) between the edges and
|
|
451
|
+
source and target nodes.
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
As a crude visual example, let 's' and 't' represent source and target
|
|
455
|
+
nodes, respectively:
|
|
456
|
+
|
|
457
|
+
Default:
|
|
458
|
+
s-----------------------------t
|
|
459
|
+
|
|
460
|
+
With margins:
|
|
461
|
+
s ----------------------- t
|
|
462
|
+
|
|
463
|
+
"""
|
|
464
|
+
ax = plt.figure().add_subplot(111)
|
|
465
|
+
G = nx.DiGraph([(0, 1)])
|
|
466
|
+
nx.set_node_attributes(G, {0: (0, 0), 1: (1, 1)}, "pos")
|
|
467
|
+
# Get the default patches from the regular visualization
|
|
468
|
+
nx.display(G, canvas=ax, node_shape=node_shape)
|
|
469
|
+
default_arrow = [
|
|
470
|
+
f for f in ax.get_children() if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
471
|
+
][0]
|
|
472
|
+
default_extent = default_arrow.get_extents().corners()[::2, 0]
|
|
473
|
+
# Now plot again with margins
|
|
474
|
+
ax = plt.figure().add_subplot(111)
|
|
475
|
+
nx.display(
|
|
476
|
+
G,
|
|
477
|
+
canvas=ax,
|
|
478
|
+
edge_source_margin=100,
|
|
479
|
+
edge_target_margin=100,
|
|
480
|
+
node_shape=node_shape,
|
|
481
|
+
)
|
|
482
|
+
padded_arrow = [
|
|
483
|
+
f for f in ax.get_children() if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
484
|
+
][0]
|
|
485
|
+
padded_extent = padded_arrow.get_extents().corners()[::2, 0]
|
|
486
|
+
|
|
487
|
+
# With padding, the left-most extent of the edge should be further to the right
|
|
488
|
+
assert padded_extent[0] > default_extent[0]
|
|
489
|
+
# And the rightmost extent of the edge, further to the left
|
|
490
|
+
assert padded_extent[1] < default_extent[1]
|
|
491
|
+
plt.close()
|
|
492
|
+
|
|
493
|
+
|
|
494
|
+
@pytest.mark.parametrize("ticks", [False, True])
|
|
495
|
+
def test_display_hide_ticks(ticks):
|
|
496
|
+
G = nx.path_graph(3)
|
|
497
|
+
nx.set_node_attributes(G, {n: (n, n) for n in G.nodes()}, "pos")
|
|
498
|
+
ax = plt.axes()
|
|
499
|
+
nx.display(G, hide_ticks=ticks)
|
|
500
|
+
for axis in [ax.xaxis, ax.yaxis]:
|
|
501
|
+
assert bool(axis.get_ticklabels()) != ticks
|
|
502
|
+
|
|
503
|
+
plt.close()
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def test_display_self_loop():
|
|
507
|
+
ax = plt.axes()
|
|
508
|
+
G = nx.DiGraph()
|
|
509
|
+
G.add_node(0)
|
|
510
|
+
G.add_edge(0, 0)
|
|
511
|
+
nx.set_node_attributes(G, {0: (0, 0)}, "pos")
|
|
512
|
+
nx.display(G, canvas=ax)
|
|
513
|
+
arrow = [
|
|
514
|
+
f for f in ax.get_children() if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
515
|
+
][0]
|
|
516
|
+
bbox = arrow.get_extents()
|
|
517
|
+
print(bbox.width)
|
|
518
|
+
print(bbox.height)
|
|
519
|
+
assert bbox.width > 0 and bbox.height > 0
|
|
520
|
+
|
|
521
|
+
plt.delaxes(ax)
|
|
522
|
+
plt.close()
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def test_display_remove_pos_attr():
|
|
526
|
+
"""
|
|
527
|
+
If the pos attribute isn't provided or is a function, display computes the layout
|
|
528
|
+
and adds it to the graph. We need to ensure that this new attribute is removed from
|
|
529
|
+
the returned graph.
|
|
530
|
+
"""
|
|
531
|
+
G = nx.karate_club_graph()
|
|
532
|
+
nx.display(G)
|
|
533
|
+
assert nx.get_node_attributes(G, "display's position attribute name") == {}
|
|
534
|
+
|
|
535
|
+
|
|
536
|
+
@pytest.fixture
|
|
537
|
+
def subplots():
|
|
538
|
+
fig, ax = plt.subplots()
|
|
539
|
+
yield fig, ax
|
|
540
|
+
plt.delaxes(ax)
|
|
541
|
+
plt.close()
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
@pytest.mark.parametrize(
|
|
545
|
+
"function",
|
|
546
|
+
[
|
|
547
|
+
nx.draw_circular,
|
|
548
|
+
nx.draw_kamada_kawai,
|
|
549
|
+
nx.draw_planar,
|
|
550
|
+
nx.draw_random,
|
|
551
|
+
nx.draw_spectral,
|
|
552
|
+
nx.draw_spring,
|
|
553
|
+
nx.draw_shell,
|
|
554
|
+
nx.draw_forceatlas2,
|
|
555
|
+
],
|
|
556
|
+
)
|
|
557
|
+
def test_draw(function, subplots, tmp_path):
|
|
558
|
+
if function == nx.draw_kamada_kawai:
|
|
559
|
+
pytest.importorskip("scipy", reason="draw_kamada_kawai requires scipy")
|
|
560
|
+
fig, _ = subplots
|
|
561
|
+
options = {"node_color": "black", "node_size": 100, "width": 3}
|
|
562
|
+
function(barbell, **options)
|
|
563
|
+
fig.savefig(tmp_path / "test.ps")
|
|
564
|
+
|
|
565
|
+
|
|
566
|
+
def test_draw_shell_nlist(subplots, tmp_path):
|
|
567
|
+
fig, _ = subplots
|
|
568
|
+
nlist = [list(range(4)), list(range(4, 10)), list(range(10, 14))]
|
|
569
|
+
nx.draw_shell(barbell, nlist=nlist)
|
|
570
|
+
fig.savefig(tmp_path / "test.ps")
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
def test_draw_bipartite(subplots, tmp_path):
|
|
574
|
+
fig, _ = subplots
|
|
575
|
+
G = nx.complete_bipartite_graph(2, 5)
|
|
576
|
+
nx.draw_bipartite(G)
|
|
577
|
+
fig.savefig(tmp_path / "test.ps")
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
def test_edge_colormap():
|
|
581
|
+
colors = range(barbell.number_of_edges())
|
|
582
|
+
nx.draw_spring(
|
|
583
|
+
barbell, edge_color=colors, width=4, edge_cmap=plt.cm.Blues, with_labels=True
|
|
584
|
+
)
|
|
585
|
+
# plt.show()
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def test_draw_networkx_edge_labels(subplots, tmp_path):
|
|
589
|
+
fig, _ = subplots
|
|
590
|
+
edge = (0, 1)
|
|
591
|
+
G = nx.DiGraph([edge])
|
|
592
|
+
pos = {n: (n, n) for n in G}
|
|
593
|
+
nx.draw(G, pos=pos)
|
|
594
|
+
nx.draw_networkx_edge_labels(G, pos, edge_labels={edge: "edge"})
|
|
595
|
+
fig.savefig(tmp_path / "test.ps")
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
def test_arrows():
|
|
599
|
+
nx.draw_spring(barbell.to_directed())
|
|
600
|
+
# plt.show()
|
|
601
|
+
|
|
602
|
+
|
|
603
|
+
@pytest.mark.parametrize(
|
|
604
|
+
("edge_color", "expected"),
|
|
605
|
+
(
|
|
606
|
+
(None, "black"), # Default
|
|
607
|
+
("r", "red"), # Non-default color string
|
|
608
|
+
(["r"], "red"), # Single non-default color in a list
|
|
609
|
+
((1.0, 1.0, 0.0), "yellow"), # single color as rgb tuple
|
|
610
|
+
([(1.0, 1.0, 0.0)], "yellow"), # single color as rgb tuple in list
|
|
611
|
+
((0, 1, 0, 1), "lime"), # single color as rgba tuple
|
|
612
|
+
([(0, 1, 0, 1)], "lime"), # single color as rgba tuple in list
|
|
613
|
+
("#0000ff", "blue"), # single color hex code
|
|
614
|
+
(["#0000ff"], "blue"), # hex code in list
|
|
615
|
+
),
|
|
616
|
+
)
|
|
617
|
+
@pytest.mark.parametrize("edgelist", (None, [(0, 1)]))
|
|
618
|
+
def test_single_edge_color_undirected(edge_color, expected, edgelist):
|
|
619
|
+
"""Tests ways of specifying all edges have a single color for edges
|
|
620
|
+
drawn with a LineCollection"""
|
|
621
|
+
|
|
622
|
+
G = nx.path_graph(3)
|
|
623
|
+
drawn_edges = nx.draw_networkx_edges(
|
|
624
|
+
G, pos=nx.random_layout(G), edgelist=edgelist, edge_color=edge_color
|
|
625
|
+
)
|
|
626
|
+
assert mpl.colors.same_color(drawn_edges.get_color(), expected)
|
|
627
|
+
|
|
628
|
+
|
|
629
|
+
@pytest.mark.parametrize(
|
|
630
|
+
("edge_color", "expected"),
|
|
631
|
+
(
|
|
632
|
+
(None, "black"), # Default
|
|
633
|
+
("r", "red"), # Non-default color string
|
|
634
|
+
(["r"], "red"), # Single non-default color in a list
|
|
635
|
+
((1.0, 1.0, 0.0), "yellow"), # single color as rgb tuple
|
|
636
|
+
([(1.0, 1.0, 0.0)], "yellow"), # single color as rgb tuple in list
|
|
637
|
+
((0, 1, 0, 1), "lime"), # single color as rgba tuple
|
|
638
|
+
([(0, 1, 0, 1)], "lime"), # single color as rgba tuple in list
|
|
639
|
+
("#0000ff", "blue"), # single color hex code
|
|
640
|
+
(["#0000ff"], "blue"), # hex code in list
|
|
641
|
+
),
|
|
642
|
+
)
|
|
643
|
+
@pytest.mark.parametrize("edgelist", (None, [(0, 1)]))
|
|
644
|
+
def test_single_edge_color_directed(edge_color, expected, edgelist):
|
|
645
|
+
"""Tests ways of specifying all edges have a single color for edges drawn
|
|
646
|
+
with FancyArrowPatches"""
|
|
647
|
+
|
|
648
|
+
G = nx.path_graph(3, create_using=nx.DiGraph)
|
|
649
|
+
drawn_edges = nx.draw_networkx_edges(
|
|
650
|
+
G, pos=nx.random_layout(G), edgelist=edgelist, edge_color=edge_color
|
|
651
|
+
)
|
|
652
|
+
for fap in drawn_edges:
|
|
653
|
+
assert mpl.colors.same_color(fap.get_edgecolor(), expected)
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
def test_edge_color_tuple_interpretation():
|
|
657
|
+
"""If edge_color is a sequence with the same length as edgelist, then each
|
|
658
|
+
value in edge_color is mapped onto each edge via colormap."""
|
|
659
|
+
G = nx.path_graph(6, create_using=nx.DiGraph)
|
|
660
|
+
pos = {n: (n, n) for n in range(len(G))}
|
|
661
|
+
|
|
662
|
+
# num edges != 3 or 4 --> edge_color interpreted as rgb(a)
|
|
663
|
+
for ec in ((0, 0, 1), (0, 0, 1, 1)):
|
|
664
|
+
# More than 4 edges
|
|
665
|
+
drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=ec)
|
|
666
|
+
for fap in drawn_edges:
|
|
667
|
+
assert mpl.colors.same_color(fap.get_edgecolor(), ec)
|
|
668
|
+
# Fewer than 3 edges
|
|
669
|
+
drawn_edges = nx.draw_networkx_edges(
|
|
670
|
+
G, pos, edgelist=[(0, 1), (1, 2)], edge_color=ec
|
|
671
|
+
)
|
|
672
|
+
for fap in drawn_edges:
|
|
673
|
+
assert mpl.colors.same_color(fap.get_edgecolor(), ec)
|
|
674
|
+
|
|
675
|
+
# num edges == 3, len(edge_color) == 4: interpreted as rgba
|
|
676
|
+
drawn_edges = nx.draw_networkx_edges(
|
|
677
|
+
G, pos, edgelist=[(0, 1), (1, 2), (2, 3)], edge_color=(0, 0, 1, 1)
|
|
678
|
+
)
|
|
679
|
+
for fap in drawn_edges:
|
|
680
|
+
assert mpl.colors.same_color(fap.get_edgecolor(), "blue")
|
|
681
|
+
|
|
682
|
+
# num edges == 4, len(edge_color) == 3: interpreted as rgb
|
|
683
|
+
drawn_edges = nx.draw_networkx_edges(
|
|
684
|
+
G, pos, edgelist=[(0, 1), (1, 2), (2, 3), (3, 4)], edge_color=(0, 0, 1)
|
|
685
|
+
)
|
|
686
|
+
for fap in drawn_edges:
|
|
687
|
+
assert mpl.colors.same_color(fap.get_edgecolor(), "blue")
|
|
688
|
+
|
|
689
|
+
# num edges == len(edge_color) == 3: interpreted with cmap, *not* as rgb
|
|
690
|
+
drawn_edges = nx.draw_networkx_edges(
|
|
691
|
+
G, pos, edgelist=[(0, 1), (1, 2), (2, 3)], edge_color=(0, 0, 1)
|
|
692
|
+
)
|
|
693
|
+
assert mpl.colors.same_color(
|
|
694
|
+
drawn_edges[0].get_edgecolor(), drawn_edges[1].get_edgecolor()
|
|
695
|
+
)
|
|
696
|
+
for fap in drawn_edges:
|
|
697
|
+
assert not mpl.colors.same_color(fap.get_edgecolor(), "blue")
|
|
698
|
+
|
|
699
|
+
# num edges == len(edge_color) == 4: interpreted with cmap, *not* as rgba
|
|
700
|
+
drawn_edges = nx.draw_networkx_edges(
|
|
701
|
+
G, pos, edgelist=[(0, 1), (1, 2), (2, 3), (3, 4)], edge_color=(0, 0, 1, 1)
|
|
702
|
+
)
|
|
703
|
+
assert mpl.colors.same_color(
|
|
704
|
+
drawn_edges[0].get_edgecolor(), drawn_edges[1].get_edgecolor()
|
|
705
|
+
)
|
|
706
|
+
assert mpl.colors.same_color(
|
|
707
|
+
drawn_edges[2].get_edgecolor(), drawn_edges[3].get_edgecolor()
|
|
708
|
+
)
|
|
709
|
+
for fap in drawn_edges:
|
|
710
|
+
assert not mpl.colors.same_color(fap.get_edgecolor(), "blue")
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
def test_fewer_edge_colors_than_num_edges_directed():
|
|
714
|
+
"""Test that the edge colors are cycled when there are fewer specified
|
|
715
|
+
colors than edges."""
|
|
716
|
+
G = barbell.to_directed()
|
|
717
|
+
pos = nx.random_layout(barbell)
|
|
718
|
+
edgecolors = ("r", "g", "b")
|
|
719
|
+
drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=edgecolors)
|
|
720
|
+
for fap, expected in zip(drawn_edges, itertools.cycle(edgecolors)):
|
|
721
|
+
assert mpl.colors.same_color(fap.get_edgecolor(), expected)
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
def test_more_edge_colors_than_num_edges_directed():
|
|
725
|
+
"""Test that extra edge colors are ignored when there are more specified
|
|
726
|
+
colors than edges."""
|
|
727
|
+
G = nx.path_graph(4, create_using=nx.DiGraph) # 3 edges
|
|
728
|
+
pos = nx.random_layout(barbell)
|
|
729
|
+
edgecolors = ("r", "g", "b", "c") # 4 edge colors
|
|
730
|
+
drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=edgecolors)
|
|
731
|
+
for fap, expected in zip(drawn_edges, edgecolors[:-1]):
|
|
732
|
+
assert mpl.colors.same_color(fap.get_edgecolor(), expected)
|
|
733
|
+
|
|
734
|
+
|
|
735
|
+
def test_edge_color_string_with_global_alpha_undirected():
|
|
736
|
+
edge_collection = nx.draw_networkx_edges(
|
|
737
|
+
barbell,
|
|
738
|
+
pos=nx.random_layout(barbell),
|
|
739
|
+
edgelist=[(0, 1), (1, 2)],
|
|
740
|
+
edge_color="purple",
|
|
741
|
+
alpha=0.2,
|
|
742
|
+
)
|
|
743
|
+
ec = edge_collection.get_color().squeeze() # as rgba tuple
|
|
744
|
+
assert len(edge_collection.get_paths()) == 2
|
|
745
|
+
assert mpl.colors.same_color(ec[:-1], "purple")
|
|
746
|
+
assert ec[-1] == 0.2
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
def test_edge_color_string_with_global_alpha_directed():
|
|
750
|
+
drawn_edges = nx.draw_networkx_edges(
|
|
751
|
+
barbell.to_directed(),
|
|
752
|
+
pos=nx.random_layout(barbell),
|
|
753
|
+
edgelist=[(0, 1), (1, 2)],
|
|
754
|
+
edge_color="purple",
|
|
755
|
+
alpha=0.2,
|
|
756
|
+
)
|
|
757
|
+
assert len(drawn_edges) == 2
|
|
758
|
+
for fap in drawn_edges:
|
|
759
|
+
ec = fap.get_edgecolor() # As rgba tuple
|
|
760
|
+
assert mpl.colors.same_color(ec[:-1], "purple")
|
|
761
|
+
assert ec[-1] == 0.2
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
@pytest.mark.parametrize("graph_type", (nx.Graph, nx.DiGraph))
|
|
765
|
+
def test_edge_width_default_value(graph_type):
|
|
766
|
+
"""Test the default linewidth for edges drawn either via LineCollection or
|
|
767
|
+
FancyArrowPatches."""
|
|
768
|
+
G = nx.path_graph(2, create_using=graph_type)
|
|
769
|
+
pos = {n: (n, n) for n in range(len(G))}
|
|
770
|
+
drawn_edges = nx.draw_networkx_edges(G, pos)
|
|
771
|
+
if isinstance(drawn_edges, list): # directed case: list of FancyArrowPatch
|
|
772
|
+
drawn_edges = drawn_edges[0]
|
|
773
|
+
assert drawn_edges.get_linewidth() == 1
|
|
774
|
+
|
|
775
|
+
|
|
776
|
+
@pytest.mark.parametrize(
|
|
777
|
+
("edgewidth", "expected"),
|
|
778
|
+
(
|
|
779
|
+
(3, 3), # single-value, non-default
|
|
780
|
+
([3], 3), # Single value as a list
|
|
781
|
+
),
|
|
782
|
+
)
|
|
783
|
+
def test_edge_width_single_value_undirected(edgewidth, expected):
|
|
784
|
+
G = nx.path_graph(4)
|
|
785
|
+
pos = {n: (n, n) for n in range(len(G))}
|
|
786
|
+
drawn_edges = nx.draw_networkx_edges(G, pos, width=edgewidth)
|
|
787
|
+
assert len(drawn_edges.get_paths()) == 3
|
|
788
|
+
assert drawn_edges.get_linewidth() == expected
|
|
789
|
+
|
|
790
|
+
|
|
791
|
+
@pytest.mark.parametrize(
|
|
792
|
+
("edgewidth", "expected"),
|
|
793
|
+
(
|
|
794
|
+
(3, 3), # single-value, non-default
|
|
795
|
+
([3], 3), # Single value as a list
|
|
796
|
+
),
|
|
797
|
+
)
|
|
798
|
+
def test_edge_width_single_value_directed(edgewidth, expected):
|
|
799
|
+
G = nx.path_graph(4, create_using=nx.DiGraph)
|
|
800
|
+
pos = {n: (n, n) for n in range(len(G))}
|
|
801
|
+
drawn_edges = nx.draw_networkx_edges(G, pos, width=edgewidth)
|
|
802
|
+
assert len(drawn_edges) == 3
|
|
803
|
+
for fap in drawn_edges:
|
|
804
|
+
assert fap.get_linewidth() == expected
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
@pytest.mark.parametrize(
|
|
808
|
+
"edgelist",
|
|
809
|
+
(
|
|
810
|
+
[(0, 1), (1, 2), (2, 3)], # one width specification per edge
|
|
811
|
+
None, # fewer widths than edges - widths cycle
|
|
812
|
+
[(0, 1), (1, 2)], # More widths than edges - unused widths ignored
|
|
813
|
+
),
|
|
814
|
+
)
|
|
815
|
+
def test_edge_width_sequence(edgelist):
|
|
816
|
+
G = barbell.to_directed()
|
|
817
|
+
pos = nx.random_layout(G)
|
|
818
|
+
widths = (0.5, 2.0, 12.0)
|
|
819
|
+
drawn_edges = nx.draw_networkx_edges(G, pos, edgelist=edgelist, width=widths)
|
|
820
|
+
for fap, expected_width in zip(drawn_edges, itertools.cycle(widths)):
|
|
821
|
+
assert fap.get_linewidth() == expected_width
|
|
822
|
+
|
|
823
|
+
|
|
824
|
+
def test_edge_color_with_edge_vmin_vmax():
|
|
825
|
+
"""Test that edge_vmin and edge_vmax properly set the dynamic range of the
|
|
826
|
+
color map when num edges == len(edge_colors)."""
|
|
827
|
+
G = nx.path_graph(3, create_using=nx.DiGraph)
|
|
828
|
+
pos = nx.random_layout(G)
|
|
829
|
+
# Extract colors from the original (unscaled) colormap
|
|
830
|
+
drawn_edges = nx.draw_networkx_edges(G, pos, edge_color=[0, 1.0])
|
|
831
|
+
orig_colors = [e.get_edgecolor() for e in drawn_edges]
|
|
832
|
+
# Colors from scaled colormap
|
|
833
|
+
drawn_edges = nx.draw_networkx_edges(
|
|
834
|
+
G, pos, edge_color=[0.2, 0.8], edge_vmin=0.2, edge_vmax=0.8
|
|
835
|
+
)
|
|
836
|
+
scaled_colors = [e.get_edgecolor() for e in drawn_edges]
|
|
837
|
+
assert mpl.colors.same_color(orig_colors, scaled_colors)
|
|
838
|
+
|
|
839
|
+
|
|
840
|
+
def test_directed_edges_linestyle_default():
|
|
841
|
+
"""Test default linestyle for edges drawn with FancyArrowPatches."""
|
|
842
|
+
G = nx.path_graph(4, create_using=nx.DiGraph) # Graph with 3 edges
|
|
843
|
+
pos = {n: (n, n) for n in range(len(G))}
|
|
844
|
+
|
|
845
|
+
# edge with default style
|
|
846
|
+
drawn_edges = nx.draw_networkx_edges(G, pos)
|
|
847
|
+
assert len(drawn_edges) == 3
|
|
848
|
+
for fap in drawn_edges:
|
|
849
|
+
assert fap.get_linestyle() == "solid"
|
|
850
|
+
|
|
851
|
+
|
|
852
|
+
@pytest.mark.parametrize(
|
|
853
|
+
"style",
|
|
854
|
+
(
|
|
855
|
+
"dashed", # edge with string style
|
|
856
|
+
"--", # edge with simplified string style
|
|
857
|
+
(1, (1, 1)), # edge with (offset, onoffseq) style
|
|
858
|
+
),
|
|
859
|
+
)
|
|
860
|
+
def test_directed_edges_linestyle_single_value(style):
|
|
861
|
+
"""Tests support for specifying linestyles with a single value to be applied to
|
|
862
|
+
all edges in ``draw_networkx_edges`` for FancyArrowPatch outputs
|
|
863
|
+
(e.g. directed edges)."""
|
|
864
|
+
|
|
865
|
+
G = nx.path_graph(4, create_using=nx.DiGraph) # Graph with 3 edges
|
|
866
|
+
pos = {n: (n, n) for n in range(len(G))}
|
|
867
|
+
|
|
868
|
+
drawn_edges = nx.draw_networkx_edges(G, pos, style=style)
|
|
869
|
+
assert len(drawn_edges) == 3
|
|
870
|
+
for fap in drawn_edges:
|
|
871
|
+
assert fap.get_linestyle() == style
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
@pytest.mark.parametrize(
|
|
875
|
+
"style_seq",
|
|
876
|
+
(
|
|
877
|
+
["dashed"], # edge with string style in list
|
|
878
|
+
["--"], # edge with simplified string style in list
|
|
879
|
+
[(1, (1, 1))], # edge with (offset, onoffseq) style in list
|
|
880
|
+
["--", "-", ":"], # edges with styles for each edge
|
|
881
|
+
["--", "-"], # edges with fewer styles than edges (styles cycle)
|
|
882
|
+
["--", "-", ":", "-."], # edges with more styles than edges (extra unused)
|
|
883
|
+
),
|
|
884
|
+
)
|
|
885
|
+
def test_directed_edges_linestyle_sequence(style_seq):
|
|
886
|
+
"""Tests support for specifying linestyles with sequences in
|
|
887
|
+
``draw_networkx_edges`` for FancyArrowPatch outputs (e.g. directed edges)."""
|
|
888
|
+
|
|
889
|
+
G = nx.path_graph(4, create_using=nx.DiGraph) # Graph with 3 edges
|
|
890
|
+
pos = {n: (n, n) for n in range(len(G))}
|
|
891
|
+
|
|
892
|
+
drawn_edges = nx.draw_networkx_edges(G, pos, style=style_seq)
|
|
893
|
+
assert len(drawn_edges) == 3
|
|
894
|
+
for fap, style in zip(drawn_edges, itertools.cycle(style_seq)):
|
|
895
|
+
assert fap.get_linestyle() == style
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
def test_return_types():
|
|
899
|
+
from matplotlib.collections import LineCollection, PathCollection
|
|
900
|
+
from matplotlib.patches import FancyArrowPatch
|
|
901
|
+
|
|
902
|
+
G = nx.frucht_graph(create_using=nx.Graph)
|
|
903
|
+
dG = nx.frucht_graph(create_using=nx.DiGraph)
|
|
904
|
+
pos = nx.spring_layout(G, seed=42)
|
|
905
|
+
dpos = nx.spring_layout(dG, seed=42)
|
|
906
|
+
# nodes
|
|
907
|
+
nodes = nx.draw_networkx_nodes(G, pos)
|
|
908
|
+
assert isinstance(nodes, PathCollection)
|
|
909
|
+
# edges
|
|
910
|
+
edges = nx.draw_networkx_edges(dG, dpos, arrows=True)
|
|
911
|
+
assert isinstance(edges, list)
|
|
912
|
+
if len(edges) > 0:
|
|
913
|
+
assert isinstance(edges[0], FancyArrowPatch)
|
|
914
|
+
edges = nx.draw_networkx_edges(dG, dpos, arrows=False)
|
|
915
|
+
assert isinstance(edges, LineCollection)
|
|
916
|
+
edges = nx.draw_networkx_edges(G, dpos, arrows=None)
|
|
917
|
+
assert isinstance(edges, LineCollection)
|
|
918
|
+
edges = nx.draw_networkx_edges(dG, pos, arrows=None)
|
|
919
|
+
assert isinstance(edges, list)
|
|
920
|
+
if len(edges) > 0:
|
|
921
|
+
assert isinstance(edges[0], FancyArrowPatch)
|
|
922
|
+
|
|
923
|
+
|
|
924
|
+
def test_labels_and_colors():
|
|
925
|
+
G = nx.cubical_graph()
|
|
926
|
+
pos = nx.spring_layout(G, seed=42) # positions for all nodes
|
|
927
|
+
# nodes
|
|
928
|
+
nx.draw_networkx_nodes(
|
|
929
|
+
G, pos, nodelist=[0, 1, 2, 3], node_color="r", node_size=500, alpha=0.75
|
|
930
|
+
)
|
|
931
|
+
nx.draw_networkx_nodes(
|
|
932
|
+
G,
|
|
933
|
+
pos,
|
|
934
|
+
nodelist=[4, 5, 6, 7],
|
|
935
|
+
node_color="b",
|
|
936
|
+
node_size=500,
|
|
937
|
+
alpha=[0.25, 0.5, 0.75, 1.0],
|
|
938
|
+
)
|
|
939
|
+
# edges
|
|
940
|
+
nx.draw_networkx_edges(G, pos, width=1.0, alpha=0.5)
|
|
941
|
+
nx.draw_networkx_edges(
|
|
942
|
+
G,
|
|
943
|
+
pos,
|
|
944
|
+
edgelist=[(0, 1), (1, 2), (2, 3), (3, 0)],
|
|
945
|
+
width=8,
|
|
946
|
+
alpha=0.5,
|
|
947
|
+
edge_color="r",
|
|
948
|
+
)
|
|
949
|
+
nx.draw_networkx_edges(
|
|
950
|
+
G,
|
|
951
|
+
pos,
|
|
952
|
+
edgelist=[(4, 5), (5, 6), (6, 7), (7, 4)],
|
|
953
|
+
width=8,
|
|
954
|
+
alpha=0.5,
|
|
955
|
+
edge_color="b",
|
|
956
|
+
)
|
|
957
|
+
nx.draw_networkx_edges(
|
|
958
|
+
G,
|
|
959
|
+
pos,
|
|
960
|
+
edgelist=[(4, 5), (5, 6), (6, 7), (7, 4)],
|
|
961
|
+
arrows=True,
|
|
962
|
+
min_source_margin=0.5,
|
|
963
|
+
min_target_margin=0.75,
|
|
964
|
+
width=8,
|
|
965
|
+
edge_color="b",
|
|
966
|
+
)
|
|
967
|
+
# some math labels
|
|
968
|
+
labels = {}
|
|
969
|
+
labels[0] = r"$a$"
|
|
970
|
+
labels[1] = r"$b$"
|
|
971
|
+
labels[2] = r"$c$"
|
|
972
|
+
labels[3] = r"$d$"
|
|
973
|
+
labels[4] = r"$\alpha$"
|
|
974
|
+
labels[5] = r"$\beta$"
|
|
975
|
+
labels[6] = r"$\gamma$"
|
|
976
|
+
labels[7] = r"$\delta$"
|
|
977
|
+
colors = {n: "k" if n % 2 == 0 else "r" for n in range(8)}
|
|
978
|
+
nx.draw_networkx_labels(G, pos, labels, font_size=16)
|
|
979
|
+
nx.draw_networkx_labels(G, pos, labels, font_size=16, font_color=colors)
|
|
980
|
+
nx.draw_networkx_edge_labels(G, pos, edge_labels=None, rotate=False)
|
|
981
|
+
nx.draw_networkx_edge_labels(G, pos, edge_labels={(4, 5): "4-5"})
|
|
982
|
+
# plt.show()
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
def test_axes(subplots):
|
|
986
|
+
fig, ax = subplots
|
|
987
|
+
nx.draw(barbell, ax=ax)
|
|
988
|
+
nx.draw_networkx_edge_labels(barbell, nx.circular_layout(barbell), ax=ax)
|
|
989
|
+
|
|
990
|
+
|
|
991
|
+
def test_empty_graph():
|
|
992
|
+
G = nx.Graph()
|
|
993
|
+
nx.draw(G)
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
def test_draw_empty_nodes_return_values():
|
|
997
|
+
# See Issue #3833
|
|
998
|
+
import matplotlib.collections # call as mpl.collections
|
|
999
|
+
|
|
1000
|
+
G = nx.Graph([(1, 2), (2, 3)])
|
|
1001
|
+
DG = nx.DiGraph([(1, 2), (2, 3)])
|
|
1002
|
+
pos = nx.circular_layout(G)
|
|
1003
|
+
assert isinstance(
|
|
1004
|
+
nx.draw_networkx_nodes(G, pos, nodelist=[]), mpl.collections.PathCollection
|
|
1005
|
+
)
|
|
1006
|
+
assert isinstance(
|
|
1007
|
+
nx.draw_networkx_nodes(DG, pos, nodelist=[]), mpl.collections.PathCollection
|
|
1008
|
+
)
|
|
1009
|
+
|
|
1010
|
+
# drawing empty edges used to return an empty LineCollection or empty list.
|
|
1011
|
+
# Now it is always an empty list (because edges are now lists of FancyArrows)
|
|
1012
|
+
assert nx.draw_networkx_edges(G, pos, edgelist=[], arrows=True) == []
|
|
1013
|
+
assert nx.draw_networkx_edges(G, pos, edgelist=[], arrows=False) == []
|
|
1014
|
+
assert nx.draw_networkx_edges(DG, pos, edgelist=[], arrows=False) == []
|
|
1015
|
+
assert nx.draw_networkx_edges(DG, pos, edgelist=[], arrows=True) == []
|
|
1016
|
+
|
|
1017
|
+
|
|
1018
|
+
def test_multigraph_edgelist_tuples():
|
|
1019
|
+
# See Issue #3295
|
|
1020
|
+
G = nx.path_graph(3, create_using=nx.MultiDiGraph)
|
|
1021
|
+
nx.draw_networkx(G, edgelist=[(0, 1, 0)])
|
|
1022
|
+
nx.draw_networkx(G, edgelist=[(0, 1, 0)], node_size=[10, 20, 0])
|
|
1023
|
+
|
|
1024
|
+
|
|
1025
|
+
def test_alpha_iter():
|
|
1026
|
+
pos = nx.random_layout(barbell)
|
|
1027
|
+
fig = plt.figure()
|
|
1028
|
+
# with fewer alpha elements than nodes
|
|
1029
|
+
fig.add_subplot(131) # Each test in a new axis object
|
|
1030
|
+
nx.draw_networkx_nodes(barbell, pos, alpha=[0.1, 0.2])
|
|
1031
|
+
# with equal alpha elements and nodes
|
|
1032
|
+
num_nodes = len(barbell.nodes)
|
|
1033
|
+
alpha = [x / num_nodes for x in range(num_nodes)]
|
|
1034
|
+
colors = range(num_nodes)
|
|
1035
|
+
fig.add_subplot(132)
|
|
1036
|
+
nx.draw_networkx_nodes(barbell, pos, node_color=colors, alpha=alpha)
|
|
1037
|
+
# with more alpha elements than nodes
|
|
1038
|
+
alpha.append(1)
|
|
1039
|
+
fig.add_subplot(133)
|
|
1040
|
+
nx.draw_networkx_nodes(barbell, pos, alpha=alpha)
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
def test_multiple_node_shapes(subplots):
|
|
1044
|
+
fig, ax = subplots
|
|
1045
|
+
G = nx.path_graph(4)
|
|
1046
|
+
nx.draw(G, node_shape=["o", "h", "s", "^"], ax=ax)
|
|
1047
|
+
scatters = [
|
|
1048
|
+
s for s in ax.get_children() if isinstance(s, mpl.collections.PathCollection)
|
|
1049
|
+
]
|
|
1050
|
+
assert len(scatters) == 4
|
|
1051
|
+
|
|
1052
|
+
|
|
1053
|
+
def test_individualized_font_attributes(subplots):
|
|
1054
|
+
G = nx.karate_club_graph()
|
|
1055
|
+
fig, ax = subplots
|
|
1056
|
+
nx.draw(
|
|
1057
|
+
G,
|
|
1058
|
+
ax=ax,
|
|
1059
|
+
font_color={n: "k" if n % 2 else "r" for n in G.nodes()},
|
|
1060
|
+
font_size={n: int(n / (34 / 15) + 5) for n in G.nodes()},
|
|
1061
|
+
)
|
|
1062
|
+
for n, t in zip(
|
|
1063
|
+
G.nodes(),
|
|
1064
|
+
[
|
|
1065
|
+
t
|
|
1066
|
+
for t in ax.get_children()
|
|
1067
|
+
if isinstance(t, mpl.text.Text) and len(t.get_text()) > 0
|
|
1068
|
+
],
|
|
1069
|
+
):
|
|
1070
|
+
expected = "black" if n % 2 else "red"
|
|
1071
|
+
|
|
1072
|
+
assert mpl.colors.same_color(t.get_color(), expected)
|
|
1073
|
+
assert int(n / (34 / 15) + 5) == t.get_size()
|
|
1074
|
+
|
|
1075
|
+
|
|
1076
|
+
def test_individualized_edge_attributes(subplots):
|
|
1077
|
+
G = nx.karate_club_graph()
|
|
1078
|
+
fig, ax = subplots
|
|
1079
|
+
arrowstyles = ["-|>" if (u + v) % 2 == 0 else "-[" for u, v in G.edges()]
|
|
1080
|
+
arrowsizes = [10 * (u % 2 + v % 2) + 10 for u, v in G.edges()]
|
|
1081
|
+
nx.draw(G, ax=ax, arrows=True, arrowstyle=arrowstyles, arrowsize=arrowsizes)
|
|
1082
|
+
arrows = [
|
|
1083
|
+
f for f in ax.get_children() if isinstance(f, mpl.patches.FancyArrowPatch)
|
|
1084
|
+
]
|
|
1085
|
+
for e, a in zip(G.edges(), arrows):
|
|
1086
|
+
assert a.get_mutation_scale() == 10 * (e[0] % 2 + e[1] % 2) + 10
|
|
1087
|
+
expected = (
|
|
1088
|
+
mpl.patches.ArrowStyle.BracketB
|
|
1089
|
+
if sum(e) % 2
|
|
1090
|
+
else mpl.patches.ArrowStyle.CurveFilledB
|
|
1091
|
+
)
|
|
1092
|
+
assert isinstance(a.get_arrowstyle(), expected)
|
|
1093
|
+
|
|
1094
|
+
|
|
1095
|
+
def test_error_invalid_kwds():
|
|
1096
|
+
with pytest.raises(ValueError, match="Received invalid argument"):
|
|
1097
|
+
nx.draw(barbell, foo="bar")
|
|
1098
|
+
|
|
1099
|
+
|
|
1100
|
+
def test_draw_networkx_arrowsize_incorrect_size():
|
|
1101
|
+
G = nx.DiGraph([(0, 1), (0, 2), (0, 3), (1, 3)])
|
|
1102
|
+
arrowsize = [1, 2, 3]
|
|
1103
|
+
with pytest.raises(
|
|
1104
|
+
ValueError, match="arrowsize should have the same length as edgelist"
|
|
1105
|
+
):
|
|
1106
|
+
nx.draw(G, arrowsize=arrowsize)
|
|
1107
|
+
|
|
1108
|
+
|
|
1109
|
+
@pytest.mark.parametrize("arrowsize", (30, [10, 20, 30]))
|
|
1110
|
+
def test_draw_edges_arrowsize(arrowsize):
|
|
1111
|
+
G = nx.DiGraph([(0, 1), (0, 2), (1, 2)])
|
|
1112
|
+
pos = {0: (0, 0), 1: (0, 1), 2: (1, 0)}
|
|
1113
|
+
edges = nx.draw_networkx_edges(G, pos=pos, arrowsize=arrowsize)
|
|
1114
|
+
|
|
1115
|
+
arrowsize = itertools.repeat(arrowsize) if isinstance(arrowsize, int) else arrowsize
|
|
1116
|
+
|
|
1117
|
+
for fap, expected in zip(edges, arrowsize):
|
|
1118
|
+
assert isinstance(fap, mpl.patches.FancyArrowPatch)
|
|
1119
|
+
assert fap.get_mutation_scale() == expected
|
|
1120
|
+
|
|
1121
|
+
|
|
1122
|
+
@pytest.mark.parametrize("arrowstyle", ("-|>", ["-|>", "-[", "<|-|>"]))
|
|
1123
|
+
def test_draw_edges_arrowstyle(arrowstyle):
|
|
1124
|
+
G = nx.DiGraph([(0, 1), (0, 2), (1, 2)])
|
|
1125
|
+
pos = {0: (0, 0), 1: (0, 1), 2: (1, 0)}
|
|
1126
|
+
edges = nx.draw_networkx_edges(G, pos=pos, arrowstyle=arrowstyle)
|
|
1127
|
+
|
|
1128
|
+
arrowstyle = (
|
|
1129
|
+
itertools.repeat(arrowstyle) if isinstance(arrowstyle, str) else arrowstyle
|
|
1130
|
+
)
|
|
1131
|
+
|
|
1132
|
+
arrow_objects = {
|
|
1133
|
+
"-|>": mpl.patches.ArrowStyle.CurveFilledB,
|
|
1134
|
+
"-[": mpl.patches.ArrowStyle.BracketB,
|
|
1135
|
+
"<|-|>": mpl.patches.ArrowStyle.CurveFilledAB,
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
for fap, expected in zip(edges, arrowstyle):
|
|
1139
|
+
assert isinstance(fap, mpl.patches.FancyArrowPatch)
|
|
1140
|
+
assert isinstance(fap.get_arrowstyle(), arrow_objects[expected])
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
def test_np_edgelist():
|
|
1144
|
+
# see issue #4129
|
|
1145
|
+
nx.draw_networkx(barbell, edgelist=np.array([(0, 2), (0, 3)]))
|
|
1146
|
+
|
|
1147
|
+
|
|
1148
|
+
def test_draw_nodes_missing_node_from_position():
|
|
1149
|
+
G = nx.path_graph(3)
|
|
1150
|
+
pos = {0: (0, 0), 1: (1, 1)} # No position for node 2
|
|
1151
|
+
with pytest.raises(nx.NetworkXError, match="has no position"):
|
|
1152
|
+
nx.draw_networkx_nodes(G, pos)
|
|
1153
|
+
|
|
1154
|
+
|
|
1155
|
+
def test_draw_networkx_nodes_node_shape_list_with_scalar_color(subplots):
|
|
1156
|
+
"""Ensure draw_networkx_nodes works when node_shape is a Python list.
|
|
1157
|
+
|
|
1158
|
+
This covers the case where node_shape is a sequence (list) and node_color
|
|
1159
|
+
is a single scalar color, which should be supported.
|
|
1160
|
+
"""
|
|
1161
|
+
fig, ax = subplots
|
|
1162
|
+
|
|
1163
|
+
G = nx.empty_graph(5)
|
|
1164
|
+
pos = {i: (i, i) for i in G}
|
|
1165
|
+
|
|
1166
|
+
shapes = ["o", "^", "o", "^", "o"]
|
|
1167
|
+
|
|
1168
|
+
nodes = nx.draw_networkx_nodes(
|
|
1169
|
+
G,
|
|
1170
|
+
pos,
|
|
1171
|
+
node_color="red", # scalar color (supported)
|
|
1172
|
+
node_shape=shapes, # list of shapes – this used to be buggy
|
|
1173
|
+
ax=ax,
|
|
1174
|
+
)
|
|
1175
|
+
# Should get a PathCollection with an element in it (same as with numpy arrays)
|
|
1176
|
+
assert len(nodes.get_offsets()) > 0
|
|
1177
|
+
# NOTE: When node_shape is a sequence, draw_networkx_nodes internally calls
|
|
1178
|
+
# ax.scatter multiple times and returns only the last PathCollection.
|
|
1179
|
+
# Therefore, we do NOT assert a value for len(nodes.get_offsets()) here.
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
# NOTE: parametrizing on marker to test both branches of internal
|
|
1183
|
+
# nx.draw_networkx_edges.to_marker_edge function
|
|
1184
|
+
@pytest.mark.parametrize("node_shape", ("o", "s"))
|
|
1185
|
+
def test_draw_edges_min_source_target_margins(node_shape, subplots):
|
|
1186
|
+
"""Test that there is a wider gap between the node and the start of an
|
|
1187
|
+
incident edge when min_source_margin is specified.
|
|
1188
|
+
|
|
1189
|
+
This test checks that the use of min_{source/target}_margin kwargs result
|
|
1190
|
+
in shorter (more padding) between the edges and source and target nodes.
|
|
1191
|
+
As a crude visual example, let 's' and 't' represent source and target
|
|
1192
|
+
nodes, respectively:
|
|
1193
|
+
|
|
1194
|
+
Default:
|
|
1195
|
+
s-----------------------------t
|
|
1196
|
+
|
|
1197
|
+
With margins:
|
|
1198
|
+
s ----------------------- t
|
|
1199
|
+
|
|
1200
|
+
"""
|
|
1201
|
+
# Create a single axis object to get consistent pixel coords across
|
|
1202
|
+
# multiple draws
|
|
1203
|
+
fig, ax = subplots
|
|
1204
|
+
G = nx.DiGraph([(0, 1)])
|
|
1205
|
+
pos = {0: (0, 0), 1: (1, 0)} # horizontal layout
|
|
1206
|
+
# Get leftmost and rightmost points of the FancyArrowPatch object
|
|
1207
|
+
# representing the edge between nodes 0 and 1 (in pixel coordinates)
|
|
1208
|
+
default_patch = nx.draw_networkx_edges(G, pos, ax=ax, node_shape=node_shape)[0]
|
|
1209
|
+
default_extent = default_patch.get_extents().corners()[::2, 0]
|
|
1210
|
+
# Now, do the same but with "padding" for the source and target via the
|
|
1211
|
+
# min_{source/target}_margin kwargs
|
|
1212
|
+
padded_patch = nx.draw_networkx_edges(
|
|
1213
|
+
G,
|
|
1214
|
+
pos,
|
|
1215
|
+
ax=ax,
|
|
1216
|
+
node_shape=node_shape,
|
|
1217
|
+
min_source_margin=100,
|
|
1218
|
+
min_target_margin=100,
|
|
1219
|
+
)[0]
|
|
1220
|
+
padded_extent = padded_patch.get_extents().corners()[::2, 0]
|
|
1221
|
+
|
|
1222
|
+
# With padding, the left-most extent of the edge should be further to the
|
|
1223
|
+
# right
|
|
1224
|
+
assert padded_extent[0] > default_extent[0]
|
|
1225
|
+
# And the rightmost extent of the edge, further to the left
|
|
1226
|
+
assert padded_extent[1] < default_extent[1]
|
|
1227
|
+
|
|
1228
|
+
|
|
1229
|
+
# NOTE: parametrizing on marker to test both branches of internal
|
|
1230
|
+
# nx.draw_networkx_edges.to_marker_edge function
|
|
1231
|
+
@pytest.mark.parametrize("node_shape", ("o", "s"))
|
|
1232
|
+
def test_draw_edges_min_source_target_margins_individual(node_shape, subplots):
|
|
1233
|
+
"""Test that there is a wider gap between the node and the start of an
|
|
1234
|
+
incident edge when min_source_margin is specified.
|
|
1235
|
+
|
|
1236
|
+
This test checks that the use of min_{source/target}_margin kwargs result
|
|
1237
|
+
in shorter (more padding) between the edges and source and target nodes.
|
|
1238
|
+
As a crude visual example, let 's' and 't' represent source and target
|
|
1239
|
+
nodes, respectively:
|
|
1240
|
+
|
|
1241
|
+
Default:
|
|
1242
|
+
s-----------------------------t
|
|
1243
|
+
|
|
1244
|
+
With margins:
|
|
1245
|
+
s ----------------------- t
|
|
1246
|
+
|
|
1247
|
+
"""
|
|
1248
|
+
# Create a single axis object to get consistent pixel coords across
|
|
1249
|
+
# multiple draws
|
|
1250
|
+
fig, ax = subplots
|
|
1251
|
+
G = nx.DiGraph([(0, 1), (1, 2)])
|
|
1252
|
+
pos = {0: (0, 0), 1: (1, 0), 2: (2, 0)} # horizontal layout
|
|
1253
|
+
# Get leftmost and rightmost points of the FancyArrowPatch object
|
|
1254
|
+
# representing the edge between nodes 0 and 1 (in pixel coordinates)
|
|
1255
|
+
default_patch = nx.draw_networkx_edges(G, pos, ax=ax, node_shape=node_shape)
|
|
1256
|
+
default_extent = [d.get_extents().corners()[::2, 0] for d in default_patch]
|
|
1257
|
+
# Now, do the same but with "padding" for the source and target via the
|
|
1258
|
+
# min_{source/target}_margin kwargs
|
|
1259
|
+
padded_patch = nx.draw_networkx_edges(
|
|
1260
|
+
G,
|
|
1261
|
+
pos,
|
|
1262
|
+
ax=ax,
|
|
1263
|
+
node_shape=node_shape,
|
|
1264
|
+
min_source_margin=[98, 102],
|
|
1265
|
+
min_target_margin=[98, 102],
|
|
1266
|
+
)
|
|
1267
|
+
padded_extent = [p.get_extents().corners()[::2, 0] for p in padded_patch]
|
|
1268
|
+
for d, p in zip(default_extent, padded_extent):
|
|
1269
|
+
# With padding, the left-most extent of the edge should be further to the
|
|
1270
|
+
# right
|
|
1271
|
+
assert p[0] > d[0]
|
|
1272
|
+
# And the rightmost extent of the edge, further to the left
|
|
1273
|
+
assert p[1] < d[1]
|
|
1274
|
+
|
|
1275
|
+
|
|
1276
|
+
def test_nonzero_selfloop_with_single_node(subplots):
|
|
1277
|
+
"""Ensure that selfloop extent is non-zero when there is only one node."""
|
|
1278
|
+
# Create explicit axis object for test
|
|
1279
|
+
fig, ax = subplots
|
|
1280
|
+
# Graph with single node + self loop
|
|
1281
|
+
G = nx.DiGraph()
|
|
1282
|
+
G.add_node(0)
|
|
1283
|
+
G.add_edge(0, 0)
|
|
1284
|
+
# Draw
|
|
1285
|
+
patch = nx.draw_networkx_edges(G, {0: (0, 0)})[0]
|
|
1286
|
+
# The resulting patch must have non-zero extent
|
|
1287
|
+
bbox = patch.get_extents()
|
|
1288
|
+
assert bbox.width > 0 and bbox.height > 0
|
|
1289
|
+
|
|
1290
|
+
|
|
1291
|
+
def test_nonzero_selfloop_with_single_edge_in_edgelist(subplots):
|
|
1292
|
+
"""Ensure that selfloop extent is non-zero when only a single edge is
|
|
1293
|
+
specified in the edgelist.
|
|
1294
|
+
"""
|
|
1295
|
+
# Create explicit axis object for test
|
|
1296
|
+
fig, ax = subplots
|
|
1297
|
+
# Graph with selfloop
|
|
1298
|
+
G = nx.path_graph(2, create_using=nx.DiGraph)
|
|
1299
|
+
G.add_edge(1, 1)
|
|
1300
|
+
pos = {n: (n, n) for n in G.nodes}
|
|
1301
|
+
# Draw only the selfloop edge via the `edgelist` kwarg
|
|
1302
|
+
patch = nx.draw_networkx_edges(G, pos, edgelist=[(1, 1)])[0]
|
|
1303
|
+
# The resulting patch must have non-zero extent
|
|
1304
|
+
bbox = patch.get_extents()
|
|
1305
|
+
assert bbox.width > 0 and bbox.height > 0
|
|
1306
|
+
|
|
1307
|
+
|
|
1308
|
+
def test_apply_alpha():
|
|
1309
|
+
"""Test apply_alpha when there is a mismatch between the number of
|
|
1310
|
+
supplied colors and elements.
|
|
1311
|
+
"""
|
|
1312
|
+
nodelist = [0, 1, 2]
|
|
1313
|
+
colorlist = ["r", "g", "b"]
|
|
1314
|
+
alpha = 0.5
|
|
1315
|
+
rgba_colors = nx.drawing.nx_pylab.apply_alpha(colorlist, alpha, nodelist)
|
|
1316
|
+
assert all(rgba_colors[:, -1] == alpha)
|
|
1317
|
+
|
|
1318
|
+
|
|
1319
|
+
def test_draw_edges_toggling_with_arrows_kwarg():
|
|
1320
|
+
"""
|
|
1321
|
+
The `arrows` keyword argument is used as a 3-way switch to select which
|
|
1322
|
+
type of object to use for drawing edges:
|
|
1323
|
+
- ``arrows=None`` -> default (FancyArrowPatches for directed, else LineCollection)
|
|
1324
|
+
- ``arrows=True`` -> FancyArrowPatches
|
|
1325
|
+
- ``arrows=False`` -> LineCollection
|
|
1326
|
+
"""
|
|
1327
|
+
import matplotlib.collections
|
|
1328
|
+
import matplotlib.patches
|
|
1329
|
+
|
|
1330
|
+
UG = nx.path_graph(3)
|
|
1331
|
+
DG = nx.path_graph(3, create_using=nx.DiGraph)
|
|
1332
|
+
pos = {n: (n, n) for n in UG}
|
|
1333
|
+
|
|
1334
|
+
# Use FancyArrowPatches when arrows=True, regardless of graph type
|
|
1335
|
+
for G in (UG, DG):
|
|
1336
|
+
edges = nx.draw_networkx_edges(G, pos, arrows=True)
|
|
1337
|
+
assert len(edges) == len(G.edges)
|
|
1338
|
+
assert isinstance(edges[0], mpl.patches.FancyArrowPatch)
|
|
1339
|
+
|
|
1340
|
+
# Use LineCollection when arrows=False, regardless of graph type
|
|
1341
|
+
for G in (UG, DG):
|
|
1342
|
+
edges = nx.draw_networkx_edges(G, pos, arrows=False)
|
|
1343
|
+
assert isinstance(edges, mpl.collections.LineCollection)
|
|
1344
|
+
|
|
1345
|
+
# Default behavior when arrows=None: FAPs for directed, LC's for undirected
|
|
1346
|
+
edges = nx.draw_networkx_edges(UG, pos)
|
|
1347
|
+
assert isinstance(edges, mpl.collections.LineCollection)
|
|
1348
|
+
edges = nx.draw_networkx_edges(DG, pos)
|
|
1349
|
+
assert len(edges) == len(G.edges)
|
|
1350
|
+
assert isinstance(edges[0], mpl.patches.FancyArrowPatch)
|
|
1351
|
+
|
|
1352
|
+
|
|
1353
|
+
@pytest.mark.parametrize("drawing_func", (nx.draw, nx.draw_networkx))
|
|
1354
|
+
def test_draw_networkx_arrows_default_undirected(drawing_func, subplots):
|
|
1355
|
+
import matplotlib.collections
|
|
1356
|
+
|
|
1357
|
+
G = nx.path_graph(3)
|
|
1358
|
+
fig, ax = subplots
|
|
1359
|
+
drawing_func(G, ax=ax)
|
|
1360
|
+
assert any(isinstance(c, mpl.collections.LineCollection) for c in ax.collections)
|
|
1361
|
+
assert not ax.patches
|
|
1362
|
+
|
|
1363
|
+
|
|
1364
|
+
@pytest.mark.parametrize("drawing_func", (nx.draw, nx.draw_networkx))
|
|
1365
|
+
def test_draw_networkx_arrows_default_directed(drawing_func, subplots):
|
|
1366
|
+
import matplotlib.collections
|
|
1367
|
+
|
|
1368
|
+
G = nx.path_graph(3, create_using=nx.DiGraph)
|
|
1369
|
+
fig, ax = subplots
|
|
1370
|
+
drawing_func(G, ax=ax)
|
|
1371
|
+
assert not any(
|
|
1372
|
+
isinstance(c, mpl.collections.LineCollection) for c in ax.collections
|
|
1373
|
+
)
|
|
1374
|
+
assert ax.patches
|
|
1375
|
+
|
|
1376
|
+
|
|
1377
|
+
def test_edgelist_kwarg_not_ignored(subplots):
|
|
1378
|
+
# See gh-4994
|
|
1379
|
+
G = nx.path_graph(3)
|
|
1380
|
+
G.add_edge(0, 0)
|
|
1381
|
+
fig, ax = subplots
|
|
1382
|
+
nx.draw(G, edgelist=[(0, 1), (1, 2)], ax=ax) # Exclude self-loop from edgelist
|
|
1383
|
+
assert not ax.patches
|
|
1384
|
+
|
|
1385
|
+
|
|
1386
|
+
@pytest.mark.parametrize(
|
|
1387
|
+
("G", "expected_n_edges"),
|
|
1388
|
+
([nx.DiGraph(), 2], [nx.MultiGraph(), 4], [nx.MultiDiGraph(), 4]),
|
|
1389
|
+
)
|
|
1390
|
+
def test_draw_networkx_edges_multiedge_connectionstyle(G, expected_n_edges):
|
|
1391
|
+
"""Draws edges correctly for 3 types of graphs and checks for valid length"""
|
|
1392
|
+
for i, (u, v) in enumerate([(0, 1), (0, 1), (0, 1), (0, 2)]):
|
|
1393
|
+
G.add_edge(u, v, weight=round(i / 3, 2))
|
|
1394
|
+
pos = {n: (n, n) for n in G}
|
|
1395
|
+
# Raises on insufficient connectionstyle length
|
|
1396
|
+
for conn_style in [
|
|
1397
|
+
"arc3,rad=0.1",
|
|
1398
|
+
["arc3,rad=0.1", "arc3,rad=0.1"],
|
|
1399
|
+
["arc3,rad=0.1", "arc3,rad=0.1", "arc3,rad=0.2"],
|
|
1400
|
+
]:
|
|
1401
|
+
nx.draw_networkx_edges(G, pos, connectionstyle=conn_style)
|
|
1402
|
+
arrows = nx.draw_networkx_edges(G, pos, connectionstyle=conn_style)
|
|
1403
|
+
assert len(arrows) == expected_n_edges
|
|
1404
|
+
|
|
1405
|
+
|
|
1406
|
+
@pytest.mark.parametrize(
|
|
1407
|
+
("G", "expected_n_edges"),
|
|
1408
|
+
([nx.DiGraph(), 2], [nx.MultiGraph(), 4], [nx.MultiDiGraph(), 4]),
|
|
1409
|
+
)
|
|
1410
|
+
def test_draw_networkx_edge_labels_multiedge_connectionstyle(G, expected_n_edges):
|
|
1411
|
+
"""Draws labels correctly for 3 types of graphs and checks for valid length and class names"""
|
|
1412
|
+
for i, (u, v) in enumerate([(0, 1), (0, 1), (0, 1), (0, 2)]):
|
|
1413
|
+
G.add_edge(u, v, weight=round(i / 3, 2))
|
|
1414
|
+
pos = {n: (n, n) for n in G}
|
|
1415
|
+
# Raises on insufficient connectionstyle length
|
|
1416
|
+
arrows = nx.draw_networkx_edges(
|
|
1417
|
+
G, pos, connectionstyle=["arc3,rad=0.1", "arc3,rad=0.1", "arc3,rad=0.1"]
|
|
1418
|
+
)
|
|
1419
|
+
for conn_style in [
|
|
1420
|
+
"arc3,rad=0.1",
|
|
1421
|
+
["arc3,rad=0.1", "arc3,rad=0.2"],
|
|
1422
|
+
["arc3,rad=0.1", "arc3,rad=0.1", "arc3,rad=0.1"],
|
|
1423
|
+
]:
|
|
1424
|
+
text_items = nx.draw_networkx_edge_labels(G, pos, connectionstyle=conn_style)
|
|
1425
|
+
assert len(text_items) == expected_n_edges
|
|
1426
|
+
for ti in text_items.values():
|
|
1427
|
+
assert ti.__class__.__name__ == "CurvedArrowText"
|
|
1428
|
+
|
|
1429
|
+
|
|
1430
|
+
def test_draw_networkx_edge_label_multiedge():
|
|
1431
|
+
G = nx.MultiGraph()
|
|
1432
|
+
G.add_edge(0, 1, weight=10)
|
|
1433
|
+
G.add_edge(0, 1, weight=20)
|
|
1434
|
+
edge_labels = nx.get_edge_attributes(G, "weight") # Includes edge keys
|
|
1435
|
+
pos = {n: (n, n) for n in G}
|
|
1436
|
+
text_items = nx.draw_networkx_edge_labels(
|
|
1437
|
+
G,
|
|
1438
|
+
pos,
|
|
1439
|
+
edge_labels=edge_labels,
|
|
1440
|
+
connectionstyle=["arc3,rad=0.1", "arc3,rad=0.2"],
|
|
1441
|
+
)
|
|
1442
|
+
assert len(text_items) == 2
|
|
1443
|
+
|
|
1444
|
+
|
|
1445
|
+
def test_draw_networkx_edge_label_empty_dict():
|
|
1446
|
+
"""Regression test for draw_networkx_edge_labels with empty dict. See
|
|
1447
|
+
gh-5372."""
|
|
1448
|
+
G = nx.path_graph(3)
|
|
1449
|
+
pos = {n: (n, n) for n in G.nodes}
|
|
1450
|
+
assert nx.draw_networkx_edge_labels(G, pos, edge_labels={}) == {}
|
|
1451
|
+
|
|
1452
|
+
|
|
1453
|
+
def test_draw_networkx_edges_undirected_selfloop_colors(subplots):
|
|
1454
|
+
"""When an edgelist is supplied along with a sequence of colors, check that
|
|
1455
|
+
the self-loops have the correct colors."""
|
|
1456
|
+
fig, ax = subplots
|
|
1457
|
+
# Edge list and corresponding colors
|
|
1458
|
+
edgelist = [(1, 3), (1, 2), (2, 3), (1, 1), (3, 3), (2, 2)]
|
|
1459
|
+
edge_colors = ["pink", "cyan", "black", "red", "blue", "green"]
|
|
1460
|
+
|
|
1461
|
+
G = nx.Graph(edgelist)
|
|
1462
|
+
pos = {n: (n, n) for n in G.nodes}
|
|
1463
|
+
nx.draw_networkx_edges(G, pos, ax=ax, edgelist=edgelist, edge_color=edge_colors)
|
|
1464
|
+
|
|
1465
|
+
# Verify that there are three fancy arrow patches (1 per self loop)
|
|
1466
|
+
assert len(ax.patches) == 3
|
|
1467
|
+
|
|
1468
|
+
# These are points that should be contained in the self loops. For example,
|
|
1469
|
+
# sl_points[0] will be (1, 1.1), which is inside the "path" of the first
|
|
1470
|
+
# self-loop but outside the others
|
|
1471
|
+
sl_points = np.array(edgelist[-3:]) + np.array([0, 0.1])
|
|
1472
|
+
|
|
1473
|
+
# Check that the mapping between self-loop locations and their colors is
|
|
1474
|
+
# correct
|
|
1475
|
+
for fap, clr, slp in zip(ax.patches, edge_colors[-3:], sl_points):
|
|
1476
|
+
assert fap.get_path().contains_point(slp)
|
|
1477
|
+
assert mpl.colors.same_color(fap.get_edgecolor(), clr)
|
|
1478
|
+
|
|
1479
|
+
|
|
1480
|
+
@pytest.mark.parametrize(
|
|
1481
|
+
"fap_only_kwarg", # Non-default values for kwargs that only apply to FAPs
|
|
1482
|
+
(
|
|
1483
|
+
{"arrowstyle": "-"},
|
|
1484
|
+
{"arrowsize": 20},
|
|
1485
|
+
{"connectionstyle": "arc3,rad=0.2"},
|
|
1486
|
+
{"min_source_margin": 10},
|
|
1487
|
+
{"min_target_margin": 10},
|
|
1488
|
+
),
|
|
1489
|
+
)
|
|
1490
|
+
def test_user_warnings_for_unused_edge_drawing_kwargs(fap_only_kwarg, subplots):
|
|
1491
|
+
"""Users should get a warning when they specify a non-default value for
|
|
1492
|
+
one of the kwargs that applies only to edges drawn with FancyArrowPatches,
|
|
1493
|
+
but FancyArrowPatches aren't being used under the hood."""
|
|
1494
|
+
G = nx.path_graph(3)
|
|
1495
|
+
pos = {n: (n, n) for n in G}
|
|
1496
|
+
fig, ax = subplots
|
|
1497
|
+
# By default, an undirected graph will use LineCollection to represent
|
|
1498
|
+
# the edges
|
|
1499
|
+
kwarg_name = list(fap_only_kwarg.keys())[0]
|
|
1500
|
+
with pytest.warns(
|
|
1501
|
+
UserWarning, match=f"\n\nThe {kwarg_name} keyword argument is not applicable"
|
|
1502
|
+
):
|
|
1503
|
+
nx.draw_networkx_edges(G, pos, ax=ax, **fap_only_kwarg)
|
|
1504
|
+
# FancyArrowPatches are always used when `arrows=True` is specified.
|
|
1505
|
+
# Check that warnings are *not* raised in this case
|
|
1506
|
+
with warnings.catch_warnings():
|
|
1507
|
+
# Escalate warnings -> errors so tests fail if warnings are raised
|
|
1508
|
+
warnings.simplefilter("error")
|
|
1509
|
+
warnings.filterwarnings("ignore", category=DeprecationWarning)
|
|
1510
|
+
nx.draw_networkx_edges(G, pos, ax=ax, arrows=True, **fap_only_kwarg)
|
|
1511
|
+
|
|
1512
|
+
|
|
1513
|
+
@pytest.mark.parametrize("draw_fn", (nx.draw, nx.draw_circular))
|
|
1514
|
+
def test_no_warning_on_default_draw_arrowstyle(draw_fn, subplots):
|
|
1515
|
+
# See gh-7284
|
|
1516
|
+
fig, ax = subplots
|
|
1517
|
+
G = nx.cycle_graph(5)
|
|
1518
|
+
with warnings.catch_warnings(record=True) as w:
|
|
1519
|
+
draw_fn(G, ax=ax)
|
|
1520
|
+
assert len(w) == 0
|
|
1521
|
+
|
|
1522
|
+
|
|
1523
|
+
@pytest.mark.parametrize("hide_ticks", [False, True])
|
|
1524
|
+
@pytest.mark.parametrize(
|
|
1525
|
+
"method",
|
|
1526
|
+
[
|
|
1527
|
+
nx.draw_networkx,
|
|
1528
|
+
nx.draw_networkx_edge_labels,
|
|
1529
|
+
nx.draw_networkx_edges,
|
|
1530
|
+
nx.draw_networkx_labels,
|
|
1531
|
+
nx.draw_networkx_nodes,
|
|
1532
|
+
],
|
|
1533
|
+
)
|
|
1534
|
+
def test_hide_ticks(method, hide_ticks, subplots):
|
|
1535
|
+
G = nx.path_graph(3)
|
|
1536
|
+
pos = {n: (n, n) for n in G.nodes}
|
|
1537
|
+
_, ax = subplots
|
|
1538
|
+
method(G, pos=pos, ax=ax, hide_ticks=hide_ticks)
|
|
1539
|
+
for axis in [ax.xaxis, ax.yaxis]:
|
|
1540
|
+
assert bool(axis.get_ticklabels()) != hide_ticks
|
|
1541
|
+
|
|
1542
|
+
|
|
1543
|
+
@pytest.mark.parametrize(
|
|
1544
|
+
"style", ["angle", "angle3", "arc", "arc3,rad=0.0", "bar,fraction=0.1"]
|
|
1545
|
+
)
|
|
1546
|
+
def test_edge_label_all_connectionstyles(subplots, style):
|
|
1547
|
+
"""
|
|
1548
|
+
Check that FancyArrowPatches with all `connectionstyle`s are supported
|
|
1549
|
+
in edge label rendering. See gh-7735 and gh-8106.
|
|
1550
|
+
"""
|
|
1551
|
+
fig, ax = subplots
|
|
1552
|
+
edge = (0, 1)
|
|
1553
|
+
G = nx.DiGraph([edge])
|
|
1554
|
+
pos = {n: (n, 0) for n in G}
|
|
1555
|
+
|
|
1556
|
+
name = style.split(",")[0]
|
|
1557
|
+
labels = nx.draw_networkx_edge_labels(
|
|
1558
|
+
G, pos, edge_labels={edge: "edge"}, connectionstyle=style
|
|
1559
|
+
)
|
|
1560
|
+
|
|
1561
|
+
hmid = (pos[0][0] + pos[1][0]) / 2
|
|
1562
|
+
vmid = (pos[0][1] + pos[1][1]) / 2
|
|
1563
|
+
if name in {"arc", "arc3"}: # The label should be at roughly the midpoint.
|
|
1564
|
+
assert labels[edge].x, labels[edge].y == pytest.approx((hmid, vmid))
|
|
1565
|
+
elif name == "bar": # The label should be below the vertical midpoint.
|
|
1566
|
+
assert labels[edge].y < vmid
|
|
1567
|
+
|
|
1568
|
+
|
|
1569
|
+
@pytest.mark.parametrize("label_pos", [-0.1, 1.1])
|
|
1570
|
+
def test_edge_label_label_pos(subplots, label_pos):
|
|
1571
|
+
"""
|
|
1572
|
+
Check that label positions can be extrapolated outside [0, 1].
|
|
1573
|
+
"""
|
|
1574
|
+
fig, ax = subplots
|
|
1575
|
+
edge = (0, 1)
|
|
1576
|
+
G = nx.DiGraph([edge])
|
|
1577
|
+
pos = {n: (n, n) for n in G}
|
|
1578
|
+
lbl = nx.draw_networkx_edge_labels(
|
|
1579
|
+
G, pos, edge_labels={edge: "edge"}, label_pos=label_pos, connectionstyle="angle"
|
|
1580
|
+
)
|
|
1581
|
+
|
|
1582
|
+
assert lbl[edge].x, lbl[edge].y == pytest.approx((label_pos, label_pos))
|