jarvisplot 2.1.6__tar.gz → 2.1.7__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.
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/JarvisPLOT.egg-info/PKG-INFO +12 -2
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/JarvisPLOT.egg-info/SOURCES.txt +12 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/PKG-INFO +12 -2
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/README.md +11 -1
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/adapters_rect.py +0 -1
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/config_runtime.py +2 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/figure.py +45 -21
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/layout_runtime.py +0 -2
- jarvisplot-2.1.7/jarvisplot/Figure/legend_runtime.py +94 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/capabilities.py +6 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/2x1/dynesty_runplot.json +5 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/2x1/rect.json +1 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/2x1/rect5x1.json +5 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/2x1/rect_cmap.json +1 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/2x1/rect_marginal.json +3 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/2x1/rectratio.json +2 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/2x1/ternary.json +1 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/2x1/ternary_cmap.json +1 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/4x1/rect_cmap.json +1 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/corrplot/diamond.json +1 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/corrplot/matrix.json +1 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/gambit/2x1/rect_cmap.json +1 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/gambit/2x1/ternary.json +1 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/gambit/2x1/ternary_cmap.json +1 -0
- jarvisplot-2.1.7/jarvisplot/cards/legends/compact/legend-card.json +15 -0
- jarvisplot-2.1.7/jarvisplot/cards/legends/default/legend-card.json +68 -0
- jarvisplot-2.1.7/jarvisplot/cards/legends/paper/legend-card.json +11 -0
- jarvisplot-2.1.7/jarvisplot/cards/legends/presentation/legend-card.json +16 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/diagnostic_guidance.py +15 -6
- jarvisplot-2.1.7/jarvisplot/legend_cards.py +250 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/man_render_agent.py +4 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/man_render_human.py +13 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/layer-method.yaml +5 -1
- jarvisplot-2.1.7/jarvisplot/manual_cards/legend.yaml +117 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/manifest.yaml +4 -0
- jarvisplot-2.1.7/jarvisplot/manual_cards/style-axes.yaml +58 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/render_health.py +9 -50
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/core/figure.json +13 -5
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/core/layer.json +13 -1
- jarvisplot-2.1.7/jarvisplot/schema/core/legend-card.json +106 -0
- jarvisplot-2.1.7/jarvisplot/schema/core/legend.json +53 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/manifest.json +2 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/validation.py +43 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/pyproject.toml +1 -1
- jarvisplot-2.1.7/tests/test_layer_legend.py +186 -0
- jarvisplot-2.1.7/tests/test_legend_cards.py +185 -0
- jarvisplot-2.1.7/tests/test_legend_runtime.py +138 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_render_health.py +15 -13
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_schema_catalog.py +5 -7
- jarvisplot-2.1.6/jarvisplot/manual_cards/style-axes.yaml +0 -35
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/JarvisPLOT.egg-info/dependency_links.txt +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/JarvisPLOT.egg-info/entry_points.txt +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/JarvisPLOT.egg-info/requires.txt +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/JarvisPLOT.egg-info/top_level.txt +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/__init__.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/adapters_ternary.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/adaptive_cdf_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/bin_stat_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/cards/std_axes_adapter_config.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/colorbar_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/corr_layout.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/corr_layout_diamond.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/corr_order.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/correlation_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/corrplot_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/data_pipelines.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/debug_config.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/density_cell_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/design_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/distribution_1d_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/dynesty_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/figure_types.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/helper.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/interp_2d_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/interp_natural_neighbor.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/interp_natural_neighbor_exact.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/layer_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/method_registry.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/posterior_density_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/posterior_hpd.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/posterior_mesh.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/preprocessor.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/preprocessor_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/profile_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/significance_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/Figure/style_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/__init__.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/agent_digest.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/agent_io.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cache_store.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/1x1/ternary.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/4x1/rect.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/4x1/ternary.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/a4paper/4x1/ternary_cmap.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/args.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/colors/colormaps.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/default/output.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/flowchart/default.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/gambit/1x1/ternary.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/icons/JarvisHEP.png +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/icons/flowchart/JarvisHEP.png +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/icons/flowchart/calculator.png +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/icons/flowchart/inputfile.png +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/icons/flowchart/opera.png +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/icons/flowchart/outputfile.png +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/icons/flowchart/sampler.png +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/icons/gambit.png +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/icons/gambit_small.png +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cards/style_preference.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cli.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/cli_help.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/client.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/column_demand.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/column_probe.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/config.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/config_address.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/core.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/core_assets.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/core_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/data_access.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/data_generation_contracts.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/data_loader.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/data_loader_hdf5.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/data_loader_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/data_loader_summary.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/dataset_types.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/diagnostics.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/distribution_1d_config.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/dryrun_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/expr_names.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/fix_apply.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/flowchart.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/generated_data.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/inner_func.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/man_catalog.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/man_methods.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/man_transforms.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/agent-output.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/cli-map.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/data-columns.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/debug-overlay.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/diagnostics.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/dryrun-viz.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/field-interp.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/generated-data.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/method_notes.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/type-correlation-matrix.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/type-posterior-2d.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/type-profile-2d.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/validate.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/workflow.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/manual_cards/yaml-root.yaml +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/memtrace.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/method_contracts.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/core/common.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/core/dataset.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/core/distribution-1d.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/core/generated-data.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/core/transform.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/bar.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/barh.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/contour.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/contourf.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/corrplot.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/dynesty_runplot.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/errorbar.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/fill.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/fill_between.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/fill_betweenx.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/hist.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/hist2d.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/imshow.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/jpcontour.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/jpcontourf.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/jpfield.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/pcolor.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/pcolormesh.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/plot.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/quiver.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/scatter.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/stairs.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/step.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/tricontour.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/tricontourf.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/tripcolor.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/tripcolor_axes.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/triplot.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/voronoi.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/methods/voronoif.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema/plot-config.json +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema_catalog.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/schema_diagnostics.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/templates_catalog.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/transform_contracts.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/utils/__init__.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/utils/cmaps.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/utils/dataframes.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/utils/expression.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/utils/interpolator.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/utils/pathing.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/__init__.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/cap.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/config_cmd.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/data.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/doctor.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/dryrun.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/explain.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/man.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/suggest.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/template.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/verbs/validate.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/jarvisplot/yaml_io.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/setup.cfg +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_adaptive_cdf.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_agent_digest.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_agent_envelope.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_axis_title.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_capabilities.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_card_debug_shape.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_cli_help.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_cli_verbs.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_cmaps.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_column_existence.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_config_addressing.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_config_edit.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_config_expand.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_correlation_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_corrplot.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_data_access.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_data_describe.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_data_head_eval.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_data_loader_contracts.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_data_pipelines.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_debug_config.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_debug_switches.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_debug_yaml_override.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_density_cell_transform.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_design_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_diagnostic_guidance.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_distribution_1d_transform.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_docs_status_labels.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_doctor_partial.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_explain.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_figure_contracts.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_figure_type_expander.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_fix_application.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_flowchart_renderer.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_generated_data.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_imshow_adapter.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_interp_2d_transform.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_interp_natural_neighbor.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_interpolator_contracts.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_jpcontour_methods.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_man_cli.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_method_contracts.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_parse_data_metadata.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_pathing_contracts.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_posterior_hpd.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_profile_runtime.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_row_ledger.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_suggest.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_suggest_axes.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_template_catalog.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_template_json.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_ternary_debug.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_transform_contracts.py +0 -0
- {jarvisplot-2.1.6 → jarvisplot-2.1.7}/tests/test_validate_no_matplotlib.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: JarvisPLOT
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.7
|
|
4
4
|
Summary: Jarvis-PLOT: YAML-driven plotting engine
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -160,12 +160,22 @@ The loop `jplot man` prints is:
|
|
|
160
160
|
carry `JP-*` codes; `jplot explain JP-XXX-NNN` expands any of them.
|
|
161
161
|
5. `jplot <file>` — render, only when the figure itself is needed.
|
|
162
162
|
|
|
163
|
-
`jplot man --json` is the machine-readable manual:
|
|
163
|
+
`jplot man --json` is the machine-readable manual: a topic index, plus
|
|
164
164
|
live pages for every registered layer method and transform step
|
|
165
165
|
(`jplot man scatter`, `jplot man transform.profile`, `jplot man PDF1D`). Method contracts come from
|
|
166
166
|
the same registry `jplot cap methods` reads, so a man page cannot drift from the
|
|
167
167
|
code.
|
|
168
168
|
|
|
169
|
+
For compact legends and keys composed from real layers, use
|
|
170
|
+
`jplot man legend --json`. Declare `legend: {object, label, role}` on each drawing layer; components
|
|
171
|
+
with the same object regroup automatically using card templates such as
|
|
172
|
+
`band_line`, `line_errorbar` and `error_bounds`. The role is optional for a
|
|
173
|
+
single-component object. `frame.<axes>.legend` owns card selection, `order`,
|
|
174
|
+
`ncols`, position and spacing. JSON cards provide
|
|
175
|
+
reusable defaults, and YAML can override them. See
|
|
176
|
+
[the legend contract](docs/specs/LEGEND.md) and the
|
|
177
|
+
[self-contained example](Example/compact_legend.yaml).
|
|
178
|
+
|
|
169
179
|
For continuous one-dimensional distributions from raw samples, use `PDF1D`
|
|
170
180
|
(CDF plus PDF) or `CDF1D` in a data transform. `coordinates.x` owns `expr`,
|
|
171
181
|
`lim`, and `grid`; optional `repeat` computes independent batch means and
|
|
@@ -37,6 +37,7 @@ jarvisplot/fix_apply.py
|
|
|
37
37
|
jarvisplot/flowchart.py
|
|
38
38
|
jarvisplot/generated_data.py
|
|
39
39
|
jarvisplot/inner_func.py
|
|
40
|
+
jarvisplot/legend_cards.py
|
|
40
41
|
jarvisplot/man_catalog.py
|
|
41
42
|
jarvisplot/man_methods.py
|
|
42
43
|
jarvisplot/man_render_agent.py
|
|
@@ -77,6 +78,7 @@ jarvisplot/Figure/interp_natural_neighbor.py
|
|
|
77
78
|
jarvisplot/Figure/interp_natural_neighbor_exact.py
|
|
78
79
|
jarvisplot/Figure/layer_runtime.py
|
|
79
80
|
jarvisplot/Figure/layout_runtime.py
|
|
81
|
+
jarvisplot/Figure/legend_runtime.py
|
|
80
82
|
jarvisplot/Figure/method_registry.py
|
|
81
83
|
jarvisplot/Figure/posterior_density_runtime.py
|
|
82
84
|
jarvisplot/Figure/posterior_hpd.py
|
|
@@ -120,6 +122,10 @@ jarvisplot/cards/icons/flowchart/inputfile.png
|
|
|
120
122
|
jarvisplot/cards/icons/flowchart/opera.png
|
|
121
123
|
jarvisplot/cards/icons/flowchart/outputfile.png
|
|
122
124
|
jarvisplot/cards/icons/flowchart/sampler.png
|
|
125
|
+
jarvisplot/cards/legends/compact/legend-card.json
|
|
126
|
+
jarvisplot/cards/legends/default/legend-card.json
|
|
127
|
+
jarvisplot/cards/legends/paper/legend-card.json
|
|
128
|
+
jarvisplot/cards/legends/presentation/legend-card.json
|
|
123
129
|
jarvisplot/manual_cards/agent-output.yaml
|
|
124
130
|
jarvisplot/manual_cards/cli-map.yaml
|
|
125
131
|
jarvisplot/manual_cards/data-columns.yaml
|
|
@@ -129,6 +135,7 @@ jarvisplot/manual_cards/dryrun-viz.yaml
|
|
|
129
135
|
jarvisplot/manual_cards/field-interp.yaml
|
|
130
136
|
jarvisplot/manual_cards/generated-data.yaml
|
|
131
137
|
jarvisplot/manual_cards/layer-method.yaml
|
|
138
|
+
jarvisplot/manual_cards/legend.yaml
|
|
132
139
|
jarvisplot/manual_cards/manifest.yaml
|
|
133
140
|
jarvisplot/manual_cards/method_notes.yaml
|
|
134
141
|
jarvisplot/manual_cards/style-axes.yaml
|
|
@@ -146,6 +153,8 @@ jarvisplot/schema/core/distribution-1d.json
|
|
|
146
153
|
jarvisplot/schema/core/figure.json
|
|
147
154
|
jarvisplot/schema/core/generated-data.json
|
|
148
155
|
jarvisplot/schema/core/layer.json
|
|
156
|
+
jarvisplot/schema/core/legend-card.json
|
|
157
|
+
jarvisplot/schema/core/legend.json
|
|
149
158
|
jarvisplot/schema/core/transform.json
|
|
150
159
|
jarvisplot/schema/methods/bar.json
|
|
151
160
|
jarvisplot/schema/methods/barh.json
|
|
@@ -234,6 +243,9 @@ tests/test_interp_2d_transform.py
|
|
|
234
243
|
tests/test_interp_natural_neighbor.py
|
|
235
244
|
tests/test_interpolator_contracts.py
|
|
236
245
|
tests/test_jpcontour_methods.py
|
|
246
|
+
tests/test_layer_legend.py
|
|
247
|
+
tests/test_legend_cards.py
|
|
248
|
+
tests/test_legend_runtime.py
|
|
237
249
|
tests/test_man_cli.py
|
|
238
250
|
tests/test_method_contracts.py
|
|
239
251
|
tests/test_parse_data_metadata.py
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: JarvisPLOT
|
|
3
|
-
Version: 2.1.
|
|
3
|
+
Version: 2.1.7
|
|
4
4
|
Summary: Jarvis-PLOT: YAML-driven plotting engine
|
|
5
5
|
Requires-Python: >=3.10
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -160,12 +160,22 @@ The loop `jplot man` prints is:
|
|
|
160
160
|
carry `JP-*` codes; `jplot explain JP-XXX-NNN` expands any of them.
|
|
161
161
|
5. `jplot <file>` — render, only when the figure itself is needed.
|
|
162
162
|
|
|
163
|
-
`jplot man --json` is the machine-readable manual:
|
|
163
|
+
`jplot man --json` is the machine-readable manual: a topic index, plus
|
|
164
164
|
live pages for every registered layer method and transform step
|
|
165
165
|
(`jplot man scatter`, `jplot man transform.profile`, `jplot man PDF1D`). Method contracts come from
|
|
166
166
|
the same registry `jplot cap methods` reads, so a man page cannot drift from the
|
|
167
167
|
code.
|
|
168
168
|
|
|
169
|
+
For compact legends and keys composed from real layers, use
|
|
170
|
+
`jplot man legend --json`. Declare `legend: {object, label, role}` on each drawing layer; components
|
|
171
|
+
with the same object regroup automatically using card templates such as
|
|
172
|
+
`band_line`, `line_errorbar` and `error_bounds`. The role is optional for a
|
|
173
|
+
single-component object. `frame.<axes>.legend` owns card selection, `order`,
|
|
174
|
+
`ncols`, position and spacing. JSON cards provide
|
|
175
|
+
reusable defaults, and YAML can override them. See
|
|
176
|
+
[the legend contract](docs/specs/LEGEND.md) and the
|
|
177
|
+
[self-contained example](Example/compact_legend.yaml).
|
|
178
|
+
|
|
169
179
|
For continuous one-dimensional distributions from raw samples, use `PDF1D`
|
|
170
180
|
(CDF plus PDF) or `CDF1D` in a data transform. `coordinates.x` owns `expr`,
|
|
171
181
|
`lim`, and `grid`; optional `repeat` computes independent batch means and
|
|
@@ -138,12 +138,22 @@ The loop `jplot man` prints is:
|
|
|
138
138
|
carry `JP-*` codes; `jplot explain JP-XXX-NNN` expands any of them.
|
|
139
139
|
5. `jplot <file>` — render, only when the figure itself is needed.
|
|
140
140
|
|
|
141
|
-
`jplot man --json` is the machine-readable manual:
|
|
141
|
+
`jplot man --json` is the machine-readable manual: a topic index, plus
|
|
142
142
|
live pages for every registered layer method and transform step
|
|
143
143
|
(`jplot man scatter`, `jplot man transform.profile`, `jplot man PDF1D`). Method contracts come from
|
|
144
144
|
the same registry `jplot cap methods` reads, so a man page cannot drift from the
|
|
145
145
|
code.
|
|
146
146
|
|
|
147
|
+
For compact legends and keys composed from real layers, use
|
|
148
|
+
`jplot man legend --json`. Declare `legend: {object, label, role}` on each drawing layer; components
|
|
149
|
+
with the same object regroup automatically using card templates such as
|
|
150
|
+
`band_line`, `line_errorbar` and `error_bounds`. The role is optional for a
|
|
151
|
+
single-component object. `frame.<axes>.legend` owns card selection, `order`,
|
|
152
|
+
`ncols`, position and spacing. JSON cards provide
|
|
153
|
+
reusable defaults, and YAML can override them. See
|
|
154
|
+
[the legend contract](docs/specs/LEGEND.md) and the
|
|
155
|
+
[self-contained example](Example/compact_legend.yaml).
|
|
156
|
+
|
|
147
157
|
For continuous one-dimensional distributions from raw samples, use `PDF1D`
|
|
148
158
|
(CDF plus PDF) or `CDF1D` in a data transform. `coordinates.x` owns `expr`,
|
|
149
159
|
`lim`, and `grid`; optional `repeat` computes independent batch means and
|
|
@@ -36,7 +36,6 @@ class StdAxesAdapter:
|
|
|
36
36
|
self._defaults = defaults or {}
|
|
37
37
|
self._clip_path = clip_path # None means no cropping
|
|
38
38
|
self.config = self._load_internal_config()
|
|
39
|
-
self._legend = False
|
|
40
39
|
self.status = "init" # lifecycle: init -> configured -> drawn -> finalized
|
|
41
40
|
self.needs_finalize = True # allow some axes (e.g., logo) to opt out
|
|
42
41
|
|
|
@@ -13,6 +13,8 @@ def apply_figure_config(fig, info: Mapping) -> bool:
|
|
|
13
13
|
fig._setup_error = None
|
|
14
14
|
|
|
15
15
|
try:
|
|
16
|
+
if "legend" in info:
|
|
17
|
+
raise ValueError("Figure-level legend is not supported; declare items on layers and overall layout under frame.<axes>.legend")
|
|
16
18
|
if "name" in info:
|
|
17
19
|
fig.name = info["name"]
|
|
18
20
|
|
|
@@ -14,6 +14,8 @@ from .method_registry import resolve_callable
|
|
|
14
14
|
from .style_runtime import resolve_style_bundle_payload
|
|
15
15
|
from .config_runtime import apply_figure_config
|
|
16
16
|
from .design_runtime import draw_design_reference
|
|
17
|
+
from .legend_runtime import apply_legend
|
|
18
|
+
from ..legend_cards import merge_axes_legend, effective_axes_legend
|
|
17
19
|
from .layer_runtime import (
|
|
18
20
|
load_layer_runtime_data as runtime_load_layer_runtime_data,
|
|
19
21
|
release_layer_runtime_data as runtime_release_layer_runtime_data,
|
|
@@ -356,15 +358,35 @@ class Figure:
|
|
|
356
358
|
|
|
357
359
|
@frame.setter
|
|
358
360
|
def frame(self, value) -> None:
|
|
361
|
+
self._legend_disabled_axes = getattr(self, "_legend_disabled_axes", set())
|
|
362
|
+
for name, node in (value or {}).items():
|
|
363
|
+
if isinstance(node, dict) and "legend" in node:
|
|
364
|
+
declared = node["legend"]
|
|
365
|
+
if declared is False or (isinstance(declared, dict) and declared.get("enabled") is False):
|
|
366
|
+
self._legend_disabled_axes.add(name)
|
|
367
|
+
else:
|
|
368
|
+
self._legend_disabled_axes.discard(name)
|
|
359
369
|
if self._frame is None:
|
|
360
370
|
self._frame = value
|
|
361
371
|
else:
|
|
372
|
+
# Legend order/roles are replacement lists, not deepmerge's
|
|
373
|
+
# default append lists. Explicit YAML also enables a disabled card
|
|
374
|
+
# default, unless enabled:false was supplied by the user.
|
|
375
|
+
value = deepcopy(value)
|
|
376
|
+
legends = {}
|
|
377
|
+
for name, node in (value or {}).items():
|
|
378
|
+
if isinstance(node, dict) and "legend" in node:
|
|
379
|
+
legends[name] = merge_axes_legend(
|
|
380
|
+
self._frame.get(name, {}).get("legend", False), node.pop("legend")
|
|
381
|
+
)
|
|
362
382
|
for _name, _node in (value or {}).items():
|
|
363
383
|
_color = _node.get("color") if isinstance(_node, dict) else None
|
|
364
384
|
if isinstance(_color, dict) and "cmap" in _color:
|
|
365
385
|
self._yaml_axc_cmaps.add(str(_name))
|
|
366
386
|
from deepmerge import always_merger
|
|
367
387
|
self._frame = always_merger.merge(self._frame, value)
|
|
388
|
+
for name, legend in legends.items():
|
|
389
|
+
self._frame.setdefault(name, {})["legend"] = legend
|
|
368
390
|
|
|
369
391
|
@property
|
|
370
392
|
def yaml_colorbar_cmaps(self) -> set:
|
|
@@ -383,6 +405,7 @@ class Figure:
|
|
|
383
405
|
raise TypeError
|
|
384
406
|
family, selected, bundle = resolve_style_bundle_payload(self.jpstyles, value)
|
|
385
407
|
self._frame = deepcopy(bundle["Frame"])
|
|
408
|
+
self._legend_disabled_axes = set()
|
|
386
409
|
self._yaml_axc_cmaps = set()
|
|
387
410
|
self._style = deepcopy(bundle["Style"])
|
|
388
411
|
self._debug_config = deepcopy(bundle.get("Debug", {}))
|
|
@@ -616,7 +639,6 @@ class Figure:
|
|
|
616
639
|
clip_path=Path(vertices, codes) # 用 path 做 clip,transform 使用 ax.transData 已在适配器里处理
|
|
617
640
|
)
|
|
618
641
|
adapter._type = 'tri'
|
|
619
|
-
adapter._legend = False
|
|
620
642
|
adapter.layers = []
|
|
621
643
|
adapter.status = 'configured'
|
|
622
644
|
self.axes["axtri"] = adapter
|
|
@@ -1075,7 +1097,6 @@ class Figure:
|
|
|
1075
1097
|
adapter = StdAxesAdapter(raw_ax)
|
|
1076
1098
|
adapter._type = "rect"
|
|
1077
1099
|
adapter.layers = []
|
|
1078
|
-
adapter._legend = self.frame['ax'].get("legend", False)
|
|
1079
1100
|
self.axes['ax'] = adapter
|
|
1080
1101
|
adapter.status = 'configured'
|
|
1081
1102
|
|
|
@@ -1185,19 +1206,13 @@ class Figure:
|
|
|
1185
1206
|
self.logger.debug("Loaded main rectangle axes -> ax")
|
|
1186
1207
|
|
|
1187
1208
|
def _apply_legend_on_axes(self, ax_name: str, ax_obj, leg_cfg: dict):
|
|
1188
|
-
"""Apply
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
kw.pop("axes", None) # per-axes legend doesn't need this
|
|
1196
|
-
try:
|
|
1197
|
-
(ax_obj.ax if hasattr(ax_obj, "ax") else ax_obj).legend(**kw)
|
|
1198
|
-
except Exception as e:
|
|
1199
|
-
if self.logger:
|
|
1200
|
-
self.logger.warning(f"Legend apply failed on '{ax_name}': {e}")
|
|
1209
|
+
"""Apply frame.<axes>.legend after all real layer handles are available."""
|
|
1210
|
+
target_ax = ax_obj.ax if hasattr(ax_obj, "ax") else ax_obj
|
|
1211
|
+
layer_specs = getattr(self, "_legend_layers", {}).get(ax_name, [])
|
|
1212
|
+
return apply_legend(
|
|
1213
|
+
target_ax, leg_cfg, getattr(self, "_legend_layer_handles", {}).get(ax_name, {}),
|
|
1214
|
+
base_dir=self._yaml_dir, layer_specs=layer_specs,
|
|
1215
|
+
)
|
|
1201
1216
|
|
|
1202
1217
|
|
|
1203
1218
|
def _install_tri_auto_clip(self, ax):
|
|
@@ -1326,10 +1341,17 @@ class Figure:
|
|
|
1326
1341
|
# determined by frame config + data — never by render order.
|
|
1327
1342
|
self._prescan_colorbar_ranges()
|
|
1328
1343
|
|
|
1344
|
+
self._legend_layer_handles = {}
|
|
1345
|
+
self._legend_layers = {}
|
|
1346
|
+
axes_names = {id(ax): name for name, ax in self.axes.items()}
|
|
1329
1347
|
for ax, ly in self._render_queue:
|
|
1330
1348
|
runtime_load_layer_runtime_data(self, ly)
|
|
1331
1349
|
try:
|
|
1332
|
-
runtime_render_layer(self, ax, ly)
|
|
1350
|
+
rendered = runtime_render_layer(self, ax, ly)
|
|
1351
|
+
name = axes_names[id(ax)]
|
|
1352
|
+
specs = self._legend_layers.setdefault(name, [])
|
|
1353
|
+
self._legend_layer_handles.setdefault(name, {})[f"@layer:{len(specs)}"] = rendered
|
|
1354
|
+
specs.append(ly.get("layer_spec", {}))
|
|
1333
1355
|
finally:
|
|
1334
1356
|
runtime_release_layer_runtime_data(self, ly)
|
|
1335
1357
|
|
|
@@ -1340,12 +1362,14 @@ class Figure:
|
|
|
1340
1362
|
|
|
1341
1363
|
for name, ax in self.axes.items():
|
|
1342
1364
|
try:
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1365
|
+
legend_config = self.frame.get(name, {}).get("legend", False)
|
|
1366
|
+
legend_config = effective_axes_legend(
|
|
1367
|
+
legend_config, self._legend_layers.get(name, []),
|
|
1368
|
+
explicitly_disabled=name in getattr(self, "_legend_disabled_axes", set()),
|
|
1369
|
+
)
|
|
1370
|
+
self._apply_legend_on_axes(name, ax, legend_config)
|
|
1346
1371
|
except Exception as e:
|
|
1347
|
-
|
|
1348
|
-
self.logger.warning(f"Legend draw failed on axes '{name}': {e}")
|
|
1372
|
+
raise ValueError(f"Legend draw failed on axes '{name}': {e}") from e
|
|
1349
1373
|
|
|
1350
1374
|
# Finalize all colorbar axes (axc and any named axc*)
|
|
1351
1375
|
for name in list(self.axes.keys()):
|
|
@@ -164,7 +164,6 @@ def ensure_rect_axes(fig, ax_name: str, kwgs: dict):
|
|
|
164
164
|
adapter = StdAxesAdapter(raw_ax)
|
|
165
165
|
adapter._type = "rect"
|
|
166
166
|
adapter.layers = []
|
|
167
|
-
adapter._legend = fig.frame.get(ax_name, {}).get("legend", False)
|
|
168
167
|
fig.axes[ax_name] = adapter
|
|
169
168
|
adapter.status = "configured"
|
|
170
169
|
|
|
@@ -309,7 +308,6 @@ def ensure_corr_axes(fig, kwgs: dict):
|
|
|
309
308
|
adapter = StdAxesAdapter(raw_ax)
|
|
310
309
|
adapter._type = "rect"
|
|
311
310
|
adapter.layers = []
|
|
312
|
-
adapter._legend = False
|
|
313
311
|
fig.axes[name] = adapter
|
|
314
312
|
adapter.status = "configured"
|
|
315
313
|
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"""Native legends with reusable spacing and keys composed from real layers."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
|
|
6
|
+
from matplotlib.legend import Legend
|
|
7
|
+
from matplotlib.legend_handler import HandlerBase, HandlerTuple
|
|
8
|
+
from matplotlib.transforms import Affine2D
|
|
9
|
+
from ..legend_cards import resolve_axes_legend
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass(frozen=True)
|
|
14
|
+
class StackedKey:
|
|
15
|
+
handles: tuple
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class HandlerStack(HandlerBase):
|
|
19
|
+
"""Place constituent handles in vertical slots inside one native key."""
|
|
20
|
+
|
|
21
|
+
def create_artists(self, legend, orig_handle, xdescent, ydescent,
|
|
22
|
+
width, height, fontsize, trans):
|
|
23
|
+
artists = []
|
|
24
|
+
slot = height / len(orig_handle.handles)
|
|
25
|
+
handler_map = legend.get_legend_handler_map()
|
|
26
|
+
for index, handle in enumerate(orig_handle.handles):
|
|
27
|
+
handler = legend.get_legend_handler(handler_map, handle)
|
|
28
|
+
# Position the whole delegated key, rather than encoding the offset
|
|
29
|
+
# in ydescent: handlers interpret descent differently (Line2D halves
|
|
30
|
+
# it), which compresses the gaps and shifts the stack off center.
|
|
31
|
+
# YAML order is top to bottom inside the original handle box.
|
|
32
|
+
# Native line handlers center at (height - ydescent) / 2.
|
|
33
|
+
# Split the descent equally so increasing handleheight does not
|
|
34
|
+
# shift a stacked center line below adjacent native line keys.
|
|
35
|
+
offset = height - (index + 1) * slot - ydescent / 2
|
|
36
|
+
slot_transform = Affine2D().translate(0, offset) + trans
|
|
37
|
+
artists.extend(handler.create_artists(
|
|
38
|
+
legend, handle, xdescent, 0,
|
|
39
|
+
width, slot, fontsize, slot_transform,
|
|
40
|
+
))
|
|
41
|
+
return artists
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def representative_handle(rendered):
|
|
45
|
+
"""Require one supported artist/container; multiple series are ambiguous."""
|
|
46
|
+
from matplotlib.artist import Artist
|
|
47
|
+
from matplotlib.container import Container
|
|
48
|
+
|
|
49
|
+
handler_map = Legend.get_default_handler_map()
|
|
50
|
+
def collect(value):
|
|
51
|
+
if isinstance(value, (Artist, Container)):
|
|
52
|
+
return [value] if Legend.get_legend_handler(handler_map, value) is not None else []
|
|
53
|
+
if isinstance(value, (list, tuple)):
|
|
54
|
+
return [handle for child in value for handle in collect(child)]
|
|
55
|
+
return []
|
|
56
|
+
|
|
57
|
+
handles = collect(rendered)
|
|
58
|
+
if len(handles) > 1:
|
|
59
|
+
raise ValueError("Layer returned multiple legend handles; split its series into separate layers with explicit legend declarations")
|
|
60
|
+
return handles[0] if handles else None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def apply_legend(ax, config, layer_handles=None, *, base_dir=None, layer_specs=None):
|
|
64
|
+
"""Apply frame.<axes>.legend without modifying config or data artists."""
|
|
65
|
+
kw, entries = resolve_axes_legend(config, layer_specs or [], base_dir=base_dir)
|
|
66
|
+
if config is False or (isinstance(config, dict) and config.get("enabled", True) is False):
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
handles, labels = [], []
|
|
70
|
+
layer_handles = layer_handles or {}
|
|
71
|
+
for entry in entries:
|
|
72
|
+
names, key = entry["layers"], entry["key"]
|
|
73
|
+
parts = []
|
|
74
|
+
for name in names:
|
|
75
|
+
if name not in layer_handles:
|
|
76
|
+
raise ValueError(f"Legend object {entry['object']!r} is missing its rendered component {name!r}")
|
|
77
|
+
handle = representative_handle(layer_handles[name])
|
|
78
|
+
if handle is None:
|
|
79
|
+
raise ValueError(f"Legend object {entry['object']!r} component {name!r} has no supported legend handle")
|
|
80
|
+
parts.append(handle)
|
|
81
|
+
if len(parts) == 1:
|
|
82
|
+
handles.append(parts[0])
|
|
83
|
+
elif key == "stack":
|
|
84
|
+
handles.append(StackedKey(tuple(parts)))
|
|
85
|
+
else:
|
|
86
|
+
handles.append(tuple(parts))
|
|
87
|
+
labels.append(entry["label"])
|
|
88
|
+
|
|
89
|
+
kw["handler_map"] = {
|
|
90
|
+
tuple: HandlerTuple(ndivide=1),
|
|
91
|
+
StackedKey: HandlerStack(),
|
|
92
|
+
**kw.get("handler_map", {}),
|
|
93
|
+
}
|
|
94
|
+
return ax.legend(handles=handles, labels=labels, **kw)
|
|
@@ -258,6 +258,12 @@ def _styles() -> list[dict[str, Any]]:
|
|
|
258
258
|
axes = frame.get("axes", {})
|
|
259
259
|
entry["usable"] = True
|
|
260
260
|
entry["axes"] = sorted(axes) if isinstance(axes, dict) else []
|
|
261
|
+
entry["legend_cards"] = {
|
|
262
|
+
name: node["legend"]["card"]
|
|
263
|
+
for name, node in frame.items()
|
|
264
|
+
if isinstance(node, dict) and isinstance(node.get("legend"), dict)
|
|
265
|
+
and "card" in node["legend"]
|
|
266
|
+
}
|
|
261
267
|
contract = card.get("Contract")
|
|
262
268
|
if isinstance(contract, dict):
|
|
263
269
|
entry["contract"] = {
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
"ax0": {
|
|
71
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
71
72
|
"ticks": {
|
|
72
73
|
"both": {
|
|
73
74
|
"labelsize": 6,
|
|
@@ -109,6 +110,7 @@
|
|
|
109
110
|
}
|
|
110
111
|
},
|
|
111
112
|
"ax1": {
|
|
113
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
112
114
|
"ticks": {
|
|
113
115
|
"both": {
|
|
114
116
|
"labelsize": 6,
|
|
@@ -162,6 +164,7 @@
|
|
|
162
164
|
]
|
|
163
165
|
},
|
|
164
166
|
"ax2": {
|
|
167
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
165
168
|
"ticks": {
|
|
166
169
|
"both": {
|
|
167
170
|
"labelsize": 6,
|
|
@@ -203,6 +206,7 @@
|
|
|
203
206
|
}
|
|
204
207
|
},
|
|
205
208
|
"ax3": {
|
|
209
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
206
210
|
"ticks": {
|
|
207
211
|
"both": {
|
|
208
212
|
"labelsize": 6,
|
|
@@ -244,6 +248,7 @@
|
|
|
244
248
|
}
|
|
245
249
|
},
|
|
246
250
|
"ax4": {
|
|
251
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
247
252
|
"ticks": {
|
|
248
253
|
"both": {
|
|
249
254
|
"labelsize": 6,
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
}
|
|
69
69
|
},
|
|
70
70
|
"ax0": {
|
|
71
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
71
72
|
"title_params": {
|
|
72
73
|
"position": "top",
|
|
73
74
|
"fontsize": "small",
|
|
@@ -132,6 +133,7 @@
|
|
|
132
133
|
}
|
|
133
134
|
},
|
|
134
135
|
"ax1": {
|
|
136
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
135
137
|
"frame": {
|
|
136
138
|
"linewidth": 0.8,
|
|
137
139
|
"solid_capstyle": "projecting",
|
|
@@ -188,6 +190,7 @@
|
|
|
188
190
|
}
|
|
189
191
|
},
|
|
190
192
|
"ax2": {
|
|
193
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
191
194
|
"frame": {
|
|
192
195
|
"linewidth": 0.8,
|
|
193
196
|
"solid_capstyle": "projecting",
|
|
@@ -244,6 +247,7 @@
|
|
|
244
247
|
}
|
|
245
248
|
},
|
|
246
249
|
"ax3": {
|
|
250
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
247
251
|
"frame": {
|
|
248
252
|
"linewidth": 0.8,
|
|
249
253
|
"solid_capstyle": "projecting",
|
|
@@ -300,6 +304,7 @@
|
|
|
300
304
|
}
|
|
301
305
|
},
|
|
302
306
|
"ax4": {
|
|
307
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
303
308
|
"frame": {
|
|
304
309
|
"linewidth": 0.8,
|
|
305
310
|
"solid_capstyle": "projecting",
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
}
|
|
62
62
|
},
|
|
63
63
|
"ax": {
|
|
64
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
64
65
|
"title_params": {
|
|
65
66
|
"position": "top",
|
|
66
67
|
"fontsize": "small",
|
|
@@ -132,6 +133,7 @@
|
|
|
132
133
|
}
|
|
133
134
|
},
|
|
134
135
|
"axl": {
|
|
136
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
135
137
|
"title_params": {
|
|
136
138
|
"position": "top",
|
|
137
139
|
"fontsize": "small",
|
|
@@ -207,6 +209,7 @@
|
|
|
207
209
|
}
|
|
208
210
|
},
|
|
209
211
|
"axb": {
|
|
212
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
210
213
|
"title_params": {
|
|
211
214
|
"position": "top",
|
|
212
215
|
"fontsize": "small",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
46
|
"ax": {
|
|
47
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
47
48
|
"title_params": {
|
|
48
49
|
"position": "top",
|
|
49
50
|
"fontsize": "small",
|
|
@@ -112,6 +113,7 @@
|
|
|
112
113
|
}
|
|
113
114
|
},
|
|
114
115
|
"axr": {
|
|
116
|
+
"legend": {"enabled": false, "card": "compact"},
|
|
115
117
|
"title_params": {
|
|
116
118
|
"position": "top",
|
|
117
119
|
"fontsize": "small",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"title": "Compact",
|
|
4
|
+
"extends": "default",
|
|
5
|
+
"legend": {
|
|
6
|
+
"frameon": false,
|
|
7
|
+
"borderpad": 0.25,
|
|
8
|
+
"labelspacing": 0.25,
|
|
9
|
+
"handlelength": 1.6,
|
|
10
|
+
"handleheight": 0.7,
|
|
11
|
+
"handletextpad": 0.5,
|
|
12
|
+
"columnspacing": 1.0,
|
|
13
|
+
"borderaxespad": 0.4
|
|
14
|
+
}
|
|
15
|
+
}
|