jarvisplot 2.1.2__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.2 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/PKG-INFO +1 -1
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/SOURCES.txt +1 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/PKG-INFO +1 -1
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/corrplot_runtime.py +39 -11
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/layout_runtime.py +22 -2
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/preprocessor.py +13 -10
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/profile_runtime.py +54 -32
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/colors/colormaps.json +15 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/corrplot/diamond.json +2 -1
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/core_runtime.py +46 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/method_notes.yaml +1 -1
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/type-correlation-matrix.yaml +3 -1
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/transform_contracts.py +2 -1
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/utils/cmaps.py +3 -1
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/cap.py +1 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/pyproject.toml +1 -1
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_axis_title.py +26 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_cmaps.py +15 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_corrplot.py +73 -0
- {jarvisplot-2.1.2 → 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.2 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/dependency_links.txt +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/entry_points.txt +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/requires.txt +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/JarvisPLOT.egg-info/top_level.txt +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/README.md +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/__init__.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/adapters_rect.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/adapters_ternary.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/bin_stat_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/cards/std_axes_adapter_config.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/colorbar_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/config_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/corr_layout.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/corr_layout_diamond.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/corr_order.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/correlation_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/data_pipelines.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/debug_config.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/density_cell_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/design_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/dynesty_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/figure.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/figure_types.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/helper.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/interp_2d_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/interp_natural_neighbor.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/interp_natural_neighbor_exact.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/layer_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/method_registry.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/posterior_density_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/posterior_hpd.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/posterior_mesh.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/preprocessor_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/significance_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/Figure/style_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/__init__.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/agent_digest.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/agent_io.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cache_store.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/capabilities.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/1x1/ternary.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/dynesty_runplot.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/rect.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/rect5x1.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/rect_cmap.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/rect_marginal.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/rectratio.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/ternary.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/2x1/ternary_cmap.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/4x1/rect.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/4x1/rect_cmap.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/4x1/ternary.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/a4paper/4x1/ternary_cmap.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/args.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/corrplot/matrix.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/default/output.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/flowchart/default.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/gambit/1x1/ternary.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/gambit/2x1/rect_cmap.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/gambit/2x1/ternary.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/gambit/2x1/ternary_cmap.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/icons/JarvisHEP.png +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/JarvisHEP.png +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/calculator.png +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/inputfile.png +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/opera.png +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/outputfile.png +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/icons/flowchart/sampler.png +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/icons/gambit.png +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/icons/gambit_small.png +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cards/style_preference.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cli.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/cli_help.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/client.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/column_demand.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/column_probe.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/config.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/config_address.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/core.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/core_assets.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/data_access.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/data_loader.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/data_loader_hdf5.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/data_loader_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/data_loader_summary.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/dataset_types.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/diagnostic_guidance.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/diagnostics.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/dryrun_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/expr_names.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/fix_apply.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/flowchart.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/inner_func.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/man_catalog.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/man_methods.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/man_render_agent.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/man_render_human.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/man_transforms.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/agent-output.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/cli-map.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/data-columns.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/debug-overlay.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/diagnostics.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/dryrun-viz.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/layer-method.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/manifest.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/style-axes.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/type-posterior-2d.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/type-profile-2d.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/validate.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/workflow.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/manual_cards/yaml-root.yaml +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/memtrace.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/method_contracts.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/render_health.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/core/common.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/core/dataset.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/core/figure.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/core/layer.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/core/transform.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/manifest.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/bar.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/barh.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/contour.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/contourf.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/corrplot.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/dynesty_runplot.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/errorbar.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/fill.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/fill_between.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/fill_betweenx.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/hist.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/hist2d.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/imshow.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/jpcontour.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/jpcontourf.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/jpfield.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/pcolor.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/pcolormesh.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/plot.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/quiver.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/scatter.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/stairs.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/step.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/tricontour.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/tricontourf.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/tripcolor.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/tripcolor_axes.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/triplot.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/voronoi.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/methods/voronoif.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema/plot-config.json +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema_catalog.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/schema_diagnostics.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/templates_catalog.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/utils/__init__.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/utils/dataframes.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/utils/expression.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/utils/interpolator.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/utils/pathing.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/validation.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/__init__.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/config_cmd.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/data.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/doctor.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/dryrun.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/explain.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/man.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/suggest.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/template.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/verbs/validate.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/jarvisplot/yaml_io.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/setup.cfg +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_agent_digest.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_agent_envelope.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_capabilities.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_card_debug_shape.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_cli_help.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_cli_verbs.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_column_existence.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_config_addressing.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_config_edit.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_config_expand.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_correlation_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_data_access.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_data_describe.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_data_head_eval.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_data_loader_contracts.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_data_pipelines.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_debug_config.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_debug_switches.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_debug_yaml_override.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_density_cell_transform.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_design_runtime.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_diagnostic_guidance.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_docs_status_labels.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_doctor_partial.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_explain.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_figure_type_expander.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_fix_application.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_flowchart_renderer.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_imshow_adapter.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_interp_2d_transform.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_interp_natural_neighbor.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_interpolator_contracts.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_jpcontour_methods.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_man_cli.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_method_contracts.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_parse_data_metadata.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_pathing_contracts.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_posterior_hpd.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_render_health.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_row_ledger.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_schema_catalog.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_suggest.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_suggest_axes.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_template_catalog.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_template_json.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_ternary_debug.py +0 -0
- {jarvisplot-2.1.2 → jarvisplot-2.1.4}/tests/test_transform_contracts.py +0 -0
- {jarvisplot-2.1.2 → 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
|
|
@@ -45,10 +45,15 @@ GLYPHS = ("circle", "square", "ellipse", "color", "shade", "pie", "number")
|
|
|
45
45
|
|
|
46
46
|
_TRIANGLES = ("full", "upper", "lower")
|
|
47
47
|
|
|
48
|
+
#: What the tint may be told to mean. `selected` is the author's own grouping,
|
|
49
|
+
#: `alternate` the figure's own, `none` nothing.
|
|
50
|
+
_STRIPES = ("alternate", "selected", "none")
|
|
51
|
+
|
|
48
52
|
#: Formals resolved at config time. They arrive because the user wrote them
|
|
49
53
|
#: in the layer, and are dropped here rather than forwarded to matplotlib.
|
|
50
54
|
_CONFIG_TIME = ("order", "hclust.method", "addrect", "col", "tl.pos", "tl.cex",
|
|
51
|
-
"tl.col", "tl.srt", "tl.offset", "cl.cex", "edge.numbers.cex"
|
|
55
|
+
"tl.col", "tl.srt", "tl.offset", "cl.cex", "edge.numbers.cex",
|
|
56
|
+
"stripe.variables")
|
|
52
57
|
|
|
53
58
|
|
|
54
59
|
def _pop(kwargs: dict, name: str, default=None):
|
|
@@ -270,14 +275,25 @@ def _notch_vertices(n: int, side: str = "left", diag: bool = False):
|
|
|
270
275
|
)
|
|
271
276
|
|
|
272
277
|
|
|
273
|
-
def _shaded_variables(n: int, blocks=None) -> np.ndarray:
|
|
274
|
-
"""Which variables carry the tint
|
|
278
|
+
def _shaded_variables(n: int, blocks=None, selected=None) -> np.ndarray:
|
|
279
|
+
"""Which variables carry the tint.
|
|
280
|
+
|
|
281
|
+
Three answers, and they say different things. ``selected`` is an explicit
|
|
282
|
+
set of positions -- the author naming the variables that matter, so the
|
|
283
|
+
tint is *their* grouping and nothing is inferred. Otherwise it is read off
|
|
284
|
+
the figure: alternate **blocks** when the clustering cut some, so the
|
|
285
|
+
shading says where one group ends and the next begins (which is what the
|
|
286
|
+
boxes were for), and alternate **names** when it did not.
|
|
275
287
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
next begins -- which is what the boxes were for.
|
|
288
|
+
``selected`` arrives as positions, not names: the order is settled at
|
|
289
|
+
config time and only the order knows which position a name ended up at.
|
|
279
290
|
"""
|
|
280
291
|
shaded = np.zeros(int(n), dtype=bool)
|
|
292
|
+
if selected is not None:
|
|
293
|
+
for position in selected:
|
|
294
|
+
if 0 <= int(position) < int(n):
|
|
295
|
+
shaded[int(position)] = True
|
|
296
|
+
return shaded
|
|
281
297
|
if blocks:
|
|
282
298
|
for position, (start, end) in enumerate(blocks):
|
|
283
299
|
if position % 2 == 0:
|
|
@@ -728,9 +744,21 @@ def draw_corrplot(ax, **kwargs):
|
|
|
728
744
|
# Diamond only. See the stripe block below for why it is not decoration.
|
|
729
745
|
stripe = _pop(kwargs, "stripe", "alternate")
|
|
730
746
|
stripe = "none" if stripe is False else str(stripe).strip().lower()
|
|
731
|
-
if stripe not in
|
|
747
|
+
if stripe not in _STRIPES:
|
|
748
|
+
raise ValueError(
|
|
749
|
+
"corrplot stripe must be one of {}; got {!r}. `selected` takes the "
|
|
750
|
+
"variables to tint in `stripe.variables`.".format(
|
|
751
|
+
", ".join(_STRIPES), stripe
|
|
752
|
+
)
|
|
753
|
+
)
|
|
754
|
+
# Positions, resolved from `stripe.variables` at config time -- see
|
|
755
|
+
# `core_runtime._corr_shaded_positions`. The names cannot be resolved here
|
|
756
|
+
# because `order` has already moved them.
|
|
757
|
+
shaded_positions = kwargs.pop("__corr_shaded__", None)
|
|
758
|
+
if stripe == "selected" and shaded_positions is None:
|
|
732
759
|
raise ValueError(
|
|
733
|
-
"corrplot stripe
|
|
760
|
+
"corrplot stripe: selected needs stripe.variables -- the names to "
|
|
761
|
+
"tint. Without them the tint would say nothing."
|
|
734
762
|
)
|
|
735
763
|
stripe_color = _pop(kwargs, "stripe.col", "#EFEFEF")
|
|
736
764
|
# Diamond only. See `_edge_rules`: the rotated matrix has no top or bottom
|
|
@@ -883,7 +911,7 @@ def draw_corrplot(ax, **kwargs):
|
|
|
883
911
|
edge_color, clip, zorder + 40,
|
|
884
912
|
)
|
|
885
913
|
|
|
886
|
-
if diamond and stripe
|
|
914
|
+
if diamond and stripe != "none" and np.any(drawn):
|
|
887
915
|
# Every other variable's cells, tinted. Not decoration: a variable's
|
|
888
916
|
# pairs run away from its name as a V, and at 40 names a reader
|
|
889
917
|
# following one of those arms has nothing to hold on to. The band is
|
|
@@ -899,7 +927,7 @@ def draw_corrplot(ax, **kwargs):
|
|
|
899
927
|
#
|
|
900
928
|
# The union of those variables' cells rather than one band each, so a
|
|
901
929
|
# cell where two bands cross is filled once and the tint stays even.
|
|
902
|
-
shaded = _shaded_variables(n, blocks)
|
|
930
|
+
shaded = _shaded_variables(n, blocks, shaded_positions)
|
|
903
931
|
band = shaded[index_x.astype(int)] | shaded[index_y.astype(int)]
|
|
904
932
|
band &= drawn
|
|
905
933
|
if np.any(band):
|
|
@@ -1091,7 +1119,7 @@ def draw_corrplot(ax, **kwargs):
|
|
|
1091
1119
|
# block above), so a box around each of them would be the same fact drawn
|
|
1092
1120
|
# twice, in the heaviest ink on the figure. `addrect` still decides *what*
|
|
1093
1121
|
# the blocks are; it just stops drawing them.
|
|
1094
|
-
if blocks and not (diamond and stripe
|
|
1122
|
+
if blocks and not (diamond and stripe == "alternate"):
|
|
1095
1123
|
for start, end in blocks:
|
|
1096
1124
|
if diamond:
|
|
1097
1125
|
ax.add_patch(
|
|
@@ -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",
|
|
@@ -498,7 +498,8 @@
|
|
|
498
498
|
"type": {"type": "enum", "values": ["upper", "lower"], "default": "upper", "forbidden": ["full"]},
|
|
499
499
|
"diag": {"type": "boolean", "default": true},
|
|
500
500
|
"side": {"type": "enum", "values": ["left", "right"], "default": "right"},
|
|
501
|
-
"stripe": {"type": "enum", "values": ["alternate", "none"], "default": "alternate", "false_alias": "none"},
|
|
501
|
+
"stripe": {"type": "enum", "values": ["alternate", "selected", "none"], "default": "alternate", "false_alias": "none"},
|
|
502
|
+
"stripe.variables": {"type": "list_of_strings", "default": null, "requires": {"stripe": "selected"}},
|
|
502
503
|
"order": {"type": "enum", "values": ["original", "AOE", "FPC", "hclust", "alphabet"], "default": "original"},
|
|
503
504
|
"hclust.method": {"type": "enum", "values": ["single", "complete", "average", "weighted", "mcquitty", "median", "centroid", "ward.D", "ward.D2"], "default": "complete"},
|
|
504
505
|
"addrect": {"type": "integer_or_null", "default": null, "requires": {"order": "hclust"}},
|
|
@@ -590,6 +590,47 @@ def _solve_corr_diamond(card, info, style, columns, axes_name):
|
|
|
590
590
|
return geom, solved
|
|
591
591
|
|
|
592
592
|
|
|
593
|
+
def _corr_shaded_positions(style: Mapping, columns, name: str):
|
|
594
|
+
"""`stripe.variables` resolved against the order the figure ended up in.
|
|
595
|
+
|
|
596
|
+
It has to happen here and not at draw time. The renderer sees positions,
|
|
597
|
+
and which position a variable holds is `order`'s answer, settled a moment
|
|
598
|
+
ago -- a name resolved against the *unordered* columns would tint a
|
|
599
|
+
different variable on every reordering and never say so.
|
|
600
|
+
|
|
601
|
+
A name that is not in the matrix is an error rather than a silent miss, for
|
|
602
|
+
the same reason: a tint that quietly did nothing is indistinguishable from
|
|
603
|
+
a tint that was not asked for.
|
|
604
|
+
"""
|
|
605
|
+
stripe = style.get("stripe", "alternate")
|
|
606
|
+
stripe = "none" if stripe is False else str(stripe or "").strip().lower()
|
|
607
|
+
wanted = style.get("stripe.variables")
|
|
608
|
+
if wanted is None:
|
|
609
|
+
return None
|
|
610
|
+
if stripe != "selected":
|
|
611
|
+
raise ValueError(
|
|
612
|
+
"figure '{}' gives corrplot stripe.variables with stripe: {}. The "
|
|
613
|
+
"names are only read by stripe: selected; leaving them here would "
|
|
614
|
+
"draw the other tint and say nothing about them.".format(name, stripe)
|
|
615
|
+
)
|
|
616
|
+
if isinstance(wanted, str) or not isinstance(wanted, (list, tuple, set)):
|
|
617
|
+
raise ValueError(
|
|
618
|
+
"figure '{}' gives corrplot stripe.variables: {!r}. It takes a "
|
|
619
|
+
"list of variable names.".format(name, wanted)
|
|
620
|
+
)
|
|
621
|
+
at = {str(column): position for position, column in enumerate(columns)}
|
|
622
|
+
missing = [str(v) for v in wanted if str(v) not in at]
|
|
623
|
+
if missing:
|
|
624
|
+
raise ValueError(
|
|
625
|
+
"figure '{}' asks corrplot to tint {}, which {} not in the matrix. "
|
|
626
|
+
"The variables drawn are: {}.".format(
|
|
627
|
+
name, ", ".join(missing), "is" if len(missing) == 1 else "are",
|
|
628
|
+
", ".join(str(c) for c in columns),
|
|
629
|
+
)
|
|
630
|
+
)
|
|
631
|
+
return sorted(at[str(v)] for v in wanted)
|
|
632
|
+
|
|
633
|
+
|
|
593
634
|
def _as_corr_bool(value, default: bool = False) -> bool:
|
|
594
635
|
if value is None:
|
|
595
636
|
return default
|
|
@@ -1000,6 +1041,11 @@ def _prebuild_one(core, info: dict, card: Mapping) -> None:
|
|
|
1000
1041
|
# but placed and sized by the solve.
|
|
1001
1042
|
layer["style"]["__corr_number_mm__"] = geom.number_pad_mm
|
|
1002
1043
|
layer["style"]["__corr_number_pt__"] = geom.number_size_pt
|
|
1044
|
+
# `stripe.variables` names variables; the renderer draws positions, and
|
|
1045
|
+
# only the order settled above knows which is which.
|
|
1046
|
+
shaded = _corr_shaded_positions(style, columns, info.get("name", "?"))
|
|
1047
|
+
if shaded is not None:
|
|
1048
|
+
layer["style"]["__corr_shaded__"] = shaded
|
|
1003
1049
|
|
|
1004
1050
|
if blocks:
|
|
1005
1051
|
# The boxes are cuts of the tree the order came from, so they are
|
|
@@ -62,7 +62,7 @@ corrplot:
|
|
|
62
62
|
- "Reserved: only the [corrplot, matrix] or [corrplot, diamond] style card provides its axes (axcorr / axccorr)."
|
|
63
63
|
- "No coordinates needed — x_index / y_index / rho are the transform's own output columns."
|
|
64
64
|
- "style takes R's formals: method (circle|square|ellipse|color|shade|pie|number), type, diag, glyph.scale, outline, addgrid.col, plus the card's own ellipse.scale."
|
|
65
|
-
- "Use [corrplot, matrix] for the square matrix; [corrplot, diamond] keeps one triangle, rotates it 45 degrees, and adds side: left|right (default right, which puts the triangle on the left of the page) plus stripe: alternate|none."
|
|
65
|
+
- "Use [corrplot, matrix] for the square matrix; [corrplot, diamond] keeps one triangle, rotates it 45 degrees, and adds side: left|right (default right, which puts the triangle on the left of the page) plus stripe: alternate|selected|none. stripe: selected takes the variables to tint in stripe.variables, resolved against the solved order; diag: true|false is the self-correlation on the diagonal, on by default."
|
|
66
66
|
- "order (original|AOE|FPC|hclust|alphabet) and addrect are resolved before the figure is built, then written into the transform's `columns`."
|
|
67
67
|
- "sig.level switches on the significance test; unlike R no p.mat is needed, because the table carries n per pair."
|
|
68
68
|
- "The glyph is sized from the solved cell and the coefficient text is back-solved from it, so both survive the 170 mm width clamp."
|
|
@@ -45,7 +45,9 @@ human:
|
|
|
45
45
|
`style: [corrplot, diamond]` picks the other card: the same matrix as
|
|
46
46
|
one triangle turned 45 degrees, names in a plain column of horizontal
|
|
47
47
|
text, each variable's pairs a V rooted at its own name. Same formals,
|
|
48
|
-
plus `side: left | right` (default `right`, the triangle on the left of the page) and `stripe: alternate | none
|
|
48
|
+
plus `side: left | right` (default `right`, the triangle on the left of the page) and `stripe: alternate | selected | none`
|
|
49
|
+
(`selected` names the variables in `stripe.variables`), plus
|
|
50
|
+
`diag: true | false` for the self-correlation on the diagonal.
|
|
49
51
|
- kind: yaml
|
|
50
52
|
title: Minimal figure
|
|
51
53
|
lexer: yaml
|
|
@@ -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)
|