tensor-network-visualization 1.6.1__tar.gz → 1.6.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tensor_network_visualization-1.6.1/src/tensor_network_visualization.egg-info → tensor_network_visualization-1.6.3}/PKG-INFO +22 -5
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/README.md +21 -4
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/pyproject.toml +1 -1
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3/src/tensor_network_visualization.egg-info}/PKG-INFO +22 -5
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_visualization.egg-info/SOURCES.txt +10 -0
- tensor_network_visualization-1.6.3/src/tensor_network_viz/_auto_display.py +54 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/dangling_self_edges.py +3 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/edge_labels.py +1 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/fonts_and_scale.py +45 -2
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/graph_pipeline.py +3 -0
- tensor_network_visualization-1.6.3/src/tensor_network_viz/_core/draw/plotter.py +68 -0
- tensor_network_visualization-1.6.3/src/tensor_network_viz/_core/draw/plotter_2d.py +229 -0
- tensor_network_visualization-1.6.3/src/tensor_network_viz/_core/draw/plotter_3d.py +209 -0
- tensor_network_visualization-1.6.3/src/tensor_network_viz/_core/draw/plotter_common.py +85 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/render_prep.py +12 -5
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/scene_state.py +9 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/tensors.py +13 -3
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/viewport_geometry.py +16 -5
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/focus.py +71 -16
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/free_directions_2d.py +112 -11
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/free_directions_3d.py +45 -5
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/positions.py +112 -1
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout_structure.py +211 -217
- tensor_network_visualization-1.6.3/src/tensor_network_viz/_core/layout_structure_coordinates.py +208 -0
- tensor_network_visualization-1.6.3/src/tensor_network_viz/_core/layout_structure_sparse_grid.py +222 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/renderer.py +19 -7
- tensor_network_visualization-1.6.3/src/tensor_network_viz/_import_state.py +37 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_input_inspection.py +23 -18
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_interaction/controller.py +60 -5
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_interaction/controls.py +0 -2
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_interaction/tensor_inspector.py +61 -4
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_interaction/views.py +0 -3
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_interactive_scene.py +57 -32
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_registry.py +6 -5
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_tensor_comparison_support.py +2 -1
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_tensor_elements_controller.py +301 -29
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_tensor_elements_data.py +61 -695
- tensor_network_visualization-1.6.3/src/tensor_network_viz/_tensor_elements_inputs.py +586 -0
- tensor_network_visualization-1.6.3/src/tensor_network_viz/_tensor_elements_models.py +137 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_tensor_elements_payloads.py +59 -2
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_tensor_elements_rendering.py +4 -2
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_tensor_elements_support.py +5 -3
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/config.py +349 -347
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensor_comparison.py +1 -1
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensor_elements.py +48 -44
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/viewer.py +52 -32
- tensor_network_visualization-1.6.3/tests/test_bench_user_workflows.py +246 -0
- tensor_network_visualization-1.6.3/tests/test_ci_workflow.py +230 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_contraction_groups_once.py +0 -7
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_demo_cli_scheme.py +13 -4
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_einsum_backend.py +2 -2
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_engine_detection.py +48 -1
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_engineering_baseline.py +98 -70
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_examples.py +35 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_examples_structure.py +12 -12
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_graph_cache.py +54 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_interaction_controls.py +53 -1
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_label_draw_metrics_perf.py +1 -1
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_layout_core.py +517 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_plotting.py +424 -17
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_public_api.py +2 -2
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_quimb_backend.py +3 -2
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_render_performance_controls.py +128 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_tenpy_backend.py +8 -3
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_tensor_elements.py +404 -1
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_tensor_elements_perf.py +14 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_verify_script.py +8 -9
- tensor_network_visualization-1.6.1/src/tensor_network_viz/_core/draw/plotter.py +0 -478
- tensor_network_visualization-1.6.1/tests/test_ci_workflow.py +0 -176
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/LICENSE +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/setup.cfg +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_visualization.egg-info/dependency_links.txt +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_visualization.egg-info/requires.txt +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_visualization.egg-info/top_level.txt +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/__init__.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_contraction_viewer_style.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_contraction_viewer_ui.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/__init__.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/_draw_common.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/_label_format.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/_nodes_edges_common.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/axis_directions.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/contractions.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/curves.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/__init__.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/constants.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/contraction_edges.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/contraction_scheme.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/disk_metrics.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/edge_orchestration.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/edges.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/hover.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/label_descriptors.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/labels_misc.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/pick_distance.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/draw/vectors.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/graph.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/graph_cache.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/graph_utils.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/__init__.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/body.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/direction_common.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/force_directed.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/generic_coarsening.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/geometry.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/parameters.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_core/layout/types.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_engine_specs.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_interaction/__init__.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_interaction/bridge.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_interaction/scheme.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_interaction/state.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_logging.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_matplotlib_state.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_typing.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_ui_utils.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/_widgets.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/contraction_viewer.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/einsum_module/__init__.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/einsum_module/_backend.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/einsum_module/_equation.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/einsum_module/_trace_state.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/einsum_module/_trace_types.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/einsum_module/contraction_cost.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/einsum_module/graph.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/einsum_module/renderer.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/einsum_module/trace.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/exceptions.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/interactive_viewer.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/py.typed +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/quimb/__init__.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/quimb/graph.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/quimb/renderer.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/snapshot.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tenpy/__init__.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tenpy/explicit.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tenpy/graph.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tenpy/renderer.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensor_comparison_config.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensor_elements_config.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensorkrowch/__init__.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensorkrowch/_history.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensorkrowch/graph.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensorkrowch/renderer.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensornetwork/__init__.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensornetwork/graph.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/src/tensor_network_viz/tensornetwork/renderer.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_contraction_cost.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_contraction_scheme.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_contraction_scheme_api.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_contraction_viewer.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_draw_performance.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_edge_index_label_2d.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_edge_index_label_3d.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_einsum_autotrace.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_integration_einsum.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_integration_tensorkrowch.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_integration_tensornetwork.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_interaction_state.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_label_format.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_lazy_imports.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_logging_and_exceptions.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_matplotlib_state.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_node_degrees_perf.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_packaging_metadata.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_show_tensor_network_throughput.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_snapshot_api.py +0 -0
- {tensor_network_visualization-1.6.1 → tensor_network_visualization-1.6.3}/tests/test_tensor_comparison.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tensor-network-visualization
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.3
|
|
4
4
|
Summary: Minimal Matplotlib visualizations for TensorKrowch, TensorNetwork, Quimb, TeNPy, and traced PyTorch/NumPy einsum tensor networks.
|
|
5
5
|
Author: Alejandro Mata Ali
|
|
6
6
|
License-Expression: MIT
|
|
@@ -156,10 +156,27 @@ fig.savefig("tensorkrowch-network.png", bbox_inches="tight")
|
|
|
156
156
|
Use `show=False` when you want to save or customize the figure yourself. Use
|
|
157
157
|
`show_controls=False` when you want a clean static figure with no embedded Matplotlib controls.
|
|
158
158
|
|
|
159
|
-
In
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
[
|
|
159
|
+
In a notebook, use this exact recipe:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
%pip install "tensor-network-visualization[jupyter]"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
If you just installed that extra in the current kernel, restart the kernel once. Then, in the
|
|
166
|
+
first plotting cell:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
%matplotlib widget
|
|
170
|
+
|
|
171
|
+
from tensor_network_viz import PlotConfig, show_tensor_network
|
|
172
|
+
|
|
173
|
+
fig, ax = show_tensor_network(
|
|
174
|
+
network,
|
|
175
|
+
config=PlotConfig(show_tensor_labels=True, hover_labels=True),
|
|
176
|
+
)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
See [Installation](docs/installation.md) and [User Guide](docs/guide.md) for details.
|
|
163
180
|
|
|
164
181
|
## Documentation
|
|
165
182
|
|
|
@@ -105,10 +105,27 @@ fig.savefig("tensorkrowch-network.png", bbox_inches="tight")
|
|
|
105
105
|
Use `show=False` when you want to save or customize the figure yourself. Use
|
|
106
106
|
`show_controls=False` when you want a clean static figure with no embedded Matplotlib controls.
|
|
107
107
|
|
|
108
|
-
In
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
[
|
|
108
|
+
In a notebook, use this exact recipe:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
%pip install "tensor-network-visualization[jupyter]"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
If you just installed that extra in the current kernel, restart the kernel once. Then, in the
|
|
115
|
+
first plotting cell:
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
%matplotlib widget
|
|
119
|
+
|
|
120
|
+
from tensor_network_viz import PlotConfig, show_tensor_network
|
|
121
|
+
|
|
122
|
+
fig, ax = show_tensor_network(
|
|
123
|
+
network,
|
|
124
|
+
config=PlotConfig(show_tensor_labels=True, hover_labels=True),
|
|
125
|
+
)
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
See [Installation](docs/installation.md) and [User Guide](docs/guide.md) for details.
|
|
112
129
|
|
|
113
130
|
## Documentation
|
|
114
131
|
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "tensor-network-visualization"
|
|
7
|
-
version = "1.6.
|
|
7
|
+
version = "1.6.3"
|
|
8
8
|
description = "Minimal Matplotlib visualizations for TensorKrowch, TensorNetwork, Quimb, TeNPy, and traced PyTorch/NumPy einsum tensor networks."
|
|
9
9
|
authors = [{ name = "Alejandro Mata Ali" }]
|
|
10
10
|
readme = "README.md"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: tensor-network-visualization
|
|
3
|
-
Version: 1.6.
|
|
3
|
+
Version: 1.6.3
|
|
4
4
|
Summary: Minimal Matplotlib visualizations for TensorKrowch, TensorNetwork, Quimb, TeNPy, and traced PyTorch/NumPy einsum tensor networks.
|
|
5
5
|
Author: Alejandro Mata Ali
|
|
6
6
|
License-Expression: MIT
|
|
@@ -156,10 +156,27 @@ fig.savefig("tensorkrowch-network.png", bbox_inches="tight")
|
|
|
156
156
|
Use `show=False` when you want to save or customize the figure yourself. Use
|
|
157
157
|
`show_controls=False` when you want a clean static figure with no embedded Matplotlib controls.
|
|
158
158
|
|
|
159
|
-
In
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
[
|
|
159
|
+
In a notebook, use this exact recipe:
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
%pip install "tensor-network-visualization[jupyter]"
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
If you just installed that extra in the current kernel, restart the kernel once. Then, in the
|
|
166
|
+
first plotting cell:
|
|
167
|
+
|
|
168
|
+
```python
|
|
169
|
+
%matplotlib widget
|
|
170
|
+
|
|
171
|
+
from tensor_network_viz import PlotConfig, show_tensor_network
|
|
172
|
+
|
|
173
|
+
fig, ax = show_tensor_network(
|
|
174
|
+
network,
|
|
175
|
+
config=PlotConfig(show_tensor_labels=True, hover_labels=True),
|
|
176
|
+
)
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
See [Installation](docs/installation.md) and [User Guide](docs/guide.md) for details.
|
|
163
180
|
|
|
164
181
|
## Documentation
|
|
165
182
|
|
|
@@ -7,9 +7,11 @@ src/tensor_network_visualization.egg-info/dependency_links.txt
|
|
|
7
7
|
src/tensor_network_visualization.egg-info/requires.txt
|
|
8
8
|
src/tensor_network_visualization.egg-info/top_level.txt
|
|
9
9
|
src/tensor_network_viz/__init__.py
|
|
10
|
+
src/tensor_network_viz/_auto_display.py
|
|
10
11
|
src/tensor_network_viz/_contraction_viewer_style.py
|
|
11
12
|
src/tensor_network_viz/_contraction_viewer_ui.py
|
|
12
13
|
src/tensor_network_viz/_engine_specs.py
|
|
14
|
+
src/tensor_network_viz/_import_state.py
|
|
13
15
|
src/tensor_network_viz/_input_inspection.py
|
|
14
16
|
src/tensor_network_viz/_interactive_scene.py
|
|
15
17
|
src/tensor_network_viz/_logging.py
|
|
@@ -18,6 +20,8 @@ src/tensor_network_viz/_registry.py
|
|
|
18
20
|
src/tensor_network_viz/_tensor_comparison_support.py
|
|
19
21
|
src/tensor_network_viz/_tensor_elements_controller.py
|
|
20
22
|
src/tensor_network_viz/_tensor_elements_data.py
|
|
23
|
+
src/tensor_network_viz/_tensor_elements_inputs.py
|
|
24
|
+
src/tensor_network_viz/_tensor_elements_models.py
|
|
21
25
|
src/tensor_network_viz/_tensor_elements_payloads.py
|
|
22
26
|
src/tensor_network_viz/_tensor_elements_rendering.py
|
|
23
27
|
src/tensor_network_viz/_tensor_elements_support.py
|
|
@@ -47,6 +51,8 @@ src/tensor_network_viz/_core/graph.py
|
|
|
47
51
|
src/tensor_network_viz/_core/graph_cache.py
|
|
48
52
|
src/tensor_network_viz/_core/graph_utils.py
|
|
49
53
|
src/tensor_network_viz/_core/layout_structure.py
|
|
54
|
+
src/tensor_network_viz/_core/layout_structure_coordinates.py
|
|
55
|
+
src/tensor_network_viz/_core/layout_structure_sparse_grid.py
|
|
50
56
|
src/tensor_network_viz/_core/renderer.py
|
|
51
57
|
src/tensor_network_viz/_core/draw/__init__.py
|
|
52
58
|
src/tensor_network_viz/_core/draw/constants.py
|
|
@@ -64,6 +70,9 @@ src/tensor_network_viz/_core/draw/label_descriptors.py
|
|
|
64
70
|
src/tensor_network_viz/_core/draw/labels_misc.py
|
|
65
71
|
src/tensor_network_viz/_core/draw/pick_distance.py
|
|
66
72
|
src/tensor_network_viz/_core/draw/plotter.py
|
|
73
|
+
src/tensor_network_viz/_core/draw/plotter_2d.py
|
|
74
|
+
src/tensor_network_viz/_core/draw/plotter_3d.py
|
|
75
|
+
src/tensor_network_viz/_core/draw/plotter_common.py
|
|
67
76
|
src/tensor_network_viz/_core/draw/render_prep.py
|
|
68
77
|
src/tensor_network_viz/_core/draw/scene_state.py
|
|
69
78
|
src/tensor_network_viz/_core/draw/tensors.py
|
|
@@ -111,6 +120,7 @@ src/tensor_network_viz/tensorkrowch/renderer.py
|
|
|
111
120
|
src/tensor_network_viz/tensornetwork/__init__.py
|
|
112
121
|
src/tensor_network_viz/tensornetwork/graph.py
|
|
113
122
|
src/tensor_network_viz/tensornetwork/renderer.py
|
|
123
|
+
tests/test_bench_user_workflows.py
|
|
114
124
|
tests/test_ci_workflow.py
|
|
115
125
|
tests/test_contraction_cost.py
|
|
116
126
|
tests/test_contraction_groups_once.py
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""Shared helpers for auto-resolving display toggles."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from dataclasses import replace
|
|
6
|
+
|
|
7
|
+
from ._core.graph import _GraphData
|
|
8
|
+
from .config import PlotConfig
|
|
9
|
+
|
|
10
|
+
AUTO_VISIBLE_TENSOR_THRESHOLD: int = 25
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def count_visible_tensors(graph: _GraphData) -> int:
|
|
14
|
+
"""Count visible non-virtual tensors, falling back to total nodes when needed."""
|
|
15
|
+
visible_tensors = sum(1 for node in graph.nodes.values() if not node.is_virtual)
|
|
16
|
+
return visible_tensors or len(graph.nodes)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def resolve_auto_display_flag(
|
|
20
|
+
value: bool | None,
|
|
21
|
+
*,
|
|
22
|
+
visible_tensor_count: int,
|
|
23
|
+
) -> bool:
|
|
24
|
+
"""Resolve one optional display flag using the shared visibility heuristic."""
|
|
25
|
+
if value is not None:
|
|
26
|
+
return bool(value)
|
|
27
|
+
return int(visible_tensor_count) < AUTO_VISIBLE_TENSOR_THRESHOLD
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def resolve_auto_display_config(
|
|
31
|
+
config: PlotConfig,
|
|
32
|
+
*,
|
|
33
|
+
visible_tensor_count: int,
|
|
34
|
+
) -> PlotConfig:
|
|
35
|
+
"""Freeze auto display flags into concrete booleans for the current render."""
|
|
36
|
+
return replace(
|
|
37
|
+
config,
|
|
38
|
+
show_nodes=resolve_auto_display_flag(
|
|
39
|
+
config.show_nodes,
|
|
40
|
+
visible_tensor_count=visible_tensor_count,
|
|
41
|
+
),
|
|
42
|
+
show_tensor_labels=resolve_auto_display_flag(
|
|
43
|
+
config.show_tensor_labels,
|
|
44
|
+
visible_tensor_count=visible_tensor_count,
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
__all__ = [
|
|
50
|
+
"AUTO_VISIBLE_TENSOR_THRESHOLD",
|
|
51
|
+
"count_visible_tensors",
|
|
52
|
+
"resolve_auto_display_config",
|
|
53
|
+
"resolve_auto_display_flag",
|
|
54
|
+
]
|
|
@@ -169,6 +169,7 @@ def _draw_dangling_edge_labels(
|
|
|
169
169
|
dimensions=dimensions,
|
|
170
170
|
is_physical=True,
|
|
171
171
|
preferred_fontsize_pt=config.edge_label_fontsize,
|
|
172
|
+
fast_text_metrics=bool(p.fast_text_metrics),
|
|
172
173
|
)
|
|
173
174
|
text_kwargs = _edge_index_text_kwargs(
|
|
174
175
|
config,
|
|
@@ -392,6 +393,7 @@ def _draw_self_loop_edge_labels(
|
|
|
392
393
|
is_physical=False,
|
|
393
394
|
peer_captions_for_width=peer_width,
|
|
394
395
|
preferred_fontsize_pt=config.edge_label_fontsize,
|
|
396
|
+
fast_text_metrics=bool(p.fast_text_metrics),
|
|
395
397
|
)
|
|
396
398
|
text_kwargs_a = {
|
|
397
399
|
**_edge_index_text_kwargs(
|
|
@@ -446,6 +448,7 @@ def _draw_self_loop_edge_labels(
|
|
|
446
448
|
is_physical=False,
|
|
447
449
|
peer_captions_for_width=peer_width,
|
|
448
450
|
preferred_fontsize_pt=config.edge_label_fontsize,
|
|
451
|
+
fast_text_metrics=bool(p.fast_text_metrics),
|
|
449
452
|
)
|
|
450
453
|
text_kwargs_b = {
|
|
451
454
|
**_edge_index_text_kwargs(
|
|
@@ -28,6 +28,7 @@ def _figure_size_sqrt_ratio(fig: Figure) -> float:
|
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
_TEXTPATH_WIDTH_CACHE_MAX: int = 8192
|
|
31
|
+
_FAST_TEXT_METRICS_LABEL_THRESHOLD: int = 256
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
@functools.lru_cache(maxsize=_TEXTPATH_WIDTH_CACHE_MAX)
|
|
@@ -40,8 +41,38 @@ def _textpath_width_pts_cached(text: str, fontsize_pt_key: float) -> float:
|
|
|
40
41
|
return float(tp.get_extents().width)
|
|
41
42
|
|
|
42
43
|
|
|
43
|
-
|
|
44
|
+
@functools.lru_cache(maxsize=_TEXTPATH_WIDTH_CACHE_MAX)
|
|
45
|
+
def _textpath_width_pts_fast_cached(text: str, fontsize_pt_key: float) -> float:
|
|
46
|
+
"""Fast TextPath width approximation from raw vertices.
|
|
47
|
+
|
|
48
|
+
``TextPath.get_extents()`` walks Bezier extrema and becomes expensive for many unique labels.
|
|
49
|
+
The vertex span is slightly less exact, but avoids that path for dense interactive views.
|
|
50
|
+
"""
|
|
51
|
+
if not text.strip():
|
|
52
|
+
return 0.0
|
|
53
|
+
fp = FontProperties(size=float(fontsize_pt_key))
|
|
54
|
+
tp = TextPath((0.0, 0.0), text, prop=fp)
|
|
55
|
+
vertices = np.asarray(tp.vertices, dtype=float)
|
|
56
|
+
if vertices.size == 0:
|
|
57
|
+
return 0.0
|
|
58
|
+
return float(vertices[:, 0].max() - vertices[:, 0].min())
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def _textpath_width_pts_fast(text: str, *, fontsize_pt: float) -> float:
|
|
62
|
+
"""Fast horizontal span of *text* at *fontsize_pt* for dense label views."""
|
|
63
|
+
key = round(float(fontsize_pt), 6)
|
|
64
|
+
return float(_textpath_width_pts_fast_cached(text, key))
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _textpath_width_pts(
|
|
68
|
+
text: str,
|
|
69
|
+
*,
|
|
70
|
+
fontsize_pt: float,
|
|
71
|
+
fast_metrics: bool = False,
|
|
72
|
+
) -> float:
|
|
44
73
|
"""Horizontal advance of *text* from Matplotlib TextPath at *fontsize_pt* (points)."""
|
|
74
|
+
if fast_metrics:
|
|
75
|
+
return _textpath_width_pts_fast(text, fontsize_pt=fontsize_pt)
|
|
45
76
|
key = round(float(fontsize_pt), 6)
|
|
46
77
|
return float(_textpath_width_pts_cached(text, key))
|
|
47
78
|
|
|
@@ -86,6 +117,7 @@ class _DrawScaleParams:
|
|
|
86
117
|
label_offset: float
|
|
87
118
|
ellipse_w: float
|
|
88
119
|
ellipse_h: float
|
|
120
|
+
fast_text_metrics: bool = False
|
|
89
121
|
|
|
90
122
|
|
|
91
123
|
def _draw_scale_params(
|
|
@@ -96,11 +128,18 @@ def _draw_scale_params(
|
|
|
96
128
|
is_3d: bool,
|
|
97
129
|
font_figure_scale: float = 1.0,
|
|
98
130
|
label_slots: int = 1,
|
|
131
|
+
fast_text_metrics: bool | None = None,
|
|
99
132
|
) -> _DrawScaleParams:
|
|
100
133
|
"""Compute scale-dependent drawing parameters from config."""
|
|
101
134
|
fs = font_figure_scale
|
|
102
135
|
tensor_fs = _figure_base_size_scale(fig)
|
|
103
|
-
|
|
136
|
+
resolved_label_slots = max(1, int(label_slots))
|
|
137
|
+
bbox_pad = _index_label_bbox_pad(resolved_label_slots)
|
|
138
|
+
use_fast_text_metrics = (
|
|
139
|
+
resolved_label_slots >= _FAST_TEXT_METRICS_LABEL_THRESHOLD
|
|
140
|
+
if fast_text_metrics is None
|
|
141
|
+
else bool(fast_text_metrics)
|
|
142
|
+
)
|
|
104
143
|
r = (
|
|
105
144
|
config.node_radius if config.node_radius is not None else PlotConfig.DEFAULT_NODE_RADIUS
|
|
106
145
|
) * scale
|
|
@@ -128,6 +167,7 @@ def _draw_scale_params(
|
|
|
128
167
|
label_offset=0.08 * scale * float(np.clip(0.82 + 0.22 * fs, 0.75, 1.2)),
|
|
129
168
|
ellipse_w=0.16 * scale,
|
|
130
169
|
ellipse_h=0.12 * scale,
|
|
170
|
+
fast_text_metrics=use_fast_text_metrics,
|
|
131
171
|
)
|
|
132
172
|
|
|
133
173
|
|
|
@@ -176,9 +216,12 @@ __all__ = [
|
|
|
176
216
|
"_figure_base_size_scale",
|
|
177
217
|
"_figure_relative_font_scale",
|
|
178
218
|
"_figure_size_sqrt_ratio",
|
|
219
|
+
"_FAST_TEXT_METRICS_LABEL_THRESHOLD",
|
|
179
220
|
"_index_label_bbox_pad",
|
|
180
221
|
"_on_2d_limits_changed",
|
|
181
222
|
"_register_2d_zoom_font_scaling",
|
|
182
223
|
"_textpath_width_pts",
|
|
183
224
|
"_textpath_width_pts_cached",
|
|
225
|
+
"_textpath_width_pts_fast",
|
|
226
|
+
"_textpath_width_pts_fast_cached",
|
|
184
227
|
]
|
|
@@ -16,6 +16,7 @@ from .render_prep import (
|
|
|
16
16
|
|
|
17
17
|
if TYPE_CHECKING:
|
|
18
18
|
from ..._interaction.scheme import _ContractionSchemeBundle
|
|
19
|
+
from .scene_state import _FocusSceneFeedback
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def _refresh_contraction_hover(
|
|
@@ -159,6 +160,7 @@ def _draw_graph(
|
|
|
159
160
|
contraction_controls_build_ui: bool = True,
|
|
160
161
|
register_contraction_controls_on_figure: bool = True,
|
|
161
162
|
build_scene_state: bool = True,
|
|
163
|
+
focus_feedback: _FocusSceneFeedback | None = None,
|
|
162
164
|
) -> None:
|
|
163
165
|
context = _prepare_render_context(
|
|
164
166
|
ax=ax,
|
|
@@ -244,6 +246,7 @@ def _draw_graph(
|
|
|
244
246
|
scale=scale,
|
|
245
247
|
hover_state=hover_state,
|
|
246
248
|
tensor_disk_radius_px_3d=tensor_disk_radius_px_3d,
|
|
249
|
+
focus_feedback=focus_feedback,
|
|
247
250
|
)
|
|
248
251
|
scene.contraction_controls = controls
|
|
249
252
|
set_scene(ax, scene)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Literal, Protocol, cast
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
|
|
7
|
+
from ...config import PlotConfig
|
|
8
|
+
from .fonts_and_scale import _DrawScaleParams
|
|
9
|
+
from .plotter_2d import _make_2d_plotter
|
|
10
|
+
from .plotter_3d import _make_3d_plotter
|
|
11
|
+
from .plotter_common import (
|
|
12
|
+
NodeRenderMode,
|
|
13
|
+
_edge_outline_effects,
|
|
14
|
+
_graph_edge_degree,
|
|
15
|
+
_node_edge_degrees,
|
|
16
|
+
_NodeArtistBundle,
|
|
17
|
+
_visible_degree_one_mask,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class _PlotAdapter(Protocol):
|
|
22
|
+
"""Protocol for dimension-aware plotting (2D vs 3D)."""
|
|
23
|
+
|
|
24
|
+
def plot_line(self, start: np.ndarray, end: np.ndarray, **kwargs: Any) -> None: ...
|
|
25
|
+
def plot_curve(self, curve: np.ndarray, **kwargs: Any) -> None: ...
|
|
26
|
+
def plot_text(self, pos: np.ndarray, text: str, **kwargs: Any) -> None: ...
|
|
27
|
+
def draw_tensor_nodes(
|
|
28
|
+
self,
|
|
29
|
+
coords: np.ndarray,
|
|
30
|
+
*,
|
|
31
|
+
config: PlotConfig,
|
|
32
|
+
p: _DrawScaleParams,
|
|
33
|
+
degree_one_mask: np.ndarray,
|
|
34
|
+
mode: NodeRenderMode,
|
|
35
|
+
) -> None: ...
|
|
36
|
+
def draw_virtual_hub_markers(
|
|
37
|
+
self,
|
|
38
|
+
coords: np.ndarray,
|
|
39
|
+
*,
|
|
40
|
+
config: PlotConfig,
|
|
41
|
+
zorder: float,
|
|
42
|
+
) -> None: ...
|
|
43
|
+
def get_node_artist_bundle(self) -> _NodeArtistBundle | None: ...
|
|
44
|
+
def get_edge_artists(self) -> tuple[Any, ...]: ...
|
|
45
|
+
def style_axes(self, coords: np.ndarray, *, view_margin: float) -> None: ...
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def _make_plotter(
|
|
49
|
+
ax: Any,
|
|
50
|
+
*,
|
|
51
|
+
dimensions: Literal[2, 3],
|
|
52
|
+
hover_edge_targets: list[tuple[np.ndarray, str]] | None = None,
|
|
53
|
+
) -> _PlotAdapter:
|
|
54
|
+
"""Create a dimension-aware plot adapter."""
|
|
55
|
+
if dimensions == 2:
|
|
56
|
+
return cast(_PlotAdapter, _make_2d_plotter(ax, hover_edge_targets=hover_edge_targets))
|
|
57
|
+
return cast(_PlotAdapter, _make_3d_plotter(ax, hover_edge_targets=hover_edge_targets))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
__all__ = [
|
|
61
|
+
"_PlotAdapter",
|
|
62
|
+
"_NodeArtistBundle",
|
|
63
|
+
"_edge_outline_effects",
|
|
64
|
+
"_graph_edge_degree",
|
|
65
|
+
"_make_plotter",
|
|
66
|
+
"_node_edge_degrees",
|
|
67
|
+
"_visible_degree_one_mask",
|
|
68
|
+
]
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections import defaultdict
|
|
4
|
+
from typing import Any
|
|
5
|
+
|
|
6
|
+
import numpy as np
|
|
7
|
+
from matplotlib.artist import Artist
|
|
8
|
+
from matplotlib.axes import Axes
|
|
9
|
+
from matplotlib.collections import LineCollection, PatchCollection, PathCollection
|
|
10
|
+
from matplotlib.patches import Circle
|
|
11
|
+
|
|
12
|
+
from ...config import PlotConfig
|
|
13
|
+
from .constants import _EDGE_LINE_CAP_STYLE, _EDGE_LINE_JOIN_STYLE, _ZORDER_NODE_DISK
|
|
14
|
+
from .fonts_and_scale import _DrawScaleParams
|
|
15
|
+
from .plotter_common import (
|
|
16
|
+
_COMPACT_NODE_MARKER_AREA_2D_PT2,
|
|
17
|
+
_COMPACT_NODE_MARKER_LINEWIDTH_PT,
|
|
18
|
+
_VIRTUAL_HUB_MARKER_AREA_2D_PT2,
|
|
19
|
+
_VIRTUAL_HUB_MARKER_LINEWIDTH_PT,
|
|
20
|
+
NodeRenderMode,
|
|
21
|
+
_edge_outline_effects,
|
|
22
|
+
_NodeArtistBundle,
|
|
23
|
+
)
|
|
24
|
+
from .viewport_geometry import (
|
|
25
|
+
_apply_axis_limits_with_outset,
|
|
26
|
+
_apply_edge_line_style,
|
|
27
|
+
_apply_text_no_clip,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _make_2d_plotter(
|
|
32
|
+
ax: Axes,
|
|
33
|
+
*,
|
|
34
|
+
hover_edge_targets: list[tuple[np.ndarray, str]] | None = None,
|
|
35
|
+
) -> object:
|
|
36
|
+
class _2DPlotter:
|
|
37
|
+
__slots__ = (
|
|
38
|
+
"_ax",
|
|
39
|
+
"_edge_segments",
|
|
40
|
+
"_hover_edge_targets",
|
|
41
|
+
"_edge_artists",
|
|
42
|
+
"_node_disk_collection",
|
|
43
|
+
"_node_disk_collections",
|
|
44
|
+
"_node_artist_bundle",
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
def __init__(
|
|
48
|
+
self,
|
|
49
|
+
ax_2d: Axes,
|
|
50
|
+
hover_edges: list[tuple[np.ndarray, str]] | None,
|
|
51
|
+
) -> None:
|
|
52
|
+
self._ax = ax_2d
|
|
53
|
+
self._edge_segments: list[tuple[float, str, float, np.ndarray]] = []
|
|
54
|
+
self._hover_edge_targets = hover_edges
|
|
55
|
+
self._edge_artists: list[Artist] = []
|
|
56
|
+
self._node_disk_collection: PatchCollection | PathCollection | None = None
|
|
57
|
+
self._node_disk_collections: list[PatchCollection | PathCollection] = []
|
|
58
|
+
self._node_artist_bundle: _NodeArtistBundle | None = None
|
|
59
|
+
|
|
60
|
+
def clear_node_disk_collections(self) -> None:
|
|
61
|
+
self._node_disk_collections.clear()
|
|
62
|
+
self._node_disk_collection = None
|
|
63
|
+
self._node_artist_bundle = None
|
|
64
|
+
|
|
65
|
+
def get_node_artist_bundle(self) -> _NodeArtistBundle | None:
|
|
66
|
+
return self._node_artist_bundle
|
|
67
|
+
|
|
68
|
+
def get_edge_artists(self) -> tuple[Artist, ...]:
|
|
69
|
+
return tuple(self._edge_artists)
|
|
70
|
+
|
|
71
|
+
def flush_edge_collections(self) -> None:
|
|
72
|
+
"""Batch buffered edges into a few LineCollections (call after all edges drawn)."""
|
|
73
|
+
if not self._edge_segments:
|
|
74
|
+
return
|
|
75
|
+
groups: dict[tuple[float, str, float], list[np.ndarray]] = defaultdict(list)
|
|
76
|
+
for z, color, lw, seg in self._edge_segments:
|
|
77
|
+
groups[(z, color, lw)].append(seg)
|
|
78
|
+
ax_ = self._ax
|
|
79
|
+
for (z, color, lw), segs in sorted(groups.items(), key=lambda kv: kv[0][0]):
|
|
80
|
+
coll = LineCollection(
|
|
81
|
+
segs,
|
|
82
|
+
colors=color,
|
|
83
|
+
linewidths=lw,
|
|
84
|
+
zorder=z,
|
|
85
|
+
capstyle=_EDGE_LINE_CAP_STYLE,
|
|
86
|
+
joinstyle=_EDGE_LINE_JOIN_STYLE,
|
|
87
|
+
)
|
|
88
|
+
coll.set_path_effects(_edge_outline_effects(float(lw)))
|
|
89
|
+
ax_.add_collection(coll, autolim=False)
|
|
90
|
+
self._edge_artists.append(coll)
|
|
91
|
+
self._edge_segments.clear()
|
|
92
|
+
|
|
93
|
+
def plot_line(self, start: np.ndarray, end: np.ndarray, **kwargs: Any) -> None:
|
|
94
|
+
_apply_edge_line_style(kwargs)
|
|
95
|
+
z = float(kwargs.get("zorder", 1))
|
|
96
|
+
color = str(kwargs.get("color", "#000000"))
|
|
97
|
+
lw = float(kwargs.get("linewidth", 1.0))
|
|
98
|
+
seg = np.array(
|
|
99
|
+
[[float(start[0]), float(start[1])], [float(end[0]), float(end[1])]],
|
|
100
|
+
dtype=float,
|
|
101
|
+
)
|
|
102
|
+
self._edge_segments.append((z, color, lw, seg))
|
|
103
|
+
|
|
104
|
+
def plot_curve(self, curve: np.ndarray, **kwargs: Any) -> None:
|
|
105
|
+
_apply_edge_line_style(kwargs)
|
|
106
|
+
z = float(kwargs.get("zorder", 1))
|
|
107
|
+
color = str(kwargs.get("color", "#000000"))
|
|
108
|
+
lw = float(kwargs.get("linewidth", 1.0))
|
|
109
|
+
seg = np.asarray(curve[:, :2], dtype=float, order="C")
|
|
110
|
+
self._edge_segments.append((z, color, lw, seg))
|
|
111
|
+
|
|
112
|
+
def plot_text(self, pos: np.ndarray, text: str, **kwargs: Any) -> None:
|
|
113
|
+
_apply_text_no_clip(kwargs)
|
|
114
|
+
self._ax.text(pos[0], pos[1], text, **kwargs)
|
|
115
|
+
|
|
116
|
+
def draw_tensor_node(
|
|
117
|
+
self,
|
|
118
|
+
coord: np.ndarray,
|
|
119
|
+
*,
|
|
120
|
+
config: PlotConfig,
|
|
121
|
+
p: _DrawScaleParams,
|
|
122
|
+
degree_one: bool,
|
|
123
|
+
mode: NodeRenderMode,
|
|
124
|
+
zorder: float,
|
|
125
|
+
) -> None:
|
|
126
|
+
fc = config.node_color_degree_one if degree_one else config.node_color
|
|
127
|
+
ec = config.node_edge_color_degree_one if degree_one else config.node_edge_color
|
|
128
|
+
if mode == "compact":
|
|
129
|
+
coll = self._ax.scatter(
|
|
130
|
+
[float(coord[0])],
|
|
131
|
+
[float(coord[1])],
|
|
132
|
+
s=_COMPACT_NODE_MARKER_AREA_2D_PT2,
|
|
133
|
+
c=[fc],
|
|
134
|
+
edgecolors=[ec],
|
|
135
|
+
linewidths=_COMPACT_NODE_MARKER_LINEWIDTH_PT,
|
|
136
|
+
zorder=zorder,
|
|
137
|
+
)
|
|
138
|
+
else:
|
|
139
|
+
patch = Circle((float(coord[0]), float(coord[1])), radius=p.r)
|
|
140
|
+
coll = PatchCollection(
|
|
141
|
+
[patch],
|
|
142
|
+
facecolors=[fc],
|
|
143
|
+
edgecolors=[ec],
|
|
144
|
+
linewidths=float(p.lw),
|
|
145
|
+
zorder=zorder,
|
|
146
|
+
match_original=False,
|
|
147
|
+
)
|
|
148
|
+
self._ax.add_collection(coll, autolim=False)
|
|
149
|
+
self._node_disk_collections.append(coll)
|
|
150
|
+
self._node_artist_bundle = _NodeArtistBundle(
|
|
151
|
+
mode=mode,
|
|
152
|
+
artists=tuple(self._node_disk_collections),
|
|
153
|
+
hover_target=tuple(self._node_disk_collections),
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
def draw_tensor_nodes(
|
|
157
|
+
self,
|
|
158
|
+
coords: np.ndarray,
|
|
159
|
+
*,
|
|
160
|
+
config: PlotConfig,
|
|
161
|
+
p: _DrawScaleParams,
|
|
162
|
+
degree_one_mask: np.ndarray,
|
|
163
|
+
mode: NodeRenderMode,
|
|
164
|
+
) -> None:
|
|
165
|
+
n = int(coords.shape[0])
|
|
166
|
+
if n == 0:
|
|
167
|
+
return
|
|
168
|
+
faces = [
|
|
169
|
+
config.node_color_degree_one if degree_one_mask[i] else config.node_color
|
|
170
|
+
for i in range(n)
|
|
171
|
+
]
|
|
172
|
+
c1 = config.node_edge_color_degree_one
|
|
173
|
+
c0 = config.node_edge_color
|
|
174
|
+
edges_ = [c1 if degree_one_mask[i] else c0 for i in range(n)]
|
|
175
|
+
if mode == "compact":
|
|
176
|
+
coll = self._ax.scatter(
|
|
177
|
+
coords[:, 0],
|
|
178
|
+
coords[:, 1],
|
|
179
|
+
s=_COMPACT_NODE_MARKER_AREA_2D_PT2,
|
|
180
|
+
c=faces,
|
|
181
|
+
edgecolors=edges_,
|
|
182
|
+
linewidths=_COMPACT_NODE_MARKER_LINEWIDTH_PT,
|
|
183
|
+
zorder=_ZORDER_NODE_DISK,
|
|
184
|
+
)
|
|
185
|
+
else:
|
|
186
|
+
patches = [
|
|
187
|
+
Circle((float(coords[i, 0]), float(coords[i, 1])), radius=p.r) for i in range(n)
|
|
188
|
+
]
|
|
189
|
+
coll = PatchCollection(
|
|
190
|
+
patches,
|
|
191
|
+
facecolors=faces,
|
|
192
|
+
edgecolors=edges_,
|
|
193
|
+
linewidths=float(p.lw),
|
|
194
|
+
zorder=_ZORDER_NODE_DISK,
|
|
195
|
+
match_original=False,
|
|
196
|
+
)
|
|
197
|
+
self._ax.add_collection(coll, autolim=False)
|
|
198
|
+
self._node_disk_collection = coll
|
|
199
|
+
self._node_disk_collections = [coll]
|
|
200
|
+
self._node_artist_bundle = _NodeArtistBundle(
|
|
201
|
+
mode=mode,
|
|
202
|
+
artists=(coll,),
|
|
203
|
+
hover_target=coll,
|
|
204
|
+
)
|
|
205
|
+
|
|
206
|
+
def draw_virtual_hub_markers(
|
|
207
|
+
self,
|
|
208
|
+
coords: np.ndarray,
|
|
209
|
+
*,
|
|
210
|
+
config: PlotConfig,
|
|
211
|
+
zorder: float,
|
|
212
|
+
) -> None:
|
|
213
|
+
if int(coords.shape[0]) == 0:
|
|
214
|
+
return
|
|
215
|
+
self._ax.scatter(
|
|
216
|
+
coords[:, 0],
|
|
217
|
+
coords[:, 1],
|
|
218
|
+
marker="^",
|
|
219
|
+
s=_VIRTUAL_HUB_MARKER_AREA_2D_PT2,
|
|
220
|
+
c=[config.dangling_edge_color],
|
|
221
|
+
edgecolors=[config.node_edge_color_degree_one],
|
|
222
|
+
linewidths=_VIRTUAL_HUB_MARKER_LINEWIDTH_PT,
|
|
223
|
+
zorder=zorder,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
def style_axes(self, coords: np.ndarray, *, view_margin: float) -> None:
|
|
227
|
+
_apply_axis_limits_with_outset(self._ax, coords, view_margin=view_margin, dimensions=2)
|
|
228
|
+
|
|
229
|
+
return _2DPlotter(ax, hover_edge_targets)
|