jarvisplot 2.0.4__tar.gz → 2.0.6__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.0.4 → jarvisplot-2.0.6}/JarvisPLOT.egg-info/PKG-INFO +1 -1
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/JarvisPLOT.egg-info/SOURCES.txt +10 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/PKG-INFO +1 -1
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/colorbar_runtime.py +81 -3
- jarvisplot-2.0.6/jarvisplot/Figure/debug_config.py +466 -0
- jarvisplot-2.0.6/jarvisplot/Figure/design_runtime.py +637 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/figure.py +100 -15
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/layout_runtime.py +84 -12
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/method_registry.py +1 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/capabilities.py +4 -0
- jarvisplot-2.0.6/jarvisplot/cards/a4paper/1x1/ternary.json +298 -0
- jarvisplot-2.0.6/jarvisplot/cards/a4paper/2x1/dynesty_runplot.json +686 -0
- jarvisplot-2.0.6/jarvisplot/cards/a4paper/2x1/rect.json +435 -0
- jarvisplot-2.0.6/jarvisplot/cards/a4paper/2x1/rect5x1.json +687 -0
- jarvisplot-2.0.6/jarvisplot/cards/a4paper/2x1/rect_cmap.json +495 -0
- jarvisplot-2.0.6/jarvisplot/cards/a4paper/2x1/rect_marginal.json +660 -0
- jarvisplot-2.0.6/jarvisplot/cards/a4paper/2x1/rectratio.json +511 -0
- jarvisplot-2.0.6/jarvisplot/cards/a4paper/2x1/ternary.json +462 -0
- jarvisplot-2.0.6/jarvisplot/cards/a4paper/2x1/ternary_cmap.json +517 -0
- jarvisplot-2.0.6/jarvisplot/cards/a4paper/4x1/rect_cmap.json +480 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/a4paper/4x1/ternary_cmap.json +3 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/colors/colormaps.json +13 -0
- jarvisplot-2.0.6/jarvisplot/cards/gambit/1x1/ternary.json +298 -0
- jarvisplot-2.0.6/jarvisplot/cards/gambit/2x1/rect_cmap.json +506 -0
- jarvisplot-2.0.6/jarvisplot/cards/gambit/2x1/ternary.json +476 -0
- jarvisplot-2.0.6/jarvisplot/cards/gambit/2x1/ternary_cmap.json +533 -0
- jarvisplot-2.0.6/jarvisplot/cards/icons/JarvisHEP.png +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/style_preference.json +3 -1
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/column_demand.py +6 -8
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/data_access.py +2 -3
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/expr_names.py +28 -1
- jarvisplot-2.0.6/jarvisplot/manual_cards/debug-overlay.yaml +65 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/manifest.yaml +5 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/method_notes.yaml +12 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/style-axes.yaml +2 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/method_contracts.py +1 -0
- jarvisplot-2.0.6/jarvisplot/schema/core/figure.json +230 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/core/layer.json +1 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/manifest.json +2 -0
- jarvisplot-2.0.6/jarvisplot/schema/methods/hist2d.json +37 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/pyproject.toml +1 -1
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_axis_title.py +111 -0
- jarvisplot-2.0.6/tests/test_card_debug_shape.py +75 -0
- jarvisplot-2.0.6/tests/test_debug_config.py +147 -0
- jarvisplot-2.0.6/tests/test_debug_switches.py +180 -0
- jarvisplot-2.0.6/tests/test_debug_yaml_override.py +147 -0
- jarvisplot-2.0.6/tests/test_design_runtime.py +227 -0
- jarvisplot-2.0.6/tests/test_ternary_debug.py +151 -0
- jarvisplot-2.0.4/jarvisplot/Figure/design_runtime.py +0 -342
- jarvisplot-2.0.4/jarvisplot/cards/a4paper/1x1/ternary.json +0 -6
- jarvisplot-2.0.4/jarvisplot/cards/a4paper/2x1/dynesty_runplot.json +0 -165
- jarvisplot-2.0.4/jarvisplot/cards/a4paper/2x1/rect.json +0 -143
- jarvisplot-2.0.4/jarvisplot/cards/a4paper/2x1/rect5x1.json +0 -352
- jarvisplot-2.0.4/jarvisplot/cards/a4paper/2x1/rect_cmap.json +0 -189
- jarvisplot-2.0.4/jarvisplot/cards/a4paper/2x1/ternary.json +0 -142
- jarvisplot-2.0.4/jarvisplot/cards/a4paper/2x1/ternary_cmap.json +0 -189
- jarvisplot-2.0.4/jarvisplot/cards/a4paper/4x1/rect_cmap.json +0 -174
- jarvisplot-2.0.4/jarvisplot/cards/gambit/1x1/ternary.json +0 -6
- jarvisplot-2.0.4/jarvisplot/cards/gambit/2x1/rect_cmap.json +0 -200
- jarvisplot-2.0.4/jarvisplot/cards/gambit/2x1/ternary.json +0 -156
- jarvisplot-2.0.4/jarvisplot/cards/gambit/2x1/ternary_cmap.json +0 -205
- jarvisplot-2.0.4/jarvisplot/cards/icons/flowchart/JarvisHEP.png +0 -0
- jarvisplot-2.0.4/jarvisplot/schema/core/figure.json +0 -127
- jarvisplot-2.0.4/tests/test_design_runtime.py +0 -85
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/JarvisPLOT.egg-info/dependency_links.txt +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/JarvisPLOT.egg-info/entry_points.txt +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/JarvisPLOT.egg-info/requires.txt +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/JarvisPLOT.egg-info/top_level.txt +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/README.md +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/__init__.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/adapters_rect.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/adapters_ternary.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/cards/std_axes_adapter_config.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/config_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/data_pipelines.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/density_cell_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/dynesty_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/figure_types.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/helper.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/interp_2d_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/interp_natural_neighbor.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/interp_natural_neighbor_exact.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/layer_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/posterior_density_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/posterior_hpd.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/posterior_mesh.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/preprocessor.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/preprocessor_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/profile_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/Figure/style_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/__init__.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/agent_digest.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/agent_io.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cache_store.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/a4paper/4x1/rect.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/a4paper/4x1/ternary.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/args.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/default/output.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/flowchart/default.json +0 -0
- {jarvisplot-2.0.4/jarvisplot/cards/icons → jarvisplot-2.0.6/jarvisplot/cards/icons/flowchart}/JarvisHEP.png +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/icons/flowchart/calculator.png +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/icons/flowchart/inputfile.png +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/icons/flowchart/opera.png +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/icons/flowchart/outputfile.png +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/icons/flowchart/sampler.png +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/icons/gambit.png +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cards/icons/gambit_small.png +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cli.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/cli_help.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/client.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/column_probe.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/config.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/config_address.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/core.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/core_assets.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/core_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/data_loader.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/data_loader_hdf5.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/data_loader_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/data_loader_summary.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/diagnostic_guidance.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/diagnostics.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/dryrun_runtime.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/fix_apply.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/flowchart.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/inner_func.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/man_catalog.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/man_methods.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/man_render_agent.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/man_render_human.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/man_transforms.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/agent-output.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/cli-map.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/data-columns.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/diagnostics.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/dryrun-viz.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/layer-method.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/type-posterior-2d.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/type-profile-2d.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/validate.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/workflow.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/manual_cards/yaml-root.yaml +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/memtrace.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/render_health.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/core/common.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/core/dataset.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/core/transform.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/bar.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/barh.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/contour.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/contourf.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/dynesty_runplot.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/errorbar.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/fill.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/fill_between.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/fill_betweenx.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/hist.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/imshow.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/jpcontour.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/jpcontourf.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/jpfield.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/pcolor.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/pcolormesh.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/plot.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/quiver.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/scatter.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/step.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/tricontour.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/tricontourf.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/tripcolor.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/tripcolor_axes.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/triplot.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/voronoi.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/methods/voronoif.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema/plot-config.json +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema_catalog.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/schema_diagnostics.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/templates_catalog.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/transform_contracts.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/utils/__init__.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/utils/cmaps.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/utils/dataframes.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/utils/expression.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/utils/interpolator.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/utils/pathing.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/validation.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/__init__.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/cap.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/config_cmd.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/data.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/doctor.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/dryrun.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/explain.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/man.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/suggest.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/template.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/verbs/validate.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/jarvisplot/yaml_io.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/setup.cfg +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_agent_digest.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_agent_envelope.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_capabilities.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_cli_help.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_cli_verbs.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_cmaps.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_column_existence.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_config_addressing.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_config_edit.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_config_expand.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_data_access.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_data_describe.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_data_head_eval.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_data_loader_contracts.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_data_pipelines.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_density_cell_transform.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_diagnostic_guidance.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_docs_status_labels.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_doctor_partial.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_explain.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_figure_contracts.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_figure_type_expander.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_fix_application.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_flowchart_renderer.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_interp_2d_transform.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_interp_natural_neighbor.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_interpolator_contracts.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_jpcontour_methods.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_man_cli.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_method_contracts.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_parse_data_metadata.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_pathing_contracts.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_posterior_hpd.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_render_health.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_row_ledger.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_schema_catalog.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_suggest.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_suggest_axes.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_template_catalog.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_template_json.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_transform_contracts.py +0 -0
- {jarvisplot-2.0.4 → jarvisplot-2.0.6}/tests/test_validate_no_matplotlib.py +0 -0
|
@@ -53,6 +53,7 @@ jarvisplot/Figure/adapters_ternary.py
|
|
|
53
53
|
jarvisplot/Figure/colorbar_runtime.py
|
|
54
54
|
jarvisplot/Figure/config_runtime.py
|
|
55
55
|
jarvisplot/Figure/data_pipelines.py
|
|
56
|
+
jarvisplot/Figure/debug_config.py
|
|
56
57
|
jarvisplot/Figure/density_cell_runtime.py
|
|
57
58
|
jarvisplot/Figure/design_runtime.py
|
|
58
59
|
jarvisplot/Figure/dynesty_runtime.py
|
|
@@ -80,6 +81,8 @@ jarvisplot/cards/a4paper/2x1/dynesty_runplot.json
|
|
|
80
81
|
jarvisplot/cards/a4paper/2x1/rect.json
|
|
81
82
|
jarvisplot/cards/a4paper/2x1/rect5x1.json
|
|
82
83
|
jarvisplot/cards/a4paper/2x1/rect_cmap.json
|
|
84
|
+
jarvisplot/cards/a4paper/2x1/rect_marginal.json
|
|
85
|
+
jarvisplot/cards/a4paper/2x1/rectratio.json
|
|
83
86
|
jarvisplot/cards/a4paper/2x1/ternary.json
|
|
84
87
|
jarvisplot/cards/a4paper/2x1/ternary_cmap.json
|
|
85
88
|
jarvisplot/cards/a4paper/4x1/rect.json
|
|
@@ -105,6 +108,7 @@ jarvisplot/cards/icons/flowchart/sampler.png
|
|
|
105
108
|
jarvisplot/manual_cards/agent-output.yaml
|
|
106
109
|
jarvisplot/manual_cards/cli-map.yaml
|
|
107
110
|
jarvisplot/manual_cards/data-columns.yaml
|
|
111
|
+
jarvisplot/manual_cards/debug-overlay.yaml
|
|
108
112
|
jarvisplot/manual_cards/diagnostics.yaml
|
|
109
113
|
jarvisplot/manual_cards/dryrun-viz.yaml
|
|
110
114
|
jarvisplot/manual_cards/layer-method.yaml
|
|
@@ -133,6 +137,7 @@ jarvisplot/schema/methods/fill.json
|
|
|
133
137
|
jarvisplot/schema/methods/fill_between.json
|
|
134
138
|
jarvisplot/schema/methods/fill_betweenx.json
|
|
135
139
|
jarvisplot/schema/methods/hist.json
|
|
140
|
+
jarvisplot/schema/methods/hist2d.json
|
|
136
141
|
jarvisplot/schema/methods/imshow.json
|
|
137
142
|
jarvisplot/schema/methods/jpcontour.json
|
|
138
143
|
jarvisplot/schema/methods/jpcontourf.json
|
|
@@ -171,6 +176,7 @@ tests/test_agent_digest.py
|
|
|
171
176
|
tests/test_agent_envelope.py
|
|
172
177
|
tests/test_axis_title.py
|
|
173
178
|
tests/test_capabilities.py
|
|
179
|
+
tests/test_card_debug_shape.py
|
|
174
180
|
tests/test_cli_help.py
|
|
175
181
|
tests/test_cli_verbs.py
|
|
176
182
|
tests/test_cmaps.py
|
|
@@ -183,6 +189,9 @@ tests/test_data_describe.py
|
|
|
183
189
|
tests/test_data_head_eval.py
|
|
184
190
|
tests/test_data_loader_contracts.py
|
|
185
191
|
tests/test_data_pipelines.py
|
|
192
|
+
tests/test_debug_config.py
|
|
193
|
+
tests/test_debug_switches.py
|
|
194
|
+
tests/test_debug_yaml_override.py
|
|
186
195
|
tests/test_density_cell_transform.py
|
|
187
196
|
tests/test_design_runtime.py
|
|
188
197
|
tests/test_diagnostic_guidance.py
|
|
@@ -209,5 +218,6 @@ tests/test_suggest.py
|
|
|
209
218
|
tests/test_suggest_axes.py
|
|
210
219
|
tests/test_template_catalog.py
|
|
211
220
|
tests/test_template_json.py
|
|
221
|
+
tests/test_ternary_debug.py
|
|
212
222
|
tests/test_transform_contracts.py
|
|
213
223
|
tests/test_validate_no_matplotlib.py
|
|
@@ -56,6 +56,20 @@ def axc_color_config(frame: Mapping[str, Any], cb_name: str = "axc") -> dict:
|
|
|
56
56
|
return out
|
|
57
57
|
|
|
58
58
|
|
|
59
|
+
def layer_cmap_wins(fig, cb_name: str, color_cfg: Mapping[str, Any]) -> bool:
|
|
60
|
+
"""Whether a layer's own ``cmap`` may override ``frame[cb_name].color.cmap``.
|
|
61
|
+
|
|
62
|
+
A cmap that reached the frame from the **style card** is a preset: the
|
|
63
|
+
card says what this colorbar normally looks like, and a layer naming its
|
|
64
|
+
own is the more specific statement, so the layer wins. A cmap written in
|
|
65
|
+
the **project YAML** is the author talking about this one figure, so it
|
|
66
|
+
wins instead. Same defaults < card < YAML order the Debug block uses.
|
|
67
|
+
"""
|
|
68
|
+
if color_cfg.get("cmap") is None:
|
|
69
|
+
return True
|
|
70
|
+
return str(cb_name) not in (getattr(fig, "yaml_colorbar_cmaps", None) or set())
|
|
71
|
+
|
|
72
|
+
|
|
59
73
|
# ---------------------------------------------------------------------------
|
|
60
74
|
# Scalar helpers
|
|
61
75
|
# ---------------------------------------------------------------------------
|
|
@@ -151,6 +165,55 @@ _CONTOUR_LIKE_METHODS = frozenset({
|
|
|
151
165
|
"jpcontour", "jpcontourf",
|
|
152
166
|
})
|
|
153
167
|
|
|
168
|
+
#: Methods that bin their own data: the colour channel is the bin content, so
|
|
169
|
+
#: there is no ``z`` column for the pre-scan to read. It has to run the same
|
|
170
|
+
#: binning matplotlib will run.
|
|
171
|
+
_BINNED_COLOR_METHODS = frozenset({"hist2d"})
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
def _hist2d_bin_values(df, coor: dict, style: dict):
|
|
175
|
+
"""Reproduce the bin contents ``Axes.hist2d`` will colour.
|
|
176
|
+
|
|
177
|
+
``Axes.hist2d`` is ``np.histogram2d`` followed by ``pcolormesh``, so the
|
|
178
|
+
same call with the same ``bins`` / ``range`` / ``density`` / ``weights``
|
|
179
|
+
gives the pre-scan the colour range without drawing anything.
|
|
180
|
+
"""
|
|
181
|
+
if df is None:
|
|
182
|
+
return None
|
|
183
|
+
|
|
184
|
+
def _channel(key):
|
|
185
|
+
src = coor.get(key)
|
|
186
|
+
if isinstance(src, dict) and "expr" in src:
|
|
187
|
+
return eval_dataframe_expression(df, src["expr"], logger=None)
|
|
188
|
+
if src is None:
|
|
189
|
+
src = style.get(key)
|
|
190
|
+
if src is None or isinstance(src, str):
|
|
191
|
+
return None
|
|
192
|
+
return np.asarray(src, dtype=float)
|
|
193
|
+
|
|
194
|
+
x = _channel("x")
|
|
195
|
+
y = _channel("y")
|
|
196
|
+
if x is None or y is None:
|
|
197
|
+
return None
|
|
198
|
+
|
|
199
|
+
values, _, _ = np.histogram2d(
|
|
200
|
+
np.asarray(x, dtype=float),
|
|
201
|
+
np.asarray(y, dtype=float),
|
|
202
|
+
bins=style.get("bins", 10),
|
|
203
|
+
range=style.get("range"),
|
|
204
|
+
density=bool(style.get("density", False)),
|
|
205
|
+
weights=_channel("weights"),
|
|
206
|
+
)
|
|
207
|
+
# `cmin` / `cmax` blank a bin out entirely; a blanked bin must not drag the
|
|
208
|
+
# colorbar range with it.
|
|
209
|
+
cmin = style.get("cmin")
|
|
210
|
+
cmax = style.get("cmax")
|
|
211
|
+
if cmin is not None:
|
|
212
|
+
values = values[values >= float(cmin)]
|
|
213
|
+
if cmax is not None:
|
|
214
|
+
values = values[values <= float(cmax)]
|
|
215
|
+
return values
|
|
216
|
+
|
|
154
217
|
|
|
155
218
|
def layer_uses_color(style: dict, coor: dict, method_key: str) -> bool:
|
|
156
219
|
"""Return True if this layer will need a colorbar."""
|
|
@@ -169,16 +232,30 @@ def layer_uses_color(style: dict, coor: dict, method_key: str) -> bool:
|
|
|
169
232
|
if method_key in _COLORED_Z_METHODS and _is_numeric_color_source(style_z):
|
|
170
233
|
return True
|
|
171
234
|
|
|
235
|
+
# A self-binning method always has a colour channel -- its own bin contents.
|
|
236
|
+
if method_key in _BINNED_COLOR_METHODS:
|
|
237
|
+
return True
|
|
238
|
+
|
|
172
239
|
return False
|
|
173
240
|
|
|
174
241
|
|
|
175
|
-
def collect_layer_color_range(
|
|
242
|
+
def collect_layer_color_range(
|
|
243
|
+
df, coor: dict, style: dict, *, scale: str | None = None, method_key: str | None = None
|
|
244
|
+
):
|
|
176
245
|
"""Extract (data_min, data_max) for the colour channel of a single layer.
|
|
177
246
|
|
|
178
247
|
Returns (None, None) when no finite data is available.
|
|
179
248
|
"""
|
|
180
249
|
arr = None
|
|
181
|
-
if
|
|
250
|
+
if str(method_key or "").strip().lower() in _BINNED_COLOR_METHODS:
|
|
251
|
+
try:
|
|
252
|
+
arr = _hist2d_bin_values(df, coor, style)
|
|
253
|
+
except Exception:
|
|
254
|
+
# A malformed bins/range only stops the colorbar from being
|
|
255
|
+
# pre-sized. Let the real draw call raise it, where the error
|
|
256
|
+
# names the layer instead of surfacing out of the pre-scan.
|
|
257
|
+
arr = None
|
|
258
|
+
elif isinstance(coor.get("z"), dict) and "expr" in coor["z"]:
|
|
182
259
|
arr = eval_dataframe_expression(df, coor["z"]["expr"], logger=None)
|
|
183
260
|
elif isinstance(coor.get("c"), dict) and "expr" in coor["c"]:
|
|
184
261
|
arr = eval_dataframe_expression(df, coor["c"]["expr"], logger=None)
|
|
@@ -394,13 +471,14 @@ def collect_and_attach_colorbar(
|
|
|
394
471
|
if not axc._cb.get("used"):
|
|
395
472
|
frame = getattr(fig, "frame", {})
|
|
396
473
|
color_cfg = axc_color_config(frame, cb_name)
|
|
397
|
-
if
|
|
474
|
+
if style.get("cmap") is not None and layer_cmap_wins(fig, cb_name, color_cfg):
|
|
398
475
|
color_cfg["cmap"] = style.get("cmap")
|
|
399
476
|
data_range = collect_layer_color_range(
|
|
400
477
|
df,
|
|
401
478
|
coor,
|
|
402
479
|
style,
|
|
403
480
|
scale=color_cfg.get("scale"),
|
|
481
|
+
method_key=method_key,
|
|
404
482
|
)
|
|
405
483
|
if data_range != (None, None):
|
|
406
484
|
axc._cb.update(
|
|
@@ -0,0 +1,466 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""Defaults and merge rules for the design-reference debug overlay.
|
|
4
|
+
|
|
5
|
+
Split out of :mod:`design_runtime` so the configuration surface has one owner
|
|
6
|
+
and can be tested without importing matplotlib. The drawing code reads only
|
|
7
|
+
what this module hands it -- there are no literals below the unpack.
|
|
8
|
+
|
|
9
|
+
**Every appearance value lives in a block named after the matplotlib callable
|
|
10
|
+
that consumes it, and is splatted straight into that call:**
|
|
11
|
+
|
|
12
|
+
.. code-block:: python
|
|
13
|
+
|
|
14
|
+
ov.plot(xs, ys, **cfg["cap"]["plot"])
|
|
15
|
+
ov.add_patch(mpl.patches.Rectangle((l, b), w, h, **cfg["outline"]["framed"]["Rectangle"]))
|
|
16
|
+
|
|
17
|
+
So a block's keys are matplotlib's vocabulary, not Jarvis-PLOT's, and one
|
|
18
|
+
drawn thing owns one complete kwargs table -- no shared palette to chase, no
|
|
19
|
+
partial style merged with hidden Python defaults. What stays outside those
|
|
20
|
+
blocks is geometry: positions, spans, thresholds and the autoscale constants
|
|
21
|
+
that Python computes with before it draws.
|
|
22
|
+
|
|
23
|
+
Precedence, lowest to highest:
|
|
24
|
+
|
|
25
|
+
1. :data:`DEFAULT_DEBUG` -- ships with the package, always present.
|
|
26
|
+
2. A style card's root ``Debug`` block (``jarvisplot/cards/**/*.json``).
|
|
27
|
+
3. A YAML ``Figures[].debug`` mapping, for one figure only.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
from __future__ import annotations
|
|
31
|
+
|
|
32
|
+
from copy import deepcopy
|
|
33
|
+
from typing import Mapping
|
|
34
|
+
|
|
35
|
+
from ..diagnostics import did_you_mean
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
"CALL_BLOCKS",
|
|
39
|
+
"DEFAULT_DEBUG",
|
|
40
|
+
"deep_update",
|
|
41
|
+
"merge_debug_config",
|
|
42
|
+
"resolve_debug_config",
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# Colours are written out in full inside every call block below; these names
|
|
47
|
+
# exist only to keep that table readable and to make the roles obvious. They
|
|
48
|
+
# are not a runtime indirection -- a card overrides the block, not a palette.
|
|
49
|
+
_DIM = "#1F21E9" # dimension lines, arrowheads and their labels
|
|
50
|
+
_BOX = "#111111" # outline of a framed axes
|
|
51
|
+
_MARGIN = "#FF3FA4" # figure border, caption, frameless-axes outline
|
|
52
|
+
_NAME = "#1A237E" # text inside the axes-layout panel
|
|
53
|
+
_PANEL = "#FFEC73" # the panel's own background
|
|
54
|
+
_TERNARY = "#FF42A1" # ternary tick anchors and label leaders
|
|
55
|
+
|
|
56
|
+
# The overlay sits above every real artist; text above its own artists.
|
|
57
|
+
_Z_OVERLAY, _Z_ARTIST, _Z_TEXT = 10000, 10001, 10002
|
|
58
|
+
|
|
59
|
+
# Background box shared by the dimension labels and the caption. Written into
|
|
60
|
+
# each ``text`` block in full; the alpha differs between them.
|
|
61
|
+
_LABEL_BBOX = {"boxstyle": "square,pad=0.12", "fc": "white", "ec": "none"}
|
|
62
|
+
|
|
63
|
+
# Typography shared by the dimension labels, likewise written out in full.
|
|
64
|
+
_LABEL_FONT = {
|
|
65
|
+
"fontsize": 5.0,
|
|
66
|
+
"fontweight": "normal",
|
|
67
|
+
"family": "monospace",
|
|
68
|
+
"clip_on": False,
|
|
69
|
+
"zorder": _Z_TEXT,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
DEFAULT_DEBUG = {
|
|
74
|
+
# Which axes gets fully dimensioned and hosts the info panel. First match wins.
|
|
75
|
+
"primary_order": ["ax", "ax0", "ax1", "axtri"],
|
|
76
|
+
"units": {"cm_per_inch": 2.54, "pt_per_inch": 72.0},
|
|
77
|
+
# The transparent full-figure axes every annotation is drawn onto.
|
|
78
|
+
"overlay": {"add_axes": {"zorder": _Z_OVERLAY}},
|
|
79
|
+
"figure": {
|
|
80
|
+
"border": {
|
|
81
|
+
"show": True,
|
|
82
|
+
"Rectangle": {"fill": False, "ec": _MARGIN, "lw": 0.9, "zorder": _Z_ARTIST},
|
|
83
|
+
},
|
|
84
|
+
"caption": {
|
|
85
|
+
"show": True,
|
|
86
|
+
"x": 0.5,
|
|
87
|
+
"y": 0.995,
|
|
88
|
+
"template": "design reference · figure %.2f cm × %.2f cm",
|
|
89
|
+
"text": {
|
|
90
|
+
"color": _MARGIN,
|
|
91
|
+
"fontsize": 6.0,
|
|
92
|
+
"ha": "center",
|
|
93
|
+
"va": "top",
|
|
94
|
+
"rotation": 0,
|
|
95
|
+
"fontweight": "bold",
|
|
96
|
+
"family": "DejaVu Sans",
|
|
97
|
+
"clip_on": False,
|
|
98
|
+
"zorder": _Z_TEXT,
|
|
99
|
+
"bbox": {**_LABEL_BBOX, "alpha": 0.82},
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
# Drawn through the shared dimension machinery, so it has no call block
|
|
103
|
+
# of its own -- only where it sits and how its number reads.
|
|
104
|
+
"height_marker": {"show": True, "x": 0.035, "template": "%.2f cm"},
|
|
105
|
+
},
|
|
106
|
+
"axes": {
|
|
107
|
+
"frameless_extension_max": 0.018,
|
|
108
|
+
"frameless_extension_min": 0.006,
|
|
109
|
+
"frameless_extension_factor": 0.09,
|
|
110
|
+
"outline": {
|
|
111
|
+
"show": True,
|
|
112
|
+
# A framed axes keeps the neutral reference outline; a frameless
|
|
113
|
+
# one (axlogo, say) is marked as a design box instead.
|
|
114
|
+
"framed": {
|
|
115
|
+
"Rectangle": {"fill": False, "ec": _BOX, "lw": 0.45, "zorder": _Z_ARTIST},
|
|
116
|
+
},
|
|
117
|
+
"frameless": {
|
|
118
|
+
"Rectangle": {"fill": False, "ec": _MARGIN, "lw": 0.45, "zorder": _Z_ARTIST},
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
# Hash marks past the corners, drawn for frameless axes only.
|
|
122
|
+
"corner_ticks": {
|
|
123
|
+
"show": True,
|
|
124
|
+
"plot": {
|
|
125
|
+
"color": _MARGIN,
|
|
126
|
+
"lw": 0.45,
|
|
127
|
+
"solid_capstyle": "projecting",
|
|
128
|
+
"clip_on": False,
|
|
129
|
+
"zorder": _Z_ARTIST,
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
# One dimension line: two terminal cap bars, an arrow, and a label. Every
|
|
134
|
+
# measured distance in the overlay is drawn with these four calls.
|
|
135
|
+
"dimension": {
|
|
136
|
+
"cap_half_pt": 5.0,
|
|
137
|
+
"narrow_threshold_pt": 24.0,
|
|
138
|
+
"narrow_length_pt": 8.0,
|
|
139
|
+
"narrow_scale_factor": 0.45,
|
|
140
|
+
"narrow_scale_min": 3.0,
|
|
141
|
+
"narrow_scale_max": 6.0,
|
|
142
|
+
"label_gap": 0.008,
|
|
143
|
+
"corner_gap": 0.018,
|
|
144
|
+
"colorbar_line_offset": 0.024,
|
|
145
|
+
"cap": {
|
|
146
|
+
"plot": {
|
|
147
|
+
"color": _DIM,
|
|
148
|
+
"lw": 0.7,
|
|
149
|
+
"solid_capstyle": "projecting",
|
|
150
|
+
"clip_on": False,
|
|
151
|
+
"zorder": _Z_ARTIST,
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
# Short gaps get two inward-pointing arrows whose tails extend outside
|
|
155
|
+
# the interval; ``mutation_scale`` is computed from the span, between
|
|
156
|
+
# ``narrow_scale_min`` and ``narrow_scale_max``.
|
|
157
|
+
"narrow_arrow": {
|
|
158
|
+
"annotate": {
|
|
159
|
+
"zorder": _Z_ARTIST,
|
|
160
|
+
"arrowprops": {
|
|
161
|
+
"arrowstyle": "-|>",
|
|
162
|
+
"shrinkA": 0,
|
|
163
|
+
"shrinkB": 0,
|
|
164
|
+
"color": _DIM,
|
|
165
|
+
"lw": 0.7,
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
"wide_arrow": {
|
|
170
|
+
"annotate": {
|
|
171
|
+
"zorder": _Z_ARTIST,
|
|
172
|
+
"arrowprops": {
|
|
173
|
+
"arrowstyle": "<|-|>",
|
|
174
|
+
"shrinkA": 0,
|
|
175
|
+
"shrinkB": 0,
|
|
176
|
+
"color": _DIM,
|
|
177
|
+
"lw": 0.7,
|
|
178
|
+
"mutation_scale": 6.0,
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
},
|
|
182
|
+
"hlabel": {
|
|
183
|
+
"text": {
|
|
184
|
+
**_LABEL_FONT,
|
|
185
|
+
"color": _DIM,
|
|
186
|
+
"ha": "center",
|
|
187
|
+
"va": "top",
|
|
188
|
+
"rotation": 0,
|
|
189
|
+
"bbox": {**_LABEL_BBOX, "alpha": 0.5},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
"vlabel_left": {
|
|
193
|
+
"text": {
|
|
194
|
+
**_LABEL_FONT,
|
|
195
|
+
"color": _DIM,
|
|
196
|
+
"ha": "right",
|
|
197
|
+
"va": "center",
|
|
198
|
+
"rotation": 90,
|
|
199
|
+
"bbox": {**_LABEL_BBOX, "alpha": 0.5},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
"vlabel_right": {
|
|
203
|
+
"text": {
|
|
204
|
+
**_LABEL_FONT,
|
|
205
|
+
"color": _DIM,
|
|
206
|
+
"ha": "left",
|
|
207
|
+
"va": "center",
|
|
208
|
+
"rotation": 90,
|
|
209
|
+
"bbox": {**_LABEL_BBOX, "alpha": 0.5},
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
"numbered_axes": {
|
|
214
|
+
"show": True,
|
|
215
|
+
"right_edge": 1.0,
|
|
216
|
+
"marker_step": 0.040,
|
|
217
|
+
"label_side": "left",
|
|
218
|
+
"template": "%.3f cm",
|
|
219
|
+
"top": {"show": True},
|
|
220
|
+
"bottom": {"show": True},
|
|
221
|
+
},
|
|
222
|
+
# Primary-axes margin dimensions. The top/bottom pair rides the primary
|
|
223
|
+
# axes' right border -- just inside it, mirroring where ``left`` sits --
|
|
224
|
+
# so it tracks the axes it measures and leaves the layout panel the whole
|
|
225
|
+
# left side. ``left`` measures along the top edge and keeps its own place.
|
|
226
|
+
"margins": {
|
|
227
|
+
"template": "%.3f cm",
|
|
228
|
+
"label_side": "right",
|
|
229
|
+
# Axes that get no margin dimensions at all. A logo plate is placed by
|
|
230
|
+
# eye in a corner, not designed against the page edges, so measuring it
|
|
231
|
+
# only adds a column that collides with the ones that matter.
|
|
232
|
+
"exclude": ["axlogo"],
|
|
233
|
+
# Axes that end at the same x would draw on top of each other, so each
|
|
234
|
+
# one after the first steps this far further inside the border.
|
|
235
|
+
"marker_step": 0.040,
|
|
236
|
+
"left": {"show": True},
|
|
237
|
+
"top": {"show": True},
|
|
238
|
+
"bottom": {"show": True},
|
|
239
|
+
},
|
|
240
|
+
"colorbar_gap": {"show": True, "template": "%.3f cm"},
|
|
241
|
+
# A layout reference has no layers, so nothing feeds the colorbar and it
|
|
242
|
+
# stays an empty box -- the one part of the page the reference cannot
|
|
243
|
+
# show. Fill it with the card's own colormap. A colorbar a layer did
|
|
244
|
+
# feed is a real result and is left alone.
|
|
245
|
+
"colorbar_preview": {
|
|
246
|
+
"show": True,
|
|
247
|
+
"samples": 256,
|
|
248
|
+
"fallback_cmap": "viridis",
|
|
249
|
+
"imshow": {
|
|
250
|
+
"aspect": "auto",
|
|
251
|
+
"interpolation": "bilinear",
|
|
252
|
+
"origin": "lower",
|
|
253
|
+
"zorder": 1,
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
# The layout panel. One type scale for every figure: the box is sized to
|
|
257
|
+
# its content and may run past the axes, rather than shrinking its text to
|
|
258
|
+
# fit a short axes and printing the same numbers at a different size on
|
|
259
|
+
# every card.
|
|
260
|
+
"panel": {
|
|
261
|
+
"show": True,
|
|
262
|
+
"pad_x_max": 0.018,
|
|
263
|
+
"pad_x_min": 0.004,
|
|
264
|
+
"pad_x_factor": 0.025,
|
|
265
|
+
"pad_y_max": 0.018,
|
|
266
|
+
"pad_y_min": 0.004,
|
|
267
|
+
"pad_y_factor": 0.035,
|
|
268
|
+
"entry_gap": 5.0,
|
|
269
|
+
"char_width_factor": 0.62,
|
|
270
|
+
"detail_lines_per_entry": 2.0,
|
|
271
|
+
"text_inset_x": 0.008,
|
|
272
|
+
"text_inset_y": 0.006,
|
|
273
|
+
"box": {
|
|
274
|
+
"FancyBboxPatch": {
|
|
275
|
+
"boxstyle": "round,pad=0.004",
|
|
276
|
+
"facecolor": _PANEL,
|
|
277
|
+
"alpha": 0.5,
|
|
278
|
+
"edgecolor": "none",
|
|
279
|
+
"linewidth": 0.0,
|
|
280
|
+
"zorder": _Z_ARTIST,
|
|
281
|
+
},
|
|
282
|
+
},
|
|
283
|
+
# ``size`` is used as written on every figure; ``fontsize`` is the one
|
|
284
|
+
# text kwarg Python supplies, and it supplies exactly this.
|
|
285
|
+
"header": {
|
|
286
|
+
"label": "axes layout",
|
|
287
|
+
"size": 6.0,
|
|
288
|
+
"leading": 1.20,
|
|
289
|
+
"text": {
|
|
290
|
+
"color": _NAME,
|
|
291
|
+
"fontweight": "bold",
|
|
292
|
+
"ha": "left",
|
|
293
|
+
"va": "top",
|
|
294
|
+
"family": "monospace",
|
|
295
|
+
"clip_on": True,
|
|
296
|
+
"zorder": _Z_TEXT,
|
|
297
|
+
},
|
|
298
|
+
},
|
|
299
|
+
"name": {
|
|
300
|
+
"size": 7.0,
|
|
301
|
+
"leading": 1.15,
|
|
302
|
+
"text": {
|
|
303
|
+
"color": _NAME,
|
|
304
|
+
"fontweight": "bold",
|
|
305
|
+
"ha": "left",
|
|
306
|
+
"va": "top",
|
|
307
|
+
"family": "monospace",
|
|
308
|
+
"clip_on": True,
|
|
309
|
+
"zorder": _Z_TEXT,
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
"detail": {
|
|
313
|
+
"size": 4.6,
|
|
314
|
+
"leading": 1.08,
|
|
315
|
+
"rect_template": " rect=[%.3f, %.3f, %.3f, %.3f]",
|
|
316
|
+
"size_template": " width: %.3f cm height: %.3f cm",
|
|
317
|
+
"text": {
|
|
318
|
+
"color": _NAME,
|
|
319
|
+
"fontweight": "normal",
|
|
320
|
+
"ha": "left",
|
|
321
|
+
"va": "top",
|
|
322
|
+
"family": "monospace",
|
|
323
|
+
"clip_on": True,
|
|
324
|
+
"zorder": _Z_TEXT,
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
},
|
|
328
|
+
# Ternary tick anchors and label leader lines, drawn during axtri build.
|
|
329
|
+
"ternary": {
|
|
330
|
+
"tick_anchors": {
|
|
331
|
+
"show": True,
|
|
332
|
+
"scatter": {"s": 1.0, "marker": ".", "c": _TERNARY, "clip_on": False},
|
|
333
|
+
},
|
|
334
|
+
"label_leaders": {
|
|
335
|
+
"show": True,
|
|
336
|
+
"plot": {
|
|
337
|
+
"marker": ".",
|
|
338
|
+
"linestyle": "-",
|
|
339
|
+
"lw": 0.3,
|
|
340
|
+
"markersize": 1,
|
|
341
|
+
"c": _TERNARY,
|
|
342
|
+
"clip_on": False,
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
#: Blocks named after the matplotlib callable that receives them. Their keys
|
|
350
|
+
#: are matplotlib's vocabulary, so the merge stops validating inside them --
|
|
351
|
+
#: the same way ``layers[].style`` is a delegated zone in the YAML schema.
|
|
352
|
+
#: Jarvis-PLOT does not enumerate what matplotlib accepts.
|
|
353
|
+
CALL_BLOCKS = (
|
|
354
|
+
"add_axes",
|
|
355
|
+
"annotate",
|
|
356
|
+
"plot",
|
|
357
|
+
"scatter",
|
|
358
|
+
"text",
|
|
359
|
+
"FancyBboxPatch",
|
|
360
|
+
"Rectangle",
|
|
361
|
+
)
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def deep_update(base: Mapping, override: Mapping | None) -> dict:
|
|
365
|
+
"""Layer one override mapping over another, without validating either.
|
|
366
|
+
|
|
367
|
+
Used to combine a style card's ``Debug`` block with a figure's YAML
|
|
368
|
+
``debug:`` mapping. Validation is deliberately not done here: both are
|
|
369
|
+
partial by design, so checking them against each other would report every
|
|
370
|
+
key the card happens not to mention. :func:`merge_debug_config` validates
|
|
371
|
+
the combined result against :data:`DEFAULT_DEBUG` once, later.
|
|
372
|
+
|
|
373
|
+
Non-mapping values replace rather than merge -- notably lists, so a card
|
|
374
|
+
overriding ``primary_order`` sets it instead of appending to it.
|
|
375
|
+
"""
|
|
376
|
+
merged = deepcopy(dict(base))
|
|
377
|
+
if not isinstance(override, Mapping):
|
|
378
|
+
return merged
|
|
379
|
+
for key, value in override.items():
|
|
380
|
+
if isinstance(value, Mapping) and isinstance(merged.get(key), Mapping):
|
|
381
|
+
merged[key] = deep_update(merged[key], value)
|
|
382
|
+
else:
|
|
383
|
+
merged[key] = deepcopy(value)
|
|
384
|
+
return merged
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
def _is_delegated(key: str) -> bool:
|
|
388
|
+
return key in CALL_BLOCKS
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def merge_debug_config(
|
|
392
|
+
base: Mapping,
|
|
393
|
+
override: Mapping | None,
|
|
394
|
+
*,
|
|
395
|
+
path: str = "",
|
|
396
|
+
problems: list[str] | None = None,
|
|
397
|
+
) -> tuple[dict, list[str]]:
|
|
398
|
+
"""Merge a ``Debug`` block over the defaults, reporting what it had to drop.
|
|
399
|
+
|
|
400
|
+
Returns ``(merged, problems)``. Two things used to fail in silence here and
|
|
401
|
+
now surface instead:
|
|
402
|
+
|
|
403
|
+
- a key the defaults do not define was carried through as inert junk, so a
|
|
404
|
+
typo looked exactly like a working override;
|
|
405
|
+
- a scalar written where the defaults hold a mapping was discarded outright.
|
|
406
|
+
|
|
407
|
+
Inside a call block (see :data:`CALL_BLOCKS`) neither check applies: those
|
|
408
|
+
keys belong to matplotlib. Overrides there are layered key by key, so a
|
|
409
|
+
card may change one arrow property without restating the rest.
|
|
410
|
+
|
|
411
|
+
Neither ever raises. A bad ``Debug`` block degrades to the defaults and says
|
|
412
|
+
so once, because a debug overlay must never be able to break a plot.
|
|
413
|
+
"""
|
|
414
|
+
problems = [] if problems is None else problems
|
|
415
|
+
merged = deepcopy(dict(base))
|
|
416
|
+
if not isinstance(override, Mapping):
|
|
417
|
+
return merged, problems
|
|
418
|
+
|
|
419
|
+
for key, value in override.items():
|
|
420
|
+
where = f"{path}{key}"
|
|
421
|
+
if key not in merged:
|
|
422
|
+
hint = did_you_mean(str(key), [str(k) for k in merged])
|
|
423
|
+
suffix = f" Did you mean {hint[0]!r}?" if hint else ""
|
|
424
|
+
problems.append(f"{where}: unknown Debug key, ignored.{suffix}")
|
|
425
|
+
continue
|
|
426
|
+
|
|
427
|
+
if _is_delegated(str(key)):
|
|
428
|
+
# matplotlib kwargs: take the override wholesale, validate nothing.
|
|
429
|
+
if isinstance(merged[key], Mapping) and isinstance(value, Mapping):
|
|
430
|
+
merged[key] = deep_update(merged[key], value)
|
|
431
|
+
else:
|
|
432
|
+
merged[key] = deepcopy(value)
|
|
433
|
+
continue
|
|
434
|
+
|
|
435
|
+
if isinstance(merged[key], Mapping):
|
|
436
|
+
if isinstance(value, Mapping):
|
|
437
|
+
merged[key], _ = merge_debug_config(
|
|
438
|
+
merged[key], value, path=f"{where}.", problems=problems
|
|
439
|
+
)
|
|
440
|
+
else:
|
|
441
|
+
problems.append(
|
|
442
|
+
f"{where}: expected a mapping, got "
|
|
443
|
+
f"{type(value).__name__}; kept the default."
|
|
444
|
+
)
|
|
445
|
+
continue
|
|
446
|
+
|
|
447
|
+
merged[key] = deepcopy(value)
|
|
448
|
+
|
|
449
|
+
return merged, problems
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def resolve_debug_config(fig) -> dict:
|
|
453
|
+
"""Return the merged debug settings, logging anything the merge dropped."""
|
|
454
|
+
merged, problems = merge_debug_config(
|
|
455
|
+
DEFAULT_DEBUG,
|
|
456
|
+
getattr(fig, "debug_config", getattr(fig, "_debug_config", None)),
|
|
457
|
+
)
|
|
458
|
+
if problems:
|
|
459
|
+
logger = getattr(fig, "logger", None)
|
|
460
|
+
warn = getattr(logger, "warning", None)
|
|
461
|
+
if callable(warn):
|
|
462
|
+
try:
|
|
463
|
+
warn("Debug config:\n\t" + "\n\t".join(problems))
|
|
464
|
+
except Exception:
|
|
465
|
+
pass
|
|
466
|
+
return merged
|