jarvisplot 2.1.3__tar.gz → 2.1.4__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.3 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/PKG-INFO +1 -1
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/SOURCES.txt +1 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/PKG-INFO +1 -1
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/layout_runtime.py +22 -2
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/preprocessor.py +13 -10
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/profile_runtime.py +54 -32
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/colors/colormaps.json +15 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/transform_contracts.py +2 -1
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/utils/cmaps.py +3 -1
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/cap.py +1 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/pyproject.toml +1 -1
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_axis_title.py +26 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_cmaps.py +15 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_figure_contracts.py +10 -3
- jarvisplot-2.1.4/tests/test_profile_runtime.py +141 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/dependency_links.txt +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/entry_points.txt +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/requires.txt +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/top_level.txt +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/README.md +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/__init__.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/adapters_rect.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/adapters_ternary.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/bin_stat_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/cards/std_axes_adapter_config.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/colorbar_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/config_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/corr_layout.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/corr_layout_diamond.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/corr_order.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/correlation_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/corrplot_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/data_pipelines.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/debug_config.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/density_cell_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/design_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/dynesty_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/figure.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/figure_types.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/helper.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/interp_2d_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/interp_natural_neighbor.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/interp_natural_neighbor_exact.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/layer_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/method_registry.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/posterior_density_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/posterior_hpd.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/posterior_mesh.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/preprocessor_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/significance_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/Figure/style_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/__init__.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/agent_digest.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/agent_io.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cache_store.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/capabilities.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/1x1/ternary.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/dynesty_runplot.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/rect.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/rect5x1.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/rect_cmap.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/rect_marginal.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/rectratio.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/ternary.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/ternary_cmap.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/4x1/rect.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/4x1/rect_cmap.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/4x1/ternary.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/4x1/ternary_cmap.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/args.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/corrplot/diamond.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/corrplot/matrix.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/default/output.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/flowchart/default.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/gambit/1x1/ternary.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/gambit/2x1/rect_cmap.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/gambit/2x1/ternary.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/gambit/2x1/ternary_cmap.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/icons/JarvisHEP.png +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/JarvisHEP.png +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/calculator.png +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/inputfile.png +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/opera.png +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/outputfile.png +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/sampler.png +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/icons/gambit.png +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/icons/gambit_small.png +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cards/style_preference.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cli.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/cli_help.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/client.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/column_demand.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/column_probe.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/config.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/config_address.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/core.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/core_assets.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/core_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/data_access.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/data_loader.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/data_loader_hdf5.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/data_loader_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/data_loader_summary.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/dataset_types.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/diagnostic_guidance.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/diagnostics.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/dryrun_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/expr_names.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/fix_apply.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/flowchart.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/inner_func.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/man_catalog.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/man_methods.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/man_render_agent.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/man_render_human.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/man_transforms.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/agent-output.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/cli-map.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/data-columns.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/debug-overlay.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/diagnostics.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/dryrun-viz.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/layer-method.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/manifest.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/method_notes.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/style-axes.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/type-correlation-matrix.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/type-posterior-2d.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/type-profile-2d.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/validate.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/workflow.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/manual_cards/yaml-root.yaml +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/memtrace.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/method_contracts.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/render_health.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/core/common.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/core/dataset.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/core/figure.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/core/layer.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/core/transform.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/manifest.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/bar.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/barh.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/contour.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/contourf.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/corrplot.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/dynesty_runplot.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/errorbar.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/fill.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/fill_between.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/fill_betweenx.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/hist.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/hist2d.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/imshow.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/jpcontour.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/jpcontourf.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/jpfield.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/pcolor.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/pcolormesh.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/plot.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/quiver.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/scatter.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/stairs.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/step.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/tricontour.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/tricontourf.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/tripcolor.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/tripcolor_axes.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/triplot.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/voronoi.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/methods/voronoif.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema/plot-config.json +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema_catalog.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/schema_diagnostics.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/templates_catalog.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/utils/__init__.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/utils/dataframes.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/utils/expression.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/utils/interpolator.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/utils/pathing.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/validation.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/__init__.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/config_cmd.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/data.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/doctor.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/dryrun.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/explain.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/man.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/suggest.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/template.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/verbs/validate.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/jarvisplot/yaml_io.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/setup.cfg +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_agent_digest.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_agent_envelope.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_capabilities.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_card_debug_shape.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_cli_help.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_cli_verbs.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_column_existence.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_config_addressing.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_config_edit.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_config_expand.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_correlation_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_corrplot.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_data_access.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_data_describe.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_data_head_eval.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_data_loader_contracts.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_data_pipelines.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_debug_config.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_debug_switches.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_debug_yaml_override.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_density_cell_transform.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_design_runtime.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_diagnostic_guidance.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_docs_status_labels.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_doctor_partial.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_explain.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_figure_type_expander.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_fix_application.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_flowchart_renderer.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_imshow_adapter.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_interp_2d_transform.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_interp_natural_neighbor.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_interpolator_contracts.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_jpcontour_methods.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_man_cli.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_method_contracts.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_parse_data_metadata.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_pathing_contracts.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_posterior_hpd.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_render_health.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_row_ledger.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_schema_catalog.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_suggest.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_suggest_axes.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_template_catalog.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_template_json.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_ternary_debug.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_transform_contracts.py +0 -0
- {jarvisplot-2.1.3 → jarvisplot-2.1.4}/tests/test_validate_no_matplotlib.py +0 -0
|
@@ -227,6 +227,7 @@ tests/test_method_contracts.py
|
|
|
227
227
|
tests/test_parse_data_metadata.py
|
|
228
228
|
tests/test_pathing_contracts.py
|
|
229
229
|
tests/test_posterior_hpd.py
|
|
230
|
+
tests/test_profile_runtime.py
|
|
230
231
|
tests/test_render_health.py
|
|
231
232
|
tests/test_row_ledger.py
|
|
232
233
|
tests/test_schema_catalog.py
|
|
@@ -533,15 +533,35 @@ def apply_manual_ticks(fig, ax_obj, which: str, ticks_cfg: dict):
|
|
|
533
533
|
if pos is None:
|
|
534
534
|
return
|
|
535
535
|
target = ax_obj.ax if hasattr(ax_obj, "ax") else ax_obj
|
|
536
|
+
|
|
537
|
+
# Matplotlib's set_xticks/set_yticks expands the view limits when a
|
|
538
|
+
# requested tick lies outside the current range. That is surprising for
|
|
539
|
+
# Jarvis-PLOT cards, where an explicit frame.xlim/ylim is authoritative
|
|
540
|
+
# (e.g. ylim: [200, 400] with a stale tick at 600). Preserve the range
|
|
541
|
+
# only when autoscaling was already disabled; otherwise leave the normal
|
|
542
|
+
# autoscaling behaviour untouched for axes whose limits are data-driven.
|
|
543
|
+
axis = str(which).lower()
|
|
544
|
+
if axis not in {"x", "y"}:
|
|
545
|
+
return
|
|
546
|
+
get_lim = target.get_xlim if axis == "x" else target.get_ylim
|
|
547
|
+
set_lim = target.set_xlim if axis == "x" else target.set_ylim
|
|
548
|
+
get_autoscale = (
|
|
549
|
+
target.get_autoscalex_on if axis == "x" else target.get_autoscaley_on
|
|
550
|
+
)
|
|
551
|
+
original_lim = get_lim()
|
|
552
|
+
autoscale_was_on = get_autoscale()
|
|
536
553
|
try:
|
|
537
|
-
if
|
|
554
|
+
if axis == "x":
|
|
538
555
|
target.set_xticks(pos)
|
|
539
556
|
if labs is not None:
|
|
540
557
|
target.set_xticklabels(labs)
|
|
541
|
-
elif
|
|
558
|
+
elif axis == "y":
|
|
542
559
|
target.set_yticks(pos)
|
|
543
560
|
if labs is not None:
|
|
544
561
|
target.set_yticklabels(labs)
|
|
545
562
|
except Exception as e:
|
|
546
563
|
if fig.logger:
|
|
547
564
|
fig.logger.warning(f"Manual ticks apply failed on {which}-axis: {e}")
|
|
565
|
+
finally:
|
|
566
|
+
if not autoscale_was_on:
|
|
567
|
+
set_lim(original_lim)
|
|
@@ -851,7 +851,7 @@ class DataPreprocessor:
|
|
|
851
851
|
eff_transform = self._effective_transform(source, transform)
|
|
852
852
|
payload = {
|
|
853
853
|
"kind": "pipeline",
|
|
854
|
-
"algo": "pregrid-
|
|
854
|
+
"algo": "pregrid-v7-objective-finite-voronoi",
|
|
855
855
|
"source": self._source_token(source, combine=combine),
|
|
856
856
|
"transform": eff_transform,
|
|
857
857
|
"combine": str(combine),
|
|
@@ -900,12 +900,11 @@ class DataPreprocessor:
|
|
|
900
900
|
if isinstance(item, Mapping):
|
|
901
901
|
src = item.get("source")
|
|
902
902
|
tf = self._effective_transform(src, item.get("transform"))
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
)
|
|
903
|
+
token = {"source": self._source_token(src), "transform": tf}
|
|
904
|
+
profile_sig = self._runtime_profile_signature(tf)
|
|
905
|
+
if profile_sig is not None:
|
|
906
|
+
token["profile_signature"] = profile_sig
|
|
907
|
+
tokens.append(token)
|
|
909
908
|
payload = {
|
|
910
909
|
"name": layer.get("name"),
|
|
911
910
|
"axes": layer.get("axes"),
|
|
@@ -928,7 +927,7 @@ class DataPreprocessor:
|
|
|
928
927
|
cfg = deepcopy(cfg)
|
|
929
928
|
else:
|
|
930
929
|
cfg = {"value": cfg}
|
|
931
|
-
tokens.append({"kind": "profile", "cfg": cfg})
|
|
930
|
+
tokens.append({"kind": "profile", "algo": "objective-finite-voronoi-v2", "cfg": cfg})
|
|
932
931
|
return tokens
|
|
933
932
|
|
|
934
933
|
def _runtime_profile_signature(self, transform: Any) -> Optional[str]:
|
|
@@ -1332,13 +1331,17 @@ class DataPreprocessor:
|
|
|
1332
1331
|
|
|
1333
1332
|
@staticmethod
|
|
1334
1333
|
def _preprofile_profile_cfg(profile_cfg: Any) -> Any:
|
|
1335
|
-
#
|
|
1336
|
-
#
|
|
1334
|
+
# Runtime method/bin can share a preprofile, but objective and pregrid
|
|
1335
|
+
# controls change which source rows survive and must enter its identity.
|
|
1337
1336
|
if not isinstance(profile_cfg, Mapping):
|
|
1338
1337
|
return {}
|
|
1339
1338
|
slim: Dict[str, Any] = {}
|
|
1340
1339
|
if "coordinates" in profile_cfg:
|
|
1341
1340
|
slim["coordinates"] = deepcopy(profile_cfg["coordinates"])
|
|
1341
|
+
slim["objective"] = str(profile_cfg.get("objective", "max")).lower()
|
|
1342
|
+
for key in ("pregrid", "pregrid_bin"):
|
|
1343
|
+
if key in profile_cfg:
|
|
1344
|
+
slim[key] = deepcopy(profile_cfg[key])
|
|
1342
1345
|
return slim
|
|
1343
1346
|
|
|
1344
1347
|
def _split_prebuild_transform(self, transform: Any):
|
|
@@ -451,11 +451,26 @@ def profiling(df, prof, logger):
|
|
|
451
451
|
else:
|
|
452
452
|
z = df["z"]
|
|
453
453
|
|
|
454
|
-
logger
|
|
454
|
+
if logger:
|
|
455
|
+
logger.debug("After loading profiling x, y, z. ")
|
|
455
456
|
|
|
456
|
-
x = np.asarray(x)
|
|
457
|
-
y = np.asarray(y)
|
|
458
|
-
z = np.asarray(z)
|
|
457
|
+
x = np.asarray(x, dtype=float)
|
|
458
|
+
y = np.asarray(y, dtype=float)
|
|
459
|
+
z = np.asarray(z, dtype=float)
|
|
460
|
+
# A single invalid objective used to poison min/max(z), making every
|
|
461
|
+
# normalized dz NaN and silently disabling the z-aware exclusion rule.
|
|
462
|
+
valid = np.isfinite(x) & np.isfinite(y) & np.isfinite(z)
|
|
463
|
+
for cfg, values in ((xcfg, x), (ycfg, y), (zcfg, z)):
|
|
464
|
+
if str(cfg.get("scale", "linear")).lower() == "log":
|
|
465
|
+
valid &= values > 0
|
|
466
|
+
if not np.all(valid):
|
|
467
|
+
df = df.iloc[np.flatnonzero(valid)]
|
|
468
|
+
x, y, z = x[valid], y[valid], z[valid]
|
|
469
|
+
if not len(z):
|
|
470
|
+
out = df.copy()
|
|
471
|
+
for cfg, values, default in ((xcfg, x, "x"), (ycfg, y, "y"), (zcfg, z, "z")):
|
|
472
|
+
out[cfg.get("name", default)] = values
|
|
473
|
+
return out
|
|
459
474
|
|
|
460
475
|
if grid == "ternary":
|
|
461
476
|
xlim = xcfg.get("lim", [0, 1])
|
|
@@ -535,20 +550,12 @@ def profiling(df, prof, logger):
|
|
|
535
550
|
},
|
|
536
551
|
)
|
|
537
552
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
if
|
|
544
|
-
yy = (np.log(yy) - np.log(ylim[0])) / (np.log(ylim[1]) - np.log(ylim[0]))
|
|
545
|
-
else:
|
|
546
|
-
yy = (yy - ylim[0]) / (ylim[1] - ylim[0])
|
|
547
|
-
|
|
548
|
-
if zscale == "log":
|
|
549
|
-
zz = (np.log(zz) - np.log(zlim[0])) / (np.log(zlim[1]) - np.log(zlim[0]))
|
|
550
|
-
else:
|
|
551
|
-
zz = (zz - zlim[0]) / (zlim[1] - zlim[0])
|
|
553
|
+
xx = _normalize_profile_axis(xx, xlim, xscale)
|
|
554
|
+
yy = _normalize_profile_axis(yy, ylim, yscale)
|
|
555
|
+
zz = _normalize_profile_axis(zz, zlim, zscale)
|
|
556
|
+
# Empty-grid seeds are processed last and carry NaN in the output. Give
|
|
557
|
+
# them a finite exclusion coordinate, including for logarithmic z.
|
|
558
|
+
zz[len(order):] = 2.0 if obj == "min" else -1.0
|
|
552
559
|
|
|
553
560
|
msk = profile_bridson_sorted(xx, yy, zz, radius)
|
|
554
561
|
keep_pos = np.flatnonzero(msk).astype(np.int64, copy=False)
|
|
@@ -557,6 +564,22 @@ def profiling(df, prof, logger):
|
|
|
557
564
|
keep_source = keep_pos[keep_pos < source_count]
|
|
558
565
|
keep_grid = keep_pos[keep_pos >= source_count] - source_count
|
|
559
566
|
|
|
567
|
+
# Greedy thinning only chooses the spatial partition: a high-valued point
|
|
568
|
+
# can be suppressed by an earlier seed, then a worse seed can survive on
|
|
569
|
+
# the other side of it. Re-profile *all* input rows within the nearest-seed
|
|
570
|
+
# (Voronoi) cells so those suppressed candidates still contribute. Select
|
|
571
|
+
# the entire winning source row, not just its z at another row's x/y.
|
|
572
|
+
if keep_source.size:
|
|
573
|
+
from scipy.spatial import cKDTree
|
|
574
|
+
|
|
575
|
+
source_xy = np.column_stack([xx[:source_count], yy[:source_count]])
|
|
576
|
+
tree = cKDTree(source_xy[keep_source])
|
|
577
|
+
_, cell = tree.query(source_xy)
|
|
578
|
+
winners = np.full(keep_source.size, source_count, dtype=np.int64)
|
|
579
|
+
# Input is already ordered best first for either max or min.
|
|
580
|
+
np.minimum.at(winners, cell, np.arange(source_count, dtype=np.int64))
|
|
581
|
+
keep_source = np.sort(winners[winners < source_count])
|
|
582
|
+
|
|
560
583
|
source_rows = order[keep_source]
|
|
561
584
|
source_x = x[source_rows]
|
|
562
585
|
source_y = y[source_rows]
|
|
@@ -594,7 +617,7 @@ def profiling(df, prof, logger):
|
|
|
594
617
|
|
|
595
618
|
|
|
596
619
|
def _preprofiling(df, prof, logger):
|
|
597
|
-
"""
|
|
620
|
+
"""Keep the requested finite extremum per pre-bin for cache prebuild."""
|
|
598
621
|
|
|
599
622
|
def _norm(arr, lim, scale):
|
|
600
623
|
arr = np.asarray(arr, dtype=float)
|
|
@@ -765,14 +788,14 @@ def _preprofiling(df, prof, logger):
|
|
|
765
788
|
|
|
766
789
|
xnorm = _norm(xvals, xlim, xscale)
|
|
767
790
|
ynorm = _norm(yvals, ylim, yscale)
|
|
768
|
-
valid = np.isfinite(xnorm) & np.isfinite(ynorm)
|
|
791
|
+
valid = np.isfinite(xnorm) & np.isfinite(ynorm) & np.isfinite(zvals)
|
|
769
792
|
if not np.any(valid):
|
|
770
793
|
if logger:
|
|
771
|
-
logger.warning("Preprofiling got no finite points; returning
|
|
772
|
-
out = df.copy(
|
|
773
|
-
out[xind] = xvals
|
|
774
|
-
out[yind] = yvals
|
|
775
|
-
out[zind] = zvals
|
|
794
|
+
logger.warning("Preprofiling got no finite points; returning an empty dataframe.")
|
|
795
|
+
out = df.iloc[:0].copy()
|
|
796
|
+
out[xind] = xvals[:0]
|
|
797
|
+
out[yind] = yvals[:0]
|
|
798
|
+
out[zind] = zvals[:0]
|
|
776
799
|
return out
|
|
777
800
|
|
|
778
801
|
xv = np.clip(xnorm[valid], 0.0, 1.0 - 1e-12)
|
|
@@ -783,20 +806,19 @@ def _preprofiling(df, prof, logger):
|
|
|
783
806
|
|
|
784
807
|
idx_src = np.flatnonzero(valid).astype(np.int64)
|
|
785
808
|
zraw = np.asarray(zvals, dtype=float)[valid]
|
|
786
|
-
zmax = np.where(np.isfinite(zraw), zraw, -np.inf)
|
|
787
|
-
zmin = np.where(np.isfinite(zraw), zraw, np.inf)
|
|
788
809
|
tmp = pd.DataFrame(
|
|
789
810
|
{
|
|
790
811
|
"__cell__": cell,
|
|
791
|
-
"
|
|
792
|
-
"__zmin__": zmin,
|
|
812
|
+
"__z__": zraw,
|
|
793
813
|
"__pos__": idx_src,
|
|
794
814
|
}
|
|
795
815
|
)
|
|
796
816
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
817
|
+
if str(prof.get("objective", "max")).lower() == "min":
|
|
818
|
+
loc = tmp.groupby("__cell__", sort=False)["__z__"].idxmin()
|
|
819
|
+
else:
|
|
820
|
+
loc = tmp.groupby("__cell__", sort=False)["__z__"].idxmax()
|
|
821
|
+
loc_all = np.sort(loc.to_numpy(dtype=np.int64, copy=False))
|
|
800
822
|
keep_pos = tmp.iloc[loc_all]["__pos__"].to_numpy(dtype=np.int64, copy=False)
|
|
801
823
|
reduced = df.iloc[keep_pos].copy()
|
|
802
824
|
reduced[xind] = xvals[keep_pos]
|
|
@@ -95,6 +95,21 @@
|
|
|
95
95
|
[1.0, "#575AA6"]
|
|
96
96
|
]
|
|
97
97
|
},
|
|
98
|
+
{
|
|
99
|
+
"name": "Jpurples",
|
|
100
|
+
"type": "linear",
|
|
101
|
+
"colors": [
|
|
102
|
+
[0.000, "#FFFFFF"],
|
|
103
|
+
[0.125, "#EFEDF5"],
|
|
104
|
+
[0.250, "#DADAEB"],
|
|
105
|
+
[0.375, "#BCBDDC"],
|
|
106
|
+
[0.500, "#9E9AC8"],
|
|
107
|
+
[0.625, "#807CBA"],
|
|
108
|
+
[0.750, "#6950A3"],
|
|
109
|
+
[0.875, "#53268F"],
|
|
110
|
+
[1.000, "#3F007D"]
|
|
111
|
+
]
|
|
112
|
+
},
|
|
98
113
|
{
|
|
99
114
|
"name": "SpectralB",
|
|
100
115
|
"type": "linear",
|
|
@@ -499,7 +499,8 @@ TRANSFORM_CONTRACTS: dict[str, dict[str, Any]] = {
|
|
|
499
499
|
"description": (
|
|
500
500
|
"Optional coarse pre-binning before Bridson/grid profile "
|
|
501
501
|
"(large tables). Mapping: {bin, enable}; false disables; "
|
|
502
|
-
"omit for auto-prebin from row count."
|
|
502
|
+
"omit for auto-prebin from row count. Keeps one finite "
|
|
503
|
+
"extremum per cell according to objective (max/min)."
|
|
503
504
|
),
|
|
504
505
|
"properties": {
|
|
505
506
|
"bin": {
|
|
@@ -40,7 +40,9 @@ def _register(name: str, cmap: Colormap, force: bool) -> bool:
|
|
|
40
40
|
cmap.name = name
|
|
41
41
|
except Exception:
|
|
42
42
|
pass
|
|
43
|
-
if "
|
|
43
|
+
if "force" in sig.parameters:
|
|
44
|
+
kwargs["force"] = bool(force)
|
|
45
|
+
elif "override" in sig.parameters:
|
|
44
46
|
kwargs["override"] = bool(force)
|
|
45
47
|
except Exception:
|
|
46
48
|
# If signature introspection fails, try safest call (cmap only).
|
|
@@ -170,6 +170,7 @@ _CMAP_DESCRIPTIONS = {
|
|
|
170
170
|
"gambit_cmap": "Continuous black → blue → cyan → yellow map.",
|
|
171
171
|
"jarvis_rainbow": "Continuous purple → blue → cyan → green → orange → red map.",
|
|
172
172
|
"jarvis_rainbow2": "Continuous red → yellow → green → blue map.",
|
|
173
|
+
"Jpurples": "Matplotlib Purples-style continuous map with a pure-white zero endpoint.",
|
|
173
174
|
"SpectralB": "Spectral-style continuous map from red through green to blue.",
|
|
174
175
|
"RdBuB": "Diverging red → white → blue map.",
|
|
175
176
|
"chrisB": "Diverging black → red → white → blue → navy map.",
|
|
@@ -257,3 +257,29 @@ def test_side_axes_honour_manual_tick_positions():
|
|
|
257
257
|
assert [t.get_text() for t in ax.ax.get_yticklabels()] == list("abcde")
|
|
258
258
|
finally:
|
|
259
259
|
plt.close(raw_fig)
|
|
260
|
+
|
|
261
|
+
|
|
262
|
+
def test_manual_ticks_do_not_expand_explicit_axis_limits():
|
|
263
|
+
"""Out-of-range manual ticks must not override an explicit frame limit."""
|
|
264
|
+
import matplotlib
|
|
265
|
+
|
|
266
|
+
matplotlib.use("Agg")
|
|
267
|
+
import matplotlib.pyplot as plt
|
|
268
|
+
|
|
269
|
+
from jarvisplot.Figure.layout_runtime import apply_manual_ticks
|
|
270
|
+
|
|
271
|
+
raw_fig, ax = plt.subplots(figsize=(3.3, 3.0))
|
|
272
|
+
ax.set_ylim(200, 400)
|
|
273
|
+
apply_manual_ticks(
|
|
274
|
+
SimpleNamespace(logger=_logger()),
|
|
275
|
+
ax,
|
|
276
|
+
"y",
|
|
277
|
+
{
|
|
278
|
+
"positions": [200, 300, 400, 500, 600],
|
|
279
|
+
"labels": ["200", "300", "400", "500", "600"],
|
|
280
|
+
},
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
assert ax.get_ylim() == pytest.approx((200.0, 400.0))
|
|
284
|
+
assert list(ax.get_yticks()) == [200, 300, 400, 500, 600]
|
|
285
|
+
plt.close(raw_fig)
|
|
@@ -4,6 +4,7 @@ import json
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
|
|
6
6
|
import matplotlib as mpl
|
|
7
|
+
import numpy as np
|
|
7
8
|
|
|
8
9
|
from jarvisplot.utils import cmaps
|
|
9
10
|
|
|
@@ -40,3 +41,17 @@ def test_official_tab5_is_registered_as_five_discrete_tab10_colors():
|
|
|
40
41
|
)
|
|
41
42
|
assert spec["type"] == "listed"
|
|
42
43
|
assert len(spec["colors"]) == 5
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_jpurples_matches_purples_style_with_a_pure_white_zero_endpoint():
|
|
47
|
+
summary = cmaps.register_from_json(COLORMAPS_JSON, force=True)
|
|
48
|
+
|
|
49
|
+
assert "Jpurples" in summary["registered"]
|
|
50
|
+
assert "Jpurples_r" in summary["registered"]
|
|
51
|
+
|
|
52
|
+
jpurples = mpl.colormaps["Jpurples"]
|
|
53
|
+
purples = mpl.colormaps["Purples"]
|
|
54
|
+
|
|
55
|
+
assert mpl.colors.to_hex(jpurples(0.0), keep_alpha=False) == "#ffffff"
|
|
56
|
+
for value in (0.125, 0.25, 0.5, 0.75, 1.0):
|
|
57
|
+
assert np.allclose(jpurples(value), purples(value), atol=1 / 255)
|
|
@@ -1094,10 +1094,12 @@ def test_preprofile_identity_ignores_runtime_bin():
|
|
|
1094
1094
|
"coordinates": {"x": {"expr": "x"}, "y": {"expr": "y"}},
|
|
1095
1095
|
"method": "bridson",
|
|
1096
1096
|
"bin": 32,
|
|
1097
|
-
"objective": "
|
|
1097
|
+
"objective": "max",
|
|
1098
1098
|
}
|
|
1099
1099
|
|
|
1100
1100
|
assert dp._preprofile_profile_cfg(cfg1) == dp._preprofile_profile_cfg(cfg2)
|
|
1101
|
+
cfg2["objective"] = "min"
|
|
1102
|
+
assert dp._preprofile_profile_cfg(cfg1) != dp._preprofile_profile_cfg(cfg2)
|
|
1101
1103
|
|
|
1102
1104
|
|
|
1103
1105
|
def test_runtime_projection_includes_row_identity_and_demand():
|
|
@@ -1159,7 +1161,7 @@ def test_runtime_transform_to_csv_exports_and_bypasses_cache(tmp_path):
|
|
|
1159
1161
|
assert list(out.columns) == ["y", "z"]
|
|
1160
1162
|
|
|
1161
1163
|
|
|
1162
|
-
def
|
|
1164
|
+
def test_prebuild_split_keeps_profile_reduction_controls():
|
|
1163
1165
|
dp = DataPreprocessor(context=None)
|
|
1164
1166
|
transform = [
|
|
1165
1167
|
{"add_column": {"name": "c", "expr": "a + b"}},
|
|
@@ -1169,6 +1171,7 @@ def test_prebuild_split_keeps_profile_identity_coordinates_only():
|
|
|
1169
1171
|
"method": "bridson",
|
|
1170
1172
|
"bin": 16,
|
|
1171
1173
|
"objective": "max",
|
|
1174
|
+
"pregrid": {"bin": 25, "enable": True},
|
|
1172
1175
|
}
|
|
1173
1176
|
},
|
|
1174
1177
|
{"sortby": "c"},
|
|
@@ -1178,7 +1181,11 @@ def test_prebuild_split_keeps_profile_identity_coordinates_only():
|
|
|
1178
1181
|
|
|
1179
1182
|
assert pre_transform is not None
|
|
1180
1183
|
assert runtime_transform is not None
|
|
1181
|
-
assert pre_transform[-1]["profile"] == {
|
|
1184
|
+
assert pre_transform[-1]["profile"] == {
|
|
1185
|
+
"coordinates": {"x": {"expr": "x"}, "y": {"expr": "y"}},
|
|
1186
|
+
"objective": "max",
|
|
1187
|
+
"pregrid": {"bin": 25, "enable": True},
|
|
1188
|
+
}
|
|
1182
1189
|
assert runtime_transform[0]["profile"]["method"] == "bridson"
|
|
1183
1190
|
assert runtime_transform[0]["profile"]["bin"] == 16
|
|
1184
1191
|
assert runtime_transform[1]["sortby"] == "c"
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""Regression coverage for finite, objective-aware profile support selection."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
|
|
5
|
+
import numpy as np
|
|
6
|
+
import pandas as pd
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
9
|
+
from jarvisplot.Figure.preprocessor import DataPreprocessor
|
|
10
|
+
from jarvisplot.Figure.data_pipelines import DataContext, SharedContent
|
|
11
|
+
from jarvisplot.Figure.profile_runtime import _preprofiling, profiling
|
|
12
|
+
from jarvisplot.cache_store import ProjectCache
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def config(objective="max"):
|
|
16
|
+
return {
|
|
17
|
+
"method": "bridson", "bin": 100, "objective": objective,
|
|
18
|
+
"grid_points": "none", "pregrid": {"bin": 10},
|
|
19
|
+
"coordinates": {
|
|
20
|
+
k: {"expr": k, "name": k, "lim": [0, 1]}
|
|
21
|
+
for k in ("x", "y")
|
|
22
|
+
} | {"z": {"expr": "z", "name": "z"}},
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@pytest.mark.parametrize("objective,expected", [("max", [1.0, 0.8]), ("min", [0.0, 0.2])])
|
|
27
|
+
def test_preprofile_keeps_only_requested_extremum(objective, expected):
|
|
28
|
+
# Duplicate dataframe indices occur when scan files are concatenated.
|
|
29
|
+
df = pd.DataFrame({
|
|
30
|
+
"x": [0.11, 0.12, 0.41, 0.42, 0.8],
|
|
31
|
+
"y": [0.11, 0.12, 0.41, 0.42, 0.8],
|
|
32
|
+
"z": [0.0, 1.0, 0.2, 0.8, np.nan],
|
|
33
|
+
"row": ["low1", "high1", "low2", "high2", "invalid"],
|
|
34
|
+
}, index=[0, 1, 0, 1, 0])
|
|
35
|
+
out = _preprofiling(df, config(objective), None)
|
|
36
|
+
np.testing.assert_allclose(out.z, expected)
|
|
37
|
+
assert out.row.tolist() == (["high1", "high2"] if objective == "max" else ["low1", "low2"])
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@pytest.mark.parametrize("objective", ["max", "min"])
|
|
41
|
+
def test_invalid_objective_does_not_disable_bridson_exclusion(objective):
|
|
42
|
+
# The inferior point lies in the annulus where z-aware rejection is needed.
|
|
43
|
+
z = [1.0, 0.0] if objective == "max" else [0.0, 1.0]
|
|
44
|
+
good = pd.DataFrame({"x": [0.1, 0.109], "y": [0.1, 0.1], "z": z})
|
|
45
|
+
dirty = pd.concat([good, pd.DataFrame({
|
|
46
|
+
"x": [0.8, 0.9, 0.7], "y": [0.8, 0.9, 0.7],
|
|
47
|
+
"z": [np.nan, np.inf, -np.inf],
|
|
48
|
+
})], ignore_index=True)
|
|
49
|
+
log = logging.getLogger(__name__)
|
|
50
|
+
expected = profiling(good, config(objective), log)
|
|
51
|
+
actual = profiling(dirty, config(objective), log)
|
|
52
|
+
assert len(actual) == 1
|
|
53
|
+
pd.testing.assert_frame_equal(actual, expected)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_constant_profile_still_thins_close_points():
|
|
57
|
+
df = pd.DataFrame({"x": [0.1, 0.101], "y": [0.1, 0.1], "z": [0.0, 0.0]})
|
|
58
|
+
with np.errstate(invalid="raise", divide="raise"):
|
|
59
|
+
out = profiling(df, config(), None)
|
|
60
|
+
assert len(out) == 1
|
|
61
|
+
assert out.z.iloc[0] == 0.0
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
@pytest.mark.parametrize("objective", ["max", "min"])
|
|
65
|
+
def test_suppressed_candidate_still_contributes_to_cell_extremum(objective):
|
|
66
|
+
# A suppresses B, but C lies outside A's exclusion radius. B belongs to
|
|
67
|
+
# C's nearest-seed cell and is better than C: thinning alone leaks C.
|
|
68
|
+
df = pd.DataFrame({
|
|
69
|
+
"x": [0.1, 0.1092, 0.1179], "y": [0.1, 0.1, 0.1],
|
|
70
|
+
"z": [1.0, 0.9, 0.0] if objective == "max" else [0.0, 0.1, 1.0],
|
|
71
|
+
"row": ["A", "B", "C"], "nuisance": [10.0, 20.0, 30.0],
|
|
72
|
+
})
|
|
73
|
+
actual = profiling(df, config(objective), None)
|
|
74
|
+
assert actual.row.tolist() == ["A", "B"]
|
|
75
|
+
pd.testing.assert_frame_equal(actual.reset_index(drop=True), df.iloc[:2].reset_index(drop=True))
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_all_invalid_profile_returns_empty_named_columns():
|
|
79
|
+
df = pd.DataFrame({"x": [0.1], "y": [0.1], "z": [np.nan]})
|
|
80
|
+
cfg = config()
|
|
81
|
+
cfg["coordinates"]["z"]["name"] = "likelihood"
|
|
82
|
+
for reduce in (_preprofiling, profiling):
|
|
83
|
+
out = reduce(df, cfg, None)
|
|
84
|
+
assert out.empty
|
|
85
|
+
assert "likelihood" in out
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_log_profile_ignores_nonpositive_coordinates_and_constant_z():
|
|
89
|
+
cfg = config()
|
|
90
|
+
cfg["grid_points"] = "rect"
|
|
91
|
+
cfg["bin"] = 4
|
|
92
|
+
for key in ("x", "y", "z"):
|
|
93
|
+
cfg["coordinates"][key]["scale"] = "log"
|
|
94
|
+
for key in ("x", "y"):
|
|
95
|
+
cfg["coordinates"][key]["lim"] = [1, 10]
|
|
96
|
+
df = pd.DataFrame({"x": [2.0, 0.0, -1.0], "y": [3.0, 3.0, 3.0], "z": [0.05, 0.05, 0.05]})
|
|
97
|
+
with np.errstate(invalid="raise", divide="raise"):
|
|
98
|
+
out = profiling(df, cfg, None)
|
|
99
|
+
actual = out[np.isfinite(out.z)]
|
|
100
|
+
assert actual.x.tolist() == [2.0]
|
|
101
|
+
assert actual.z.tolist() == [0.05]
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def test_pregrid_controls_and_objective_change_cache_identity():
|
|
105
|
+
dp = DataPreprocessor(context=None)
|
|
106
|
+
cfg = config()
|
|
107
|
+
base = dp._preprofile_profile_cfg(cfg)
|
|
108
|
+
for change in ({"objective": "min"}, {"pregrid": False}, {"pregrid": {"bin": 20}}, {"pregrid_bin": 20}):
|
|
109
|
+
other = dp._preprofile_profile_cfg(cfg | change)
|
|
110
|
+
assert dp._pipeline_key("scan", [{"profile": base}], mode="preprofile") != dp._pipeline_key(
|
|
111
|
+
"scan", [{"profile": other}], mode="preprofile"
|
|
112
|
+
)
|
|
113
|
+
pre, _ = dp._split_prebuild_transform([{"profile": cfg | {"pregrid": False}}])
|
|
114
|
+
df = pd.DataFrame({"x": [0.11, 0.12], "y": [0.11, 0.12], "z": [0.0, 1.0]})
|
|
115
|
+
assert _preprofiling(df, pre[0]["profile"], None) is df
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def test_old_named_profile_signature_is_invalidated(monkeypatch):
|
|
119
|
+
dp = DataPreprocessor(context=None)
|
|
120
|
+
layer = {"name": "support", "data": [{"source": "scan", "transform": [{"profile": config()}]}]}
|
|
121
|
+
current = dp._layer_signature(layer)
|
|
122
|
+
monkeypatch.setattr(dp, "_runtime_profile_signature", lambda tf: "old-algorithm")
|
|
123
|
+
assert dp._layer_signature(layer) != current
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def test_prebuild_cached_max_and_min_do_not_reuse_each_others_rows(tmp_path):
|
|
127
|
+
df = pd.DataFrame({"x": [0.11, 0.12], "y": [0.11, 0.12], "z": [0.0, 1.0]})
|
|
128
|
+
for warm in (False, True):
|
|
129
|
+
ctx = DataContext(SharedContent())
|
|
130
|
+
ctx.register("scan", lambda _: df)
|
|
131
|
+
dp = DataPreprocessor(ctx, cache=ProjectCache(str(tmp_path)))
|
|
132
|
+
project = {"Figures": [{"name": "test", "layers": [
|
|
133
|
+
{"name": objective, "data": [{"source": "scan", "transform": [{"profile": config(objective)}]}]}
|
|
134
|
+
for objective in ("max", "min")
|
|
135
|
+
]}]}
|
|
136
|
+
stats = dp.prebuild_profiles(project)
|
|
137
|
+
assert stats["hits"] == (2 if warm else 0)
|
|
138
|
+
entries = [layer["data"][0] for layer in project["Figures"][0]["layers"]]
|
|
139
|
+
assert entries[0]["source"] != entries[1]["source"]
|
|
140
|
+
assert ctx.get(entries[0]["source"]).z.tolist() == [1.0]
|
|
141
|
+
assert ctx.get(entries[1]["source"]).z.tolist() == [0.0]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|