anyplotlib 0.6.0__tar.gz → 0.7.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/CHANGELOG.rst +40 -0
- anyplotlib-0.7.1/Examples/PlotTypes/plot_key_overlays.py +169 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/PKG-INFO +1 -1
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/FIGURE_ESM.md +28 -27
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/__init__.py +2 -1
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/_base_plot.py +166 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/figure/_figure.py +27 -3
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/figure_esm.js +237 -1
- anyplotlib-0.7.1/anyplotlib/keys.py +249 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plot2d/_plot2d.py +1 -1
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plot3d/_plot3d.py +1 -1
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plotxy/_plotxy.py +1 -1
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/conftest.py +71 -0
- anyplotlib-0.7.1/anyplotlib/tests/test_embed/test_export_pixel_tokens.py +174 -0
- anyplotlib-0.7.1/anyplotlib/tests/test_keys/test_keys.py +413 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/_root/index.html +3 -3
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/_root/switcher.json +10 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/api/index.rst +1 -0
- anyplotlib-0.7.1/docs/api/keys.rst +42 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/conf.py +1 -1
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/pyproject.toml +1 -1
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/.github/workflows/ci.yml +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/.github/workflows/docs.yml +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/.github/workflows/prepare_release.yml +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/.github/workflows/release.yml +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/.github/workflows/tests.yml +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/.gitignore +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/AGENTS.md +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Benchmarks/README.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Benchmarks/plot_benchmark_comparison.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/README.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_3d_spectral_viewer.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_eels_explorer.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_figure_annotations.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_interactive_fft.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_interactive_fitting.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_ipf_density_map.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_ipf_explorer.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_key_bindings.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_particle_picker.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_point_widget.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_segment_by_contrast.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_segment_by_contrast_advanced.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_spectra_roi_inspector.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_star_globe_explorer.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_threshold_explorer.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Interactive/plot_voxel_grain_explorer.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/README.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_arrows.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_circles.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_ellipses.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_horizontal_lines.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_line_segments.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_points.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_polygons.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_rectangles.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_squares.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_texts.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_transform_markers.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Markers/plot_vertical_lines.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/README.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_3d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_3d_texture.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_bar.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_gpu_voxels.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_gridspec_custom.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_image2d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_inset.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_label_formatting.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_line_styles.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_pcolormesh.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_spectra1d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_step_and_log.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_tile_backend.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/PlotTypes/plot_twinx.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/README.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/README.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget1d_hline.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget1d_point.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget1d_range.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget1d_vline.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget2d_annular.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget2d_arrow.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget2d_circle.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget2d_crosshair.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget2d_label.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget2d_polygon.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget2d_rectangle.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Examples/Widgets/plot_widget3d_plane.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/LICENSE +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/Makefile +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/README.md +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/_binary_frame.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/_electron.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/_repr_utils.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/_utils.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/axes/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/axes/_axes.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/axes/_inset_axes.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/callbacks.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/conftest.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/embed.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/figure/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/figure/_gridspec.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/figure/_subplots.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/markers.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plot1d/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plot1d/_plot1d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plot1d/_plotbar.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plot2d/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plot2d/_layer.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plot2d/_plotmesh.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plot2d/_tile_backend.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plot3d/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/plotxy/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/_directive.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/_repr_utils.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/_scraper.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/_wheel_builder.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/static/anywidget_bridge.js +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/static/anywidget_overlay.css +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/tests/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/tests/conftest.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/tests/test_directive.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/tests/test_init.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/tests/test_repr_utils.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/tests/test_scraper.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/sphinx_anywidget/tests/test_wheel_builder.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/_gpu_clim_check.cjs +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/_png_utils.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/bar_basic.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/gridspec_3col_equal_spectra.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/gridspec_asymmetric_width_ratios.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/gridspec_height_ratio_image_histogram.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/gridspec_image_two_spectra.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/gridspec_side_by_side_1d.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/gridspec_spanning_top_two_bottom.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/imshow_axis_off.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/imshow_checkerboard.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/imshow_gradient.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/imshow_labels.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/imshow_viridis.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/inset_1d.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/inset_maximized.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/inset_minimized.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/inset_normal_2d.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/inset_stacked.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/inset_stacked_one_minimized.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/pcolormesh_uniform.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot1d_all_linestyles.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot1d_alpha.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot1d_axis_off.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot1d_dashed.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot1d_marker_symbols.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot1d_markers.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot1d_multi.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot1d_sine.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot1d_title.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot1d_twinx.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/plot3d_surface.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/baselines/subplots_2x1.png +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_benchmarks/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_benchmarks/baselines.json +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_benchmarks/benchmarks/baselines.json +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_benchmarks/test_benchmarks.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_benchmarks/test_benchmarks_py.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_documentation/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_documentation/test_bridge.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_documentation/test_push_hook.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_documentation/test_scraper.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_electron/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_electron/test_binary_frame.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_embed/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_embed/test_embed_api.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_embed/test_embed_mount.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_embed/test_export_png.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_embed/test_export_widget_sync.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_examples/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_examples/test_interactive_examples.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/_event_test_utils.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_blit_audit.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_callbacks_playwright.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_callbacks_unit.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_edit_chrome.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_edit_chrome_playwright.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_event_pause_hold.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_event_plots.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_event_settled.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_events_regression.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_orbit_direction.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_pointer_down_1d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_range_orientation_snap.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_star_globe_linking.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_tile_parity_playwright.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_title.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_touch.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_widget_brush.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_widget_max_extent.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_widget_set_notify.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_widgets.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_interactive/test_widgets_line_2d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_labels/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_labels/test_label_api.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_labels/test_label_rendering.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_labels/test_no_clipping.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_labels/test_ylabel_clearance.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_layouts/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_layouts/test_batch.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_layouts/test_coord_conversion.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_layouts/test_geom_channel.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_layouts/test_gridspec.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_layouts/test_inset.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_layouts/test_inset_callout.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_layouts/test_interaction.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_layouts/test_visual.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_markers/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_markers/test_marker_transforms.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_markers/test_markers.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_markers/test_per_marker_colors.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_markers/test_size_units.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot1d/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot1d/test_line_none_rendering.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot1d/test_plot1d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot1d/test_plotbar.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_colorbar_gap_scalebar.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_detail_tile.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_first_paint_race.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_gpu_image.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_gpu_parity_playwright.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_imshow.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_imshow_rgb.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_layers.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_layers_playwright.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_pcolormesh.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_plot2d_api.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_rapid_frame_update.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_tile_backend.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_tile_diagnostics.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_tiled_imshow.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot2d/test_zoom_view_write.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot3d/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot3d/test_colors_highlight.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot3d/test_gpu_depth.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot3d/test_gpu_fallback.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot3d/test_gpu_hidden_reveal.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot3d/test_plot3d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot3d/test_texture.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plot3d/test_voxels_planes.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/tests/test_plotxy/test_plotxy.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/widgets/__init__.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/widgets/_base.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/widgets/_widgets1d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/widgets/_widgets2d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/anyplotlib/widgets/_widgets3d.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/_sg_html_scraper.py +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/_static/anyplotlib.svg +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/_static/custom.css +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/_static/pyodide_bridge.js +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/_templates/autosummary/class.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/api/callbacks.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/api/figure.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/api/figure_plots.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/api/markers.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/api/widgets.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/benchmarking.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/dev/index.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/embedding.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/events.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/getting_started.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/docs/index.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/make.bat +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/upcoming_changes/.gitkeep +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/upcoming_changes/README.rst +0 -0
- {anyplotlib-0.6.0 → anyplotlib-0.7.1}/uv.lock +0 -0
|
@@ -10,6 +10,46 @@ Fragment files in ``upcoming_changes/`` are assembled into this file by
|
|
|
10
10
|
|
|
11
11
|
.. towncrier release notes start
|
|
12
12
|
|
|
13
|
+
0.7.1 (2026-08-02)
|
|
14
|
+
==================
|
|
15
|
+
|
|
16
|
+
Bug Fixes
|
|
17
|
+
---------
|
|
18
|
+
|
|
19
|
+
- Fixed ``save_html`` / ``to_html`` / ``figure_state`` dropping image pixels
|
|
20
|
+
under the Electron binary transport: the snapshot kept the ``"\x00bin:"``
|
|
21
|
+
change-tokens whose bytes only ever ride the live PLOTBIN channel, so an
|
|
22
|
+
overlay added with :meth:`~anyplotlib.Plot2D.add_layer` did not render in the
|
|
23
|
+
exported document. (`#52 <https://github.com/CSSFrancis/anyplotlib/pull/52>`_)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
Documentation
|
|
27
|
+
-------------
|
|
28
|
+
|
|
29
|
+
- Fixed the documentation build failing on
|
|
30
|
+
:class:`~anyplotlib.keys.KeyOverlay`, whose ``id`` and ``name`` were described
|
|
31
|
+
both in the class docstring and by the properties themselves — a duplicate
|
|
32
|
+
object description, which the build treats as an error. (`#53 <https://github.com/CSSFrancis/anyplotlib/pull/53>`_)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
0.7.0 (2026-07-31)
|
|
36
|
+
==================
|
|
37
|
+
|
|
38
|
+
New Features
|
|
39
|
+
------------
|
|
40
|
+
|
|
41
|
+
- Added :meth:`~anyplotlib.Plot2D.add_key` for pinning a floating image *key* over
|
|
42
|
+
a panel — an inverse pole figure triangle over an orientation map, a hue wheel
|
|
43
|
+
over a polarization field, a phase key over a segmentation. A key is the scale
|
|
44
|
+
bar's sibling: it floats in screen space and neither pans nor zooms with the
|
|
45
|
+
data, it takes an RGBA image so a triangle or a disc needs no rectangular card
|
|
46
|
+
around it, and ``labels=`` annotates the picture itself (an IPF triangle's
|
|
47
|
+
corner indices) in fractions of the key image. Optional ``bgcolor`` /
|
|
48
|
+
``border`` / ``alpha`` give it a card when the data underneath is busy, and
|
|
49
|
+
``hover_only=True`` reveals it only while the pointer is over the panel.
|
|
50
|
+
Available on every panel type, and included in PNG export.
|
|
51
|
+
|
|
52
|
+
|
|
13
53
|
0.6.0 (2026-07-31)
|
|
14
54
|
==================
|
|
15
55
|
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Floating keys — IPF triangles and colour wheels
|
|
3
|
+
===============================================
|
|
4
|
+
|
|
5
|
+
Some plots are coloured by a *direction*, not by a magnitude, and a colorbar
|
|
6
|
+
cannot say what the colours mean. An orientation map is coloured by which
|
|
7
|
+
crystal axis points at you; a polarization map by which way the moment lies in
|
|
8
|
+
the plane. Both need a small picture as their legend: an inverse pole figure
|
|
9
|
+
triangle, or a hue wheel.
|
|
10
|
+
|
|
11
|
+
:meth:`~anyplotlib.Plot2D.add_key` pins that picture over the panel in *screen*
|
|
12
|
+
space — it does not pan or zoom with the data, exactly like the scale bar it is
|
|
13
|
+
modelled on.
|
|
14
|
+
|
|
15
|
+
This is deliberately not :meth:`~anyplotlib.Figure.add_inset`, which is a
|
|
16
|
+
draggable window with a title bar and its own canvas stack. That is the right
|
|
17
|
+
tool when the overlay is a live plot; a key is a static picture that should
|
|
18
|
+
read as part of the figure.
|
|
19
|
+
"""
|
|
20
|
+
import numpy as np
|
|
21
|
+
|
|
22
|
+
import anyplotlib as apl
|
|
23
|
+
|
|
24
|
+
# %%
|
|
25
|
+
# The IPF colour key
|
|
26
|
+
# ------------------
|
|
27
|
+
# The standard cubic stereographic triangle. Each pixel's colour is its
|
|
28
|
+
# barycentric distance to the three corners, which is the classic IPF key: a
|
|
29
|
+
# grain pointing [1 0 0] at the detector reads red, [1 1 0] green, [1 1 1] blue.
|
|
30
|
+
#
|
|
31
|
+
# The triangle is built as an ``(H, W, 4)`` RGBA array, and **alpha 0 outside
|
|
32
|
+
# the triangle** is what lets it sit on the map without a rectangular card
|
|
33
|
+
# around it.
|
|
34
|
+
|
|
35
|
+
KEY_N = 220
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def ipf_triangle(n=KEY_N):
|
|
39
|
+
"""RGBA image of the 001–011–111 stereographic triangle."""
|
|
40
|
+
yy, xx = np.mgrid[0:n, 0:n]
|
|
41
|
+
u = xx / (n - 1)
|
|
42
|
+
v = 1.0 - yy / (n - 1)
|
|
43
|
+
inside = v <= u + 1e-9 # lower-right half
|
|
44
|
+
|
|
45
|
+
# Barycentric-ish weights: distance to each corner, normalised.
|
|
46
|
+
d100 = np.hypot(u, v) # corner (0, 0)
|
|
47
|
+
d110 = np.hypot(u - 1.0, v) # corner (1, 0)
|
|
48
|
+
d111 = np.hypot(u - 1.0, v - 1.0) # corner (1, 1)
|
|
49
|
+
far = np.maximum.reduce([d100, d110, d111])
|
|
50
|
+
rgb = np.stack([1 - d100 / far, 1 - d110 / far, 1 - d111 / far], -1)
|
|
51
|
+
rgb /= rgb.max(-1, keepdims=True) + 1e-9 # full saturation at the corners
|
|
52
|
+
|
|
53
|
+
img = np.zeros((n, n, 4), np.uint8)
|
|
54
|
+
img[..., :3] = np.clip(rgb, 0, 1) * 255
|
|
55
|
+
img[..., 3] = np.where(inside, 255, 0)
|
|
56
|
+
return img
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# %%
|
|
60
|
+
# A synthetic orientation map
|
|
61
|
+
# ---------------------------
|
|
62
|
+
# Voronoi grains, each with a random orientation, coloured through the same key
|
|
63
|
+
# so the map and its legend agree by construction.
|
|
64
|
+
|
|
65
|
+
rng = np.random.default_rng(11)
|
|
66
|
+
H, W, NGRAIN = 210, 280, 40
|
|
67
|
+
|
|
68
|
+
cy, cx = rng.uniform(0, H, NGRAIN), rng.uniform(0, W, NGRAIN)
|
|
69
|
+
yy, xx = np.mgrid[0:H, 0:W]
|
|
70
|
+
grain = np.hypot(yy[..., None] - cy, xx[..., None] - cx).argmin(-1)
|
|
71
|
+
|
|
72
|
+
# Each grain gets a point in the triangle, then reads its colour off the key.
|
|
73
|
+
gu = rng.uniform(0, 1, NGRAIN)
|
|
74
|
+
gv = rng.uniform(0, 1, NGRAIN) * gu # keep it inside v <= u
|
|
75
|
+
key_img = ipf_triangle()
|
|
76
|
+
kx = np.clip((gu * (KEY_N - 1)).astype(int), 0, KEY_N - 1)
|
|
77
|
+
ky = np.clip(((1 - gv) * (KEY_N - 1)).astype(int), 0, KEY_N - 1)
|
|
78
|
+
grain_rgb = key_img[ky, kx, :3]
|
|
79
|
+
ipf_map = grain_rgb[grain] # (H, W, 3) true colour
|
|
80
|
+
|
|
81
|
+
# %%
|
|
82
|
+
# Pinning the key
|
|
83
|
+
# ---------------
|
|
84
|
+
# ``labels`` draws text *inside* the picture, positioned as fractions of the
|
|
85
|
+
# key image, so the corner indices stay on the corners at any ``size``.
|
|
86
|
+
|
|
87
|
+
fig, ax = apl.subplots(1, 1, figsize=(520, 420))
|
|
88
|
+
vmap = ax.imshow(ipf_map)
|
|
89
|
+
vmap.set_title("orientation map")
|
|
90
|
+
|
|
91
|
+
vmap.add_key(
|
|
92
|
+
key_img,
|
|
93
|
+
corner="bottom-right",
|
|
94
|
+
size=0.34,
|
|
95
|
+
# `align` keeps a label inside the key: centring text on a corner would
|
|
96
|
+
# hang half of it off the edge, where the panel clips it.
|
|
97
|
+
labels=[
|
|
98
|
+
{"x": 0.02, "y": 0.93, "text": "[1 0 0]", "align": "left"},
|
|
99
|
+
{"x": 0.98, "y": 0.93, "text": "[1 1 0]", "align": "right"},
|
|
100
|
+
{"x": 0.98, "y": 0.08, "text": "[1 1 1]", "align": "right"},
|
|
101
|
+
],
|
|
102
|
+
name="ipf",
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
fig
|
|
106
|
+
|
|
107
|
+
# %%
|
|
108
|
+
# A colour wheel over a polarization map
|
|
109
|
+
# --------------------------------------
|
|
110
|
+
# Same mechanism, different legend. Here the key gets a translucent card
|
|
111
|
+
# (``bgcolor``) because the field underneath is saturated everywhere and a bare
|
|
112
|
+
# wheel would fight with it.
|
|
113
|
+
|
|
114
|
+
def hue_wheel(n=KEY_N):
|
|
115
|
+
"""RGBA colour wheel: hue = in-plane angle, value = magnitude."""
|
|
116
|
+
yy, xx = np.mgrid[0:n, 0:n]
|
|
117
|
+
ang = (np.arctan2(-(yy - n / 2), xx - n / 2) + np.pi) / (2 * np.pi)
|
|
118
|
+
rad = np.hypot(yy - n / 2, xx - n / 2) / (n / 2)
|
|
119
|
+
h6 = ang * 6.0
|
|
120
|
+
chan = np.clip(
|
|
121
|
+
np.abs(((h6 + np.array([0, 4, 2])[:, None, None]) % 6) - 3) - 1, 0, 1)
|
|
122
|
+
img = np.zeros((n, n, 4), np.uint8)
|
|
123
|
+
img[..., :3] = chan.transpose(1, 2, 0) * 255 * np.clip(rad, 0, 1)[..., None]
|
|
124
|
+
img[..., 3] = np.where(rad <= 1.0, 255, 0)
|
|
125
|
+
return img
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
# A vortex: the moment angle winds once around the centre.
|
|
129
|
+
ang = np.arctan2(yy - H / 2, xx - W / 2)
|
|
130
|
+
mag = np.clip(np.hypot(yy - H / 2, xx - W / 2) / (0.5 * min(H, W)), 0, 1)
|
|
131
|
+
a6 = ((ang + np.pi) / (2 * np.pi)) * 6.0
|
|
132
|
+
chan = np.clip(np.abs(((a6 + np.array([0, 4, 2])[:, None, None]) % 6) - 3) - 1, 0, 1)
|
|
133
|
+
polar_map = (chan.transpose(1, 2, 0) * 255 * (0.3 + 0.7 * mag)[..., None]).astype(np.uint8)
|
|
134
|
+
|
|
135
|
+
fig2, ax2 = apl.subplots(1, 1, figsize=(520, 420))
|
|
136
|
+
vpol = ax2.imshow(polar_map)
|
|
137
|
+
vpol.set_title("in-plane magnetic polarization")
|
|
138
|
+
|
|
139
|
+
vpol.add_key(
|
|
140
|
+
hue_wheel(),
|
|
141
|
+
corner="top-right",
|
|
142
|
+
size=0.26,
|
|
143
|
+
bgcolor="rgba(0,0,0,0.45)", # legible over a busy field
|
|
144
|
+
border="#ffffff",
|
|
145
|
+
label="moment direction",
|
|
146
|
+
labels=[
|
|
147
|
+
(0.5, 0.06, "N"), (0.94, 0.5, "E"),
|
|
148
|
+
(0.5, 0.94, "S"), (0.06, 0.5, "W"),
|
|
149
|
+
],
|
|
150
|
+
name="wheel",
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
fig2
|
|
154
|
+
|
|
155
|
+
# %%
|
|
156
|
+
# Keeping it out of the way
|
|
157
|
+
# -------------------------
|
|
158
|
+
# ``hover_only=True`` shows the key only while the pointer is over the panel —
|
|
159
|
+
# a reading aid that does not sit on the data while you study it. PNG export
|
|
160
|
+
# renders the panel as though the pointer were there, so an exported figure
|
|
161
|
+
# still carries the key.
|
|
162
|
+
#
|
|
163
|
+
# Everything is live: :meth:`~anyplotlib.KeyOverlay.set` restyles a key without
|
|
164
|
+
# re-sending the picture, and :meth:`~anyplotlib.KeyOverlay.set_image` swaps
|
|
165
|
+
# the picture without disturbing the placement::
|
|
166
|
+
#
|
|
167
|
+
# key = vmap.get_key("ipf")
|
|
168
|
+
# key.set(size=0.4, corner="top-left")
|
|
169
|
+
# key.visible = False
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: anyplotlib
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.1
|
|
4
4
|
Summary: A plotting library using python, javascript and anywidget for performant in browser plotting.
|
|
5
5
|
Project-URL: Homepage, https://cssfrancis.github.io/anyplotlib/
|
|
6
6
|
Project-URL: Repository, https://github.com/CSSFrancis/anyplotlib
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# FIGURE_ESM.md — Navigator for `figure_esm.js`
|
|
2
2
|
|
|
3
|
-
`figure_esm.js` is **~9,
|
|
3
|
+
`figure_esm.js` is **~9,470 lines** and one big closure. Everything lives inside
|
|
4
4
|
`function render({ model, el })` so that all helpers share the same scope
|
|
5
5
|
(`theme`, `PAD_*`, `panels` Map, etc.). This document is a section map so you
|
|
6
6
|
can jump straight to the relevant code without reading the whole file.
|
|
@@ -55,23 +55,24 @@ Rule 5 – Text never clips. Optional gutters earn real layout space:
|
|
|
55
55
|
| **2D gutter geometry**: `_cbWidth` / `_cbGap` / `_padT` / `_titlePx` | 301 / 313 / 323 / 333 |
|
|
56
56
|
| **Layout engine** `applyLayout` | 774 |
|
|
57
57
|
| `_buildCanvasStack` | 857 |
|
|
58
|
-
| `_createPanelDOM` |
|
|
59
|
-
| `_createInsetDOM` / `_applyAllInsetStates` |
|
|
60
|
-
| `_resizePanelDOM` |
|
|
61
|
-
| **2D drawing**: `_imgFitRect` |
|
|
62
|
-
| `draw2d` |
|
|
63
|
-
| `drawScaleBar2d` / `drawColorbar2d` |
|
|
64
|
-
| `
|
|
65
|
-
| `
|
|
66
|
-
|
|
|
58
|
+
| `_createPanelDOM` | 999 |
|
|
59
|
+
| `_createInsetDOM` / `_applyAllInsetStates` | 1129 / 1512 |
|
|
60
|
+
| `_resizePanelDOM` | 2225 |
|
|
61
|
+
| **2D drawing**: `_imgFitRect` | 2384 |
|
|
62
|
+
| `draw2d` | 2692 |
|
|
63
|
+
| `drawScaleBar2d` / `drawColorbar2d` | 2887 / 3125 |
|
|
64
|
+
| **Floating keys**: `_keyEnsure` / `_keyRect` / `drawKeys` | 2986 / 3009 / 3022 |
|
|
65
|
+
| `_drawAxes2d` (ticks, labels, title) | 3180 |
|
|
66
|
+
| `drawOverlay2d` / `drawMarkers2d` | 3333 / 3497 |
|
|
67
|
+
| **Image layers**: `_layerBytes` / `_layerBitmap` / `_drawLayers2d` | 2512 / 2536 / 2597 |
|
|
67
68
|
| Binary-bytes splice: `_spliceBinaryBytes` / `_registerBinaryPixelListeners` | 730 / 761 |
|
|
68
|
-
| **3D drawing**: `draw3d` |
|
|
69
|
-
| Event emission `_emitEvent` |
|
|
70
|
-
| 3D event handlers `_attachEvents3d` |
|
|
71
|
-
| **1D drawing**: `draw1d` |
|
|
72
|
-
| `_drawLine` (1D series + markers) |
|
|
73
|
-
| `drawOverlay1d` / `drawMarkers1d` |
|
|
74
|
-
| Marker hit-test `_markerHitTest2d` |
|
|
69
|
+
| **3D drawing**: `draw3d` | 5236 |
|
|
70
|
+
| Event emission `_emitEvent` | 6073 |
|
|
71
|
+
| 3D event handlers `_attachEvents3d` | 6125 |
|
|
72
|
+
| **1D drawing**: `draw1d` | 6346 |
|
|
73
|
+
| `_drawLine` (1D series + markers) | 6499 |
|
|
74
|
+
| `drawOverlay1d` / `drawMarkers1d` | 6792 / 6876 |
|
|
75
|
+
| Marker hit-test `_markerHitTest2d` | 7144 |
|
|
75
76
|
|
|
76
77
|
> **`raster` marker (1D/PlotXY)** — `drawMarkers1d` has a `type==='raster'`
|
|
77
78
|
> branch that blits a single RGBA image across data-coord `extent` (the fast
|
|
@@ -80,16 +81,16 @@ Rule 5 – Text never clips. Optional gutters earn real layout space:
|
|
|
80
81
|
> redraws never re-transmit them; the decoded `OffscreenCanvas` is cached on
|
|
81
82
|
> the marker set (`ms._rasterBmp`/`_rasterKey`). The shared `clip_path` block
|
|
82
83
|
> clips it to a curved sector.
|
|
83
|
-
| Panel event dispatch `_attachPanelEvents` |
|
|
84
|
-
| 2D events `_attachEvents2d` |
|
|
85
|
-
| 1D events `_attachEvents1d` |
|
|
86
|
-
| 2D widget drag `_ovHitTest2d` / `_doDrag2d` |
|
|
87
|
-
| **Brush strokes**: `_brushLiveBegin` / `_brushCommit` / `_brushErase` / `_brushPaintAt` |
|
|
88
|
-
| 1D widget drag `_canvasXToFrac1d` … / snapping `_snapVal` |
|
|
89
|
-
| Shared-axis propagation `_getShareGroups` |
|
|
90
|
-
| Figure resize `_applyFigResizeDOM` |
|
|
91
|
-
| **Bar chart**: `_barGeom` / `drawBar` / `_attachEventsBar` |
|
|
92
|
-
| Generic redraw `_redrawPanel` |
|
|
84
|
+
| Panel event dispatch `_attachPanelEvents` | 7401 |
|
|
85
|
+
| 2D events `_attachEvents2d` | 7443 |
|
|
86
|
+
| 1D events `_attachEvents1d` | 7827 |
|
|
87
|
+
| 2D widget drag `_ovHitTest2d` / `_doDrag2d` | 8099 / 8372 |
|
|
88
|
+
| **Brush strokes**: `_brushLiveBegin` / `_brushCommit` / `_brushErase` / `_brushPaintAt` | 8285 / 8299 / 8328 / 8363 |
|
|
89
|
+
| 1D widget drag `_canvasXToFrac1d` … / snapping `_snapVal` | 8495 / 8568 |
|
|
90
|
+
| Shared-axis propagation `_getShareGroups` | 8639 |
|
|
91
|
+
| Figure resize `_applyFigResizeDOM` | 8703 |
|
|
92
|
+
| **Bar chart**: `_barGeom` / `drawBar` / `_attachEventsBar` | 8894 / 8957 / 9333 |
|
|
93
|
+
| Generic redraw `_redrawPanel` | 9523 |
|
|
93
94
|
|
|
94
95
|
> **`brush` widget (2-D)** — the one widget whose drag is *modal*, and the one
|
|
95
96
|
> that must NOT write the model per tick. `_ovHitTest2d` takes an extra `mods`
|
|
@@ -15,6 +15,7 @@ from anyplotlib.plotxy import PlotXY
|
|
|
15
15
|
from anyplotlib.callbacks import CallbackRegistry, Event
|
|
16
16
|
from anyplotlib import embed
|
|
17
17
|
from anyplotlib.markers import MarkerRegistry, MarkerGroup
|
|
18
|
+
from anyplotlib.keys import KeyOverlay
|
|
18
19
|
from anyplotlib.widgets import (
|
|
19
20
|
Widget, RectangleWidget, CircleWidget, AnnularWidget,
|
|
20
21
|
CrosshairWidget, PolygonWidget, LabelWidget, ArrowWidget, BrushWidget,
|
|
@@ -43,7 +44,7 @@ __all__ = [
|
|
|
43
44
|
"Axes", "InsetAxes", "Plot1D", "Plot2D", "PlotMesh", "Plot3D", "PlotBar",
|
|
44
45
|
"Line1D",
|
|
45
46
|
"CallbackRegistry", "Event",
|
|
46
|
-
"MarkerRegistry", "MarkerGroup",
|
|
47
|
+
"MarkerRegistry", "MarkerGroup", "KeyOverlay",
|
|
47
48
|
"Widget", "RectangleWidget", "CircleWidget", "AnnularWidget",
|
|
48
49
|
"CrosshairWidget", "PolygonWidget", "LabelWidget", "ArrowWidget",
|
|
49
50
|
"BrushWidget",
|
|
@@ -76,6 +76,172 @@ class _BasePlot(_EventMixin):
|
|
|
76
76
|
self._state["axis_visible"] = True
|
|
77
77
|
self._push()
|
|
78
78
|
|
|
79
|
+
# ------------------------------------------------------------------
|
|
80
|
+
# Floating image keys (see anyplotlib/keys.py)
|
|
81
|
+
# ------------------------------------------------------------------
|
|
82
|
+
def add_key(self, image, *, corner: str = "top-right", anchor=None,
|
|
83
|
+
size: float = 0.22, margin: float = 10.0,
|
|
84
|
+
bgcolor=None, border=None, border_width: float = 1.0,
|
|
85
|
+
radius: float = 4.0, alpha: float = 1.0,
|
|
86
|
+
hover_only: bool = False, visible: bool = True,
|
|
87
|
+
label=None, label_size: float = 10.0, label_color=None,
|
|
88
|
+
labels=None, name=None) -> "KeyOverlay":
|
|
89
|
+
"""Pin a floating image key over this panel.
|
|
90
|
+
|
|
91
|
+
A key is a small picture that floats in screen space over the plot
|
|
92
|
+
area — it does not pan or zoom with the data. Use it for a colour
|
|
93
|
+
legend a colorbar cannot express: an inverse pole figure triangle over
|
|
94
|
+
an orientation map, a hue wheel over a polarization field, a phase key
|
|
95
|
+
over a segmentation::
|
|
96
|
+
|
|
97
|
+
key = plot.add_key(ipf_triangle, corner="bottom-right", size=0.28)
|
|
98
|
+
wheel = plot.add_key(hue_wheel, corner="top-left",
|
|
99
|
+
bgcolor="none", hover_only=True)
|
|
100
|
+
|
|
101
|
+
This is the lightweight sibling of :meth:`Figure.add_inset`. An inset
|
|
102
|
+
is a draggable window with a title bar and its own canvas stack — the
|
|
103
|
+
right tool when the overlay is a live plot. A key is a static picture
|
|
104
|
+
with no chrome unless you ask for it, so it reads as part of the
|
|
105
|
+
figure rather than as a floating panel.
|
|
106
|
+
|
|
107
|
+
Parameters
|
|
108
|
+
----------
|
|
109
|
+
image : array-like, bytes, or path
|
|
110
|
+
An ``(H, W, 3|4)`` colour array (uint8, or float 0–1), the raw
|
|
111
|
+
bytes of a PNG/JPEG/GIF/WebP, or a path to such a file. An RGBA
|
|
112
|
+
array is the usual choice: alpha 0 outside the shape lets a
|
|
113
|
+
triangle or a disc sit on the image without a rectangular card
|
|
114
|
+
around it.
|
|
115
|
+
corner : str, optional
|
|
116
|
+
``"top-right"`` (default), ``"top-left"``, ``"bottom-right"`` or
|
|
117
|
+
``"bottom-left"``. Ignored when *anchor* is given.
|
|
118
|
+
anchor : (x_frac, y_frac), optional
|
|
119
|
+
Free placement: the key's centre as a fraction of the plot area,
|
|
120
|
+
from its top-left. Overrides *corner*.
|
|
121
|
+
size : float, optional
|
|
122
|
+
Width as a fraction of the plot area's **shorter** side, so a key
|
|
123
|
+
keeps its proportions when the panel is resized. Default 0.22.
|
|
124
|
+
Height follows the image's aspect ratio.
|
|
125
|
+
margin : float, optional
|
|
126
|
+
Gap in CSS px between the key and the plot-area edge, for corner
|
|
127
|
+
placement. Default 10.
|
|
128
|
+
bgcolor : str, optional
|
|
129
|
+
CSS colour painted behind the image — e.g. ``"rgba(0,0,0,0.45)"``
|
|
130
|
+
for a legible card over busy data. Default ``None`` (fully
|
|
131
|
+
transparent); ``"none"`` means the same thing.
|
|
132
|
+
border : str, optional
|
|
133
|
+
CSS colour for a hairline around the card. Default ``None``.
|
|
134
|
+
border_width : float, optional
|
|
135
|
+
Border stroke width in px. Default 1.
|
|
136
|
+
radius : float, optional
|
|
137
|
+
Corner radius of the card in px. Default 4.
|
|
138
|
+
alpha : float, optional
|
|
139
|
+
Opacity of the whole key, 0–1. Default 1.
|
|
140
|
+
hover_only : bool, optional
|
|
141
|
+
Show the key only while the pointer is over the panel. Default
|
|
142
|
+
``False``. Useful for a reading aid you do not want sitting over
|
|
143
|
+
the data all the time. PNG export renders the panel as though the
|
|
144
|
+
pointer were over it, so a hover-only key **is** included in an
|
|
145
|
+
exported figure — what you save is what you see while reading.
|
|
146
|
+
visible : bool, optional
|
|
147
|
+
Draw the key at all. Default ``True``.
|
|
148
|
+
label : str, optional
|
|
149
|
+
Caption drawn under the image, mini-TeX enabled like axis labels.
|
|
150
|
+
label_size : float, optional
|
|
151
|
+
Caption size in px. Default 10.
|
|
152
|
+
label_color : str, optional
|
|
153
|
+
Caption colour. Default ``None`` (the theme's tick-label colour).
|
|
154
|
+
labels : list, optional
|
|
155
|
+
Text drawn *inside* the key, for annotating the picture itself —
|
|
156
|
+
an IPF triangle's corner indices, a wheel's compass points. Each
|
|
157
|
+
entry is ``(x, y, text)`` or a dict with those keys plus optional
|
|
158
|
+
``size`` / ``color`` / ``align``. ``x`` and ``y`` are fractions of
|
|
159
|
+
the key image, so the text follows the picture when the key is
|
|
160
|
+
resized. Mini-TeX works here as in any label::
|
|
161
|
+
|
|
162
|
+
tri.add_key(ipf, labels=[
|
|
163
|
+
(0.02, 0.97, "[1 0 0]"),
|
|
164
|
+
(0.98, 0.97, "[1 1 0]"),
|
|
165
|
+
(0.98, 0.03, "[1 1 1]"),
|
|
166
|
+
])
|
|
167
|
+
name : str, optional
|
|
168
|
+
Handle for :meth:`get_key`. Defaults to the generated id.
|
|
169
|
+
|
|
170
|
+
Returns
|
|
171
|
+
-------
|
|
172
|
+
KeyOverlay
|
|
173
|
+
|
|
174
|
+
See Also
|
|
175
|
+
--------
|
|
176
|
+
remove_key, list_keys, get_key
|
|
177
|
+
anyplotlib.Figure.add_inset : a full floating axes, for live plots.
|
|
178
|
+
"""
|
|
179
|
+
from anyplotlib._utils import _image_to_data_url
|
|
180
|
+
from anyplotlib.keys import KeyOverlay, _validate
|
|
181
|
+
|
|
182
|
+
fields = _validate(dict(
|
|
183
|
+
corner=corner, anchor=anchor, size=size, margin=margin,
|
|
184
|
+
bgcolor=bgcolor, border=border, border_width=border_width,
|
|
185
|
+
radius=radius, alpha=alpha, hover_only=hover_only,
|
|
186
|
+
visible=visible, label=label, label_size=label_size,
|
|
187
|
+
label_color=label_color, labels=labels))
|
|
188
|
+
key = KeyOverlay(self, _image_to_data_url(image), name=name, **fields)
|
|
189
|
+
if any(k.name == key.name for k in self._key_map.values()):
|
|
190
|
+
raise ValueError(f"a key named {key.name!r} already exists on this "
|
|
191
|
+
"panel; pass a different name=")
|
|
192
|
+
self._key_map[key.id] = key
|
|
193
|
+
self._push_keys()
|
|
194
|
+
return key
|
|
195
|
+
|
|
196
|
+
@property
|
|
197
|
+
def _key_map(self) -> dict:
|
|
198
|
+
"""Lazily-created ``{id: KeyOverlay}`` — panels predate this feature."""
|
|
199
|
+
if getattr(self, "_keys_dict", None) is None:
|
|
200
|
+
self._keys_dict = {}
|
|
201
|
+
return self._keys_dict
|
|
202
|
+
|
|
203
|
+
def _push_keys(self) -> None:
|
|
204
|
+
"""Re-serialise the key list + image table, then push.
|
|
205
|
+
|
|
206
|
+
The pictures ride the geometry channel under ``key_images`` so that
|
|
207
|
+
restyling a key — or a hover toggle — never re-transmits them.
|
|
208
|
+
"""
|
|
209
|
+
keys = list(self._key_map.values())
|
|
210
|
+
self._state["keys"] = [k.to_dict() for k in keys]
|
|
211
|
+
self._state["key_images"] = {k.id: k.image_url for k in keys}
|
|
212
|
+
self._push()
|
|
213
|
+
|
|
214
|
+
def get_key(self, name):
|
|
215
|
+
"""Return the key with this *name* (or id).
|
|
216
|
+
|
|
217
|
+
Raises
|
|
218
|
+
------
|
|
219
|
+
KeyError
|
|
220
|
+
If no key matches.
|
|
221
|
+
"""
|
|
222
|
+
for k in self._key_map.values():
|
|
223
|
+
if k.name == name or k.id == name:
|
|
224
|
+
return k
|
|
225
|
+
raise KeyError(f"no key named {name!r}")
|
|
226
|
+
|
|
227
|
+
def remove_key(self, key) -> None:
|
|
228
|
+
"""Remove a key, by object, name, or id."""
|
|
229
|
+
from anyplotlib.keys import KeyOverlay
|
|
230
|
+
kid = key.id if isinstance(key, KeyOverlay) else self.get_key(key).id
|
|
231
|
+
if kid not in self._key_map:
|
|
232
|
+
raise KeyError(kid)
|
|
233
|
+
del self._key_map[kid]
|
|
234
|
+
self._push_keys()
|
|
235
|
+
|
|
236
|
+
def list_keys(self) -> list:
|
|
237
|
+
"""Every key on this panel, in creation order."""
|
|
238
|
+
return list(self._key_map.values())
|
|
239
|
+
|
|
240
|
+
def clear_keys(self) -> None:
|
|
241
|
+
"""Remove every key from this panel."""
|
|
242
|
+
self._key_map.clear()
|
|
243
|
+
self._push_keys()
|
|
244
|
+
|
|
79
245
|
@contextmanager
|
|
80
246
|
def _python_view_push(self):
|
|
81
247
|
"""Context manager for view setters that must signal _view_from_python.
|
|
@@ -300,7 +300,7 @@ class Figure(anywidget.AnyWidget, _EventMixin):
|
|
|
300
300
|
self._push(pid)
|
|
301
301
|
self._push_layout()
|
|
302
302
|
|
|
303
|
-
def _push(self, panel_id: str) -> None:
|
|
303
|
+
def _push(self, panel_id: str, *, resolve_pixels: bool = False) -> None:
|
|
304
304
|
"""Serialise one panel and write to its trait.
|
|
305
305
|
|
|
306
306
|
Inside a :meth:`batch` block, pushes are coalesced: each panel is
|
|
@@ -309,6 +309,14 @@ class Figure(anywidget.AnyWidget, _EventMixin):
|
|
|
309
309
|
many per-frame pushes of a linked-view update (set_data + set_title +
|
|
310
310
|
widget moves on the same panel) into one serialise/transfer per panel
|
|
311
311
|
— the dominant cost over a Pyodide comm boundary.
|
|
312
|
+
|
|
313
|
+
Parameters
|
|
314
|
+
----------
|
|
315
|
+
resolve_pixels : bool, optional
|
|
316
|
+
Force pixel change-tokens to be materialised to inline base64 even
|
|
317
|
+
when the binary transport is live. Set by :meth:`_sync_for_export`
|
|
318
|
+
because a snapshot has no PLOTBIN channel to carry the bytes; see
|
|
319
|
+
the token discussion below.
|
|
312
320
|
"""
|
|
313
321
|
plot = self._plots_map.get(panel_id)
|
|
314
322
|
if plot is None:
|
|
@@ -329,7 +337,15 @@ class Figure(anywidget.AnyWidget, _EventMixin):
|
|
|
329
337
|
# save_html / Jupyter figure with no binary channel — materialise the
|
|
330
338
|
# real base64 inline so the pixels actually travel. ``_binary_wire``
|
|
331
339
|
# matches the producer's gate (``Plot2D._encode_pixels``).
|
|
332
|
-
|
|
340
|
+
#
|
|
341
|
+
# ``resolve_pixels`` overrides that gate for an EXPORT. A snapshot is by
|
|
342
|
+
# definition off-wire: whatever PLOTBIN would have delivered never
|
|
343
|
+
# arrives, so a token left in the state is a dangling reference and the
|
|
344
|
+
# pixels are simply lost. The gate reads a process-global env var, which
|
|
345
|
+
# is on in a host app even while THIS push is serialising a snapshot —
|
|
346
|
+
# so the export has to say so explicitly.
|
|
347
|
+
if (geom_keys and (resolve_pixels or not _binary_wire())
|
|
348
|
+
and hasattr(plot, "resolve_pixel_tokens")):
|
|
333
349
|
plot.resolve_pixel_tokens(state)
|
|
334
350
|
if geom_keys and self.has_trait(gname):
|
|
335
351
|
# Split heavy geometry into its own channel. Detect change by
|
|
@@ -814,9 +830,17 @@ class Figure(anywidget.AnyWidget, _EventMixin):
|
|
|
814
830
|
Called from ``_repr_utils._widget_state``, the one chokepoint every
|
|
815
831
|
export path goes through. The live Jupyter path deliberately keeps
|
|
816
832
|
using targeted pushes and does not pay this cost.
|
|
833
|
+
|
|
834
|
+
The re-push passes ``resolve_pixels=True``: this rewrites the panel
|
|
835
|
+
traits, and under a live binary transport an ordinary push leaves pixel
|
|
836
|
+
change-tokens in place for PLOTBIN to fill in. A snapshot has no
|
|
837
|
+
PLOTBIN, so those tokens would be dangling — and because the re-push
|
|
838
|
+
rewrites ``panel_<id>_json`` unconditionally it would also undo any
|
|
839
|
+
materialisation the caller did beforehand. An export always ships real
|
|
840
|
+
pixels.
|
|
817
841
|
"""
|
|
818
842
|
for panel_id in list(self._plots_map):
|
|
819
|
-
self._push(panel_id)
|
|
843
|
+
self._push(panel_id, resolve_pixels=True)
|
|
820
844
|
|
|
821
845
|
def _push_panel_fields(self, panel_id: str, fields: dict) -> None:
|
|
822
846
|
"""Apply a small set of changed *fields* to a panel, then push once.
|