jarvisplot 2.1.0__tar.gz → 2.1.2__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.0 → jarvisplot-2.1.2}/JarvisPLOT.egg-info/PKG-INFO +1 -1
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/JarvisPLOT.egg-info/SOURCES.txt +2 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/PKG-INFO +1 -1
- jarvisplot-2.1.2/jarvisplot/Figure/corr_layout_diamond.py +491 -0
- jarvisplot-2.1.2/jarvisplot/Figure/corrplot_runtime.py +1178 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/figure.py +18 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/capabilities.py +75 -4
- jarvisplot-2.1.2/jarvisplot/cards/corrplot/diamond.json +555 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/corrplot/matrix.json +15 -2
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/style_preference.json +2 -1
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/core_runtime.py +243 -45
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/man_methods.py +153 -19
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/man_render_agent.py +2 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/method_notes.yaml +3 -1
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/type-correlation-matrix.yaml +82 -6
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/core/figure.json +1 -1
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/corrplot.json +2 -2
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/templates_catalog.py +40 -2
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/validation.py +173 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/template.py +1 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/pyproject.toml +1 -1
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_capabilities.py +39 -0
- jarvisplot-2.1.2/tests/test_corrplot.py +1330 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_man_cli.py +49 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_template_catalog.py +29 -0
- jarvisplot-2.1.0/jarvisplot/Figure/corrplot_runtime.py +0 -556
- jarvisplot-2.1.0/tests/test_corrplot.py +0 -596
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/JarvisPLOT.egg-info/dependency_links.txt +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/JarvisPLOT.egg-info/entry_points.txt +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/JarvisPLOT.egg-info/requires.txt +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/JarvisPLOT.egg-info/top_level.txt +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/README.md +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/__init__.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/adapters_rect.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/adapters_ternary.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/bin_stat_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/cards/std_axes_adapter_config.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/colorbar_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/config_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/corr_layout.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/corr_order.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/correlation_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/data_pipelines.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/debug_config.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/density_cell_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/design_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/dynesty_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/figure_types.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/helper.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/interp_2d_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/interp_natural_neighbor.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/interp_natural_neighbor_exact.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/layer_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/layout_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/method_registry.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/posterior_density_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/posterior_hpd.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/posterior_mesh.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/preprocessor.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/preprocessor_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/profile_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/significance_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/Figure/style_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/__init__.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/agent_digest.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/agent_io.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cache_store.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/1x1/ternary.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/2x1/dynesty_runplot.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/2x1/rect.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/2x1/rect5x1.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/2x1/rect_cmap.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/2x1/rect_marginal.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/2x1/rectratio.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/2x1/ternary.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/2x1/ternary_cmap.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/4x1/rect.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/4x1/rect_cmap.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/4x1/ternary.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/a4paper/4x1/ternary_cmap.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/args.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/colors/colormaps.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/default/output.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/flowchart/default.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/gambit/1x1/ternary.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/gambit/2x1/rect_cmap.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/gambit/2x1/ternary.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/gambit/2x1/ternary_cmap.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/icons/JarvisHEP.png +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/icons/flowchart/JarvisHEP.png +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/icons/flowchart/calculator.png +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/icons/flowchart/inputfile.png +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/icons/flowchart/opera.png +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/icons/flowchart/outputfile.png +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/icons/flowchart/sampler.png +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/icons/gambit.png +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cards/icons/gambit_small.png +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cli.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/cli_help.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/client.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/column_demand.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/column_probe.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/config.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/config_address.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/core.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/core_assets.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/data_access.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/data_loader.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/data_loader_hdf5.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/data_loader_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/data_loader_summary.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/dataset_types.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/diagnostic_guidance.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/diagnostics.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/dryrun_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/expr_names.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/fix_apply.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/flowchart.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/inner_func.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/man_catalog.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/man_render_human.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/man_transforms.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/agent-output.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/cli-map.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/data-columns.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/debug-overlay.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/diagnostics.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/dryrun-viz.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/layer-method.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/manifest.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/style-axes.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/type-posterior-2d.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/type-profile-2d.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/validate.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/workflow.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/manual_cards/yaml-root.yaml +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/memtrace.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/method_contracts.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/render_health.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/core/common.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/core/dataset.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/core/layer.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/core/transform.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/manifest.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/bar.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/barh.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/contour.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/contourf.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/dynesty_runplot.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/errorbar.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/fill.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/fill_between.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/fill_betweenx.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/hist.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/hist2d.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/imshow.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/jpcontour.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/jpcontourf.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/jpfield.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/pcolor.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/pcolormesh.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/plot.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/quiver.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/scatter.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/stairs.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/step.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/tricontour.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/tricontourf.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/tripcolor.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/tripcolor_axes.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/triplot.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/voronoi.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/methods/voronoif.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema/plot-config.json +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema_catalog.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/schema_diagnostics.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/transform_contracts.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/utils/__init__.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/utils/cmaps.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/utils/dataframes.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/utils/expression.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/utils/interpolator.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/utils/pathing.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/__init__.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/cap.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/config_cmd.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/data.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/doctor.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/dryrun.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/explain.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/man.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/suggest.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/verbs/validate.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/jarvisplot/yaml_io.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/setup.cfg +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_agent_digest.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_agent_envelope.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_axis_title.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_card_debug_shape.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_cli_help.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_cli_verbs.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_cmaps.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_column_existence.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_config_addressing.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_config_edit.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_config_expand.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_correlation_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_data_access.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_data_describe.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_data_head_eval.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_data_loader_contracts.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_data_pipelines.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_debug_config.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_debug_switches.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_debug_yaml_override.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_density_cell_transform.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_design_runtime.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_diagnostic_guidance.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_docs_status_labels.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_doctor_partial.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_explain.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_figure_contracts.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_figure_type_expander.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_fix_application.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_flowchart_renderer.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_imshow_adapter.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_interp_2d_transform.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_interp_natural_neighbor.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_interpolator_contracts.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_jpcontour_methods.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_method_contracts.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_parse_data_metadata.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_pathing_contracts.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_posterior_hpd.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_render_health.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_row_ledger.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_schema_catalog.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_suggest.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_suggest_axes.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_template_json.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_ternary_debug.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_transform_contracts.py +0 -0
- {jarvisplot-2.1.0 → jarvisplot-2.1.2}/tests/test_validate_no_matplotlib.py +0 -0
|
@@ -55,6 +55,7 @@ jarvisplot/Figure/bin_stat_runtime.py
|
|
|
55
55
|
jarvisplot/Figure/colorbar_runtime.py
|
|
56
56
|
jarvisplot/Figure/config_runtime.py
|
|
57
57
|
jarvisplot/Figure/corr_layout.py
|
|
58
|
+
jarvisplot/Figure/corr_layout_diamond.py
|
|
58
59
|
jarvisplot/Figure/corr_order.py
|
|
59
60
|
jarvisplot/Figure/correlation_runtime.py
|
|
60
61
|
jarvisplot/Figure/corrplot_runtime.py
|
|
@@ -97,6 +98,7 @@ jarvisplot/cards/a4paper/4x1/rect_cmap.json
|
|
|
97
98
|
jarvisplot/cards/a4paper/4x1/ternary.json
|
|
98
99
|
jarvisplot/cards/a4paper/4x1/ternary_cmap.json
|
|
99
100
|
jarvisplot/cards/colors/colormaps.json
|
|
101
|
+
jarvisplot/cards/corrplot/diamond.json
|
|
100
102
|
jarvisplot/cards/corrplot/matrix.json
|
|
101
103
|
jarvisplot/cards/default/output.json
|
|
102
104
|
jarvisplot/cards/flowchart/default.json
|
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
"""Figure geometry for the rotated (diamond) correlation matrix.
|
|
4
|
+
|
|
5
|
+
``corr_layout`` solves the square card: one half of the matrix is redundant,
|
|
6
|
+
the names are rotated tick labels crammed under a 4.2 mm cell, and the figure
|
|
7
|
+
is bounded by the page *width*. This module solves the other arrangement --
|
|
8
|
+
keep one triangle, turn it 45 degrees -- from the map::
|
|
9
|
+
|
|
10
|
+
u = (j - i) / 2 how far apart the two variables are -> horizontal
|
|
11
|
+
v = (i + j) / 2 the midpoint of the two -> vertical
|
|
12
|
+
|
|
13
|
+
Everything about this card is a consequence of that map:
|
|
14
|
+
|
|
15
|
+
* A cell's four neighbours land at ``(±1/2, ±1/2)``, so a cell is a square
|
|
16
|
+
turned 45 degrees whose two diagonals are one unit each.
|
|
17
|
+
* Variable ``k`` appears in ``(k, j)`` for ``j > k``, running down-right from
|
|
18
|
+
``(0, k)``, and in ``(i, k)`` for ``i < k``, running up-right to the same
|
|
19
|
+
point. Its pairs are one connected **V** rooted at ``u = 0, v = k`` -- which
|
|
20
|
+
is exactly where its name goes. That is the whole reason for the card: on
|
|
21
|
+
the square one a variable's pairs are a row and a column meeting at a corner.
|
|
22
|
+
* Because item ``k`` sits at ``v = k``, the names stay ordinary y tick labels.
|
|
23
|
+
The ordering, the tick machinery and ``tl.*`` learn nothing new.
|
|
24
|
+
|
|
25
|
+
So the anchor moves. The square card is anchored on the **cell** and bounded
|
|
26
|
+
by the page width; this one is anchored on the **row pitch** -- the label line
|
|
27
|
+
height -- and bounded by the page *height*, since the panel comes out about
|
|
28
|
+
twice as tall as it is wide. Its floor is a different quantity too: below
|
|
29
|
+
``pitch_min`` it is the names that collide, not the marks that stop being
|
|
30
|
+
readable. Two different anchors, two different bounds, two different floors,
|
|
31
|
+
which is why this is its own solver rather than a branch in the other one.
|
|
32
|
+
|
|
33
|
+
Nothing here imports the rest of the Figure runtime, and the measuring
|
|
34
|
+
primitives are shared with ``corr_layout`` rather than copied.
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from __future__ import annotations
|
|
38
|
+
|
|
39
|
+
from dataclasses import dataclass, field
|
|
40
|
+
from typing import Any, Mapping, Sequence
|
|
41
|
+
|
|
42
|
+
from .corr_layout import MM_PER_INCH, _geom, max_label_mm, measure_text_mm
|
|
43
|
+
|
|
44
|
+
__all__ = [
|
|
45
|
+
"DiamondGeometry",
|
|
46
|
+
"diamond_extent",
|
|
47
|
+
"solve_diamond_geometry",
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
#: The two sides the label column may take. ``right`` is the same map with
|
|
51
|
+
#: ``u`` negated; it must never become a second code path.
|
|
52
|
+
SIDES = ("left", "right")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def diamond_extent(n: int, *, diag: bool = False) -> tuple[float, float, float, float]:
|
|
56
|
+
"""``(u_lo, u_hi, v_lo, v_hi)`` of the panel, in cell units.
|
|
57
|
+
|
|
58
|
+
Cell centres run ``u ∈ [1/2, (n-1)/2]`` and ``v ∈ [1/2, n-3/2]`` off the
|
|
59
|
+
diagonal; the panel is those plus the half cell that hangs off each end.
|
|
60
|
+
The v range is then exactly ``[0, n-1]``, which is where labels ``0`` and
|
|
61
|
+
``n-1`` sit -- the first and last name line up with the top and bottom of
|
|
62
|
+
the diamond, as they must.
|
|
63
|
+
|
|
64
|
+
With ``diag`` the self-pairs come in at ``u = 0`` and push both ranges out
|
|
65
|
+
by half a cell.
|
|
66
|
+
|
|
67
|
+
A half, not the quarter the pentagon of
|
|
68
|
+
:func:`corrplot_runtime._self_cell_vertices` actually reaches: that shape
|
|
69
|
+
is how a *fill* keeps a whole cell's area against the edge, and the round
|
|
70
|
+
glyphs do not take it. A circle on the diagonal is a circle, and at the
|
|
71
|
+
quarter it overhung the panel by 0.07 cells -- which is only 0.3 mm, but it
|
|
72
|
+
is 0.3 mm off the one gap the eye checks, the channel between the matrix
|
|
73
|
+
and the names, and it narrowed it on the diagonal rows alone. The panel
|
|
74
|
+
buys the half so that every glyph fits whatever shape it is.
|
|
75
|
+
"""
|
|
76
|
+
n = max(int(n), 2)
|
|
77
|
+
if diag:
|
|
78
|
+
return -0.5, n / 2.0, -0.5, n - 0.5
|
|
79
|
+
return 0.0, n / 2.0, 0.0, float(n - 1)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
@dataclass(frozen=True)
|
|
83
|
+
class DiamondGeometry:
|
|
84
|
+
"""A solved diamond layout, in the units each consumer wants.
|
|
85
|
+
|
|
86
|
+
``pitch_mm`` is the distance from one variable to the next down the label
|
|
87
|
+
column, and it is also the cell's diagonal -- the two are the same number
|
|
88
|
+
by construction, which is what keeps the lattice square.
|
|
89
|
+
|
|
90
|
+
``label_block_mm`` is the band the column was given; ``label_text_mm`` is
|
|
91
|
+
how much of it the names actually occupy. The difference is page margin,
|
|
92
|
+
and the stripes stop at the text rather than bleeding into it.
|
|
93
|
+
|
|
94
|
+
``name_pad_mm`` and ``number_pad_mm`` are how far from the panel's edge the
|
|
95
|
+
two columns of the label band are anchored -- the names' outer edge and the
|
|
96
|
+
numbers' outer edge. Both are anchored on their *outer* edge, which is the
|
|
97
|
+
whole point of the band: a number column is only a column if every number
|
|
98
|
+
starts at the same place, and a ragged inner edge is the price. See the
|
|
99
|
+
``edge_numbers`` branch below.
|
|
100
|
+
|
|
101
|
+
The two ``colorbar_*`` numbers are carried out because the bar's axis label
|
|
102
|
+
is placed in axes fractions of a bar this solve sized: the caller cannot
|
|
103
|
+
turn ``colorbar.label_gap`` into a fraction without knowing the width it is
|
|
104
|
+
a fraction of.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
figsize: tuple[float, float]
|
|
108
|
+
panel_rect: tuple[float, float, float, float]
|
|
109
|
+
colorbar_rect: tuple[float, float, float, float]
|
|
110
|
+
logo_rect: tuple[float, float, float, float]
|
|
111
|
+
xlim: tuple[float, float]
|
|
112
|
+
ylim: tuple[float, float]
|
|
113
|
+
pitch_mm: float
|
|
114
|
+
width_mm: float
|
|
115
|
+
height_mm: float
|
|
116
|
+
label_block_mm: float
|
|
117
|
+
label_text_mm: float
|
|
118
|
+
name_pad_mm: float
|
|
119
|
+
number_pad_mm: float
|
|
120
|
+
number_size_pt: float
|
|
121
|
+
colorbar_w_mm: float
|
|
122
|
+
colorbar_label_gap_mm: float
|
|
123
|
+
side: str
|
|
124
|
+
clamped: bool
|
|
125
|
+
n_cells: int
|
|
126
|
+
notes: list[str] = field(default_factory=list)
|
|
127
|
+
|
|
128
|
+
@property
|
|
129
|
+
def panel_w_mm(self) -> float:
|
|
130
|
+
return self.panel_rect[2] * self.figsize[0] * MM_PER_INCH
|
|
131
|
+
|
|
132
|
+
@property
|
|
133
|
+
def panel_h_mm(self) -> float:
|
|
134
|
+
return self.panel_rect[3] * self.figsize[1] * MM_PER_INCH
|
|
135
|
+
|
|
136
|
+
def as_frame(self) -> dict:
|
|
137
|
+
"""The ``Frame`` fragment this geometry implies.
|
|
138
|
+
|
|
139
|
+
The same three keys the square solver writes, so the caller merges it
|
|
140
|
+
the same way and neither card is a special case downstream.
|
|
141
|
+
"""
|
|
142
|
+
return {
|
|
143
|
+
"figure": {"figsize": list(self.figsize)},
|
|
144
|
+
"axes": {
|
|
145
|
+
"axcorr": {"rect": list(self.panel_rect)},
|
|
146
|
+
"axccorr": {"rect": list(self.colorbar_rect), "xticks": []},
|
|
147
|
+
"axlogo": {"rect": list(self.logo_rect)},
|
|
148
|
+
},
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def solve_diamond_geometry(
|
|
153
|
+
n: int,
|
|
154
|
+
*,
|
|
155
|
+
geometry: Mapping[str, Any],
|
|
156
|
+
labels: Sequence[Any] = (),
|
|
157
|
+
colorbar_labels: Sequence[Any] = (),
|
|
158
|
+
colorbar_title: Any = "",
|
|
159
|
+
side: str = "right",
|
|
160
|
+
diag: bool = False,
|
|
161
|
+
edge_numbers: bool = False,
|
|
162
|
+
label_size_pt: float = 6.0,
|
|
163
|
+
label_pad_mm: float = 0.0,
|
|
164
|
+
number_size_pt: float = 4.2,
|
|
165
|
+
colorbar_label_size_pt: float = 5.5,
|
|
166
|
+
colorbar_tick_pad_mm: float = 0.6,
|
|
167
|
+
colorbar_title_size_pt: float = 7.0,
|
|
168
|
+
family: str = "sans",
|
|
169
|
+
) -> DiamondGeometry:
|
|
170
|
+
"""Solve the figure size and axes rects for an ``n`` variable diamond.
|
|
171
|
+
|
|
172
|
+
``labels`` are printed horizontally in a column of their own, so what they
|
|
173
|
+
cost is their width -- once, in a band that has to exist anyway -- rather
|
|
174
|
+
than a rotated tick label under every cell.
|
|
175
|
+
"""
|
|
176
|
+
n = max(int(n), 2)
|
|
177
|
+
side = str(side or "left").strip().lower()
|
|
178
|
+
if side not in SIDES:
|
|
179
|
+
raise ValueError(
|
|
180
|
+
"corrplot side must be one of {}; got {!r}. It mirrors the figure: "
|
|
181
|
+
"the names go on that side and the colorbar on the other.".format(
|
|
182
|
+
", ".join(SIDES), side
|
|
183
|
+
)
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
pitch = _geom(geometry, "pitch", default=4.2)
|
|
187
|
+
pitch_min = _geom(geometry, "pitch_min", default=2.6)
|
|
188
|
+
max_width = _geom(geometry, "max_width", default=170.0)
|
|
189
|
+
max_height = _geom(geometry, "max_height", default=247.0)
|
|
190
|
+
m_left = _geom(geometry, "margin", "left", default=11.0)
|
|
191
|
+
m_right = _geom(geometry, "margin", "right", default=11.0)
|
|
192
|
+
m_top = _geom(geometry, "margin", "top", default=4.0)
|
|
193
|
+
m_bottom = _geom(geometry, "margin", "bottom", default=11.0)
|
|
194
|
+
margin = (geometry.get("margin") or {}) if isinstance(geometry, Mapping) else {}
|
|
195
|
+
fit = bool(margin.get("fit", False))
|
|
196
|
+
fit_slack = _geom(geometry, "margin", "slack", default=1.0)
|
|
197
|
+
label_gap = _geom(geometry, "labels", "gap", default=1.4)
|
|
198
|
+
number_gap = _geom(geometry, "labels", "number_gap", default=1.0)
|
|
199
|
+
# `labels.width: null` means measured. An author states it when two
|
|
200
|
+
# figures have to line up down the page and the names differ.
|
|
201
|
+
authored_column = _geom(geometry, "labels", "width", default=0.0)
|
|
202
|
+
cb_w = _geom(geometry, "colorbar", "width", default=2.6)
|
|
203
|
+
# A fraction of the panel's height, not a length in mm: the bar is a key to
|
|
204
|
+
# the panel beside it, so it should keep the same visual weight against a
|
|
205
|
+
# 13-variable matrix and a 40-variable one.
|
|
206
|
+
cb_len = _geom(geometry, "colorbar", "length", default=0.22)
|
|
207
|
+
# ... and how far its outer edge stands in from the edge of the paper.
|
|
208
|
+
cb_offset = _geom(geometry, "colorbar", "offset", default=10.0)
|
|
209
|
+
# ... and how far its own axis label stands off its inward edge.
|
|
210
|
+
cb_label_gap = _geom(geometry, "colorbar", "label_gap", default=1.5)
|
|
211
|
+
logo_w = _geom(geometry, "logo", "width", default=5.0)
|
|
212
|
+
logo_h = _geom(geometry, "logo", "height", default=5.0)
|
|
213
|
+
logo_off = _geom(geometry, "logo", "offset", default=0.838)
|
|
214
|
+
logo_corner = str(
|
|
215
|
+
(geometry.get("logo") or {}).get("corner", "far")
|
|
216
|
+
if isinstance(geometry, Mapping) else "far"
|
|
217
|
+
).strip().lower()
|
|
218
|
+
|
|
219
|
+
notes: list[str] = []
|
|
220
|
+
|
|
221
|
+
# --- the two bands beside the panel ------------------------------------
|
|
222
|
+
#
|
|
223
|
+
# The names are the whole point of this layout, so the column that holds
|
|
224
|
+
# them is measured, not guessed: `pad + widest name + gap`, which is where
|
|
225
|
+
# the text actually ends. `labels.width` overrides it for an author who
|
|
226
|
+
# wants two figures to line up; `margin.fit` is what lets it grow past the
|
|
227
|
+
# page margin, exactly as on the square card.
|
|
228
|
+
name_width = max_label_mm(labels, size_pt=label_size_pt, family=family)
|
|
229
|
+
# With `edge.numbers` the band is two columns, not one: the position, then
|
|
230
|
+
# the name. They are separate because they are set differently -- the
|
|
231
|
+
# number in the smaller, lighter face the same number wears out on the
|
|
232
|
+
# diagonal -- and a tick label is one string in one colour. Splitting them
|
|
233
|
+
# is also what lets the numbers line up: each column is anchored on its own
|
|
234
|
+
# outer edge, so the numbers make a column and the names hang off it.
|
|
235
|
+
number_width = (
|
|
236
|
+
max_label_mm(
|
|
237
|
+
[str(k + 1).zfill(len(str(n))) for k in range(n)],
|
|
238
|
+
size_pt=number_size_pt, family=family,
|
|
239
|
+
)
|
|
240
|
+
if edge_numbers and labels
|
|
241
|
+
else 0.0
|
|
242
|
+
)
|
|
243
|
+
number_block = (number_width + number_gap) if number_width else 0.0
|
|
244
|
+
name_pad = label_pad_mm + name_width
|
|
245
|
+
number_pad = name_pad + number_block
|
|
246
|
+
label_need = number_pad + label_gap
|
|
247
|
+
if authored_column:
|
|
248
|
+
label_block = authored_column
|
|
249
|
+
if label_need > label_block:
|
|
250
|
+
notes.append(
|
|
251
|
+
"labels.width is {:.1f} mm and the names need {:.1f} mm, so "
|
|
252
|
+
"they print past it.".format(label_block, label_need)
|
|
253
|
+
)
|
|
254
|
+
elif fit:
|
|
255
|
+
label_block = max(m_left if side == "left" else m_right, label_need + fit_slack)
|
|
256
|
+
else:
|
|
257
|
+
label_block = m_left if side == "left" else m_right
|
|
258
|
+
if label_need > label_block:
|
|
259
|
+
notes.append(
|
|
260
|
+
"the names need {:.1f} mm and the margin is {:.1f} mm, so they "
|
|
261
|
+
"print past it. margin.fit: true grows it instead.".format(
|
|
262
|
+
label_need, label_block
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
|
|
266
|
+
# The colorbar does not stand beside the panel on this card. Turning the
|
|
267
|
+
# matrix leaves a right-angled triangle of empty page above it -- as big as
|
|
268
|
+
# the matrix itself -- and a bar parked outside the panel would pay for a
|
|
269
|
+
# band of width twice over, once for itself and once for the hole. So it
|
|
270
|
+
# goes in the hole, the way a ternary card puts its bar in the corner
|
|
271
|
+
# beside the triangle. The figure is then the names plus the panel, and
|
|
272
|
+
# nothing else.
|
|
273
|
+
cblab = max_label_mm(colorbar_labels, size_pt=colorbar_label_size_pt, family=family)
|
|
274
|
+
cbtitle_w, cbtitle_h = (
|
|
275
|
+
measure_text_mm(colorbar_title, size_pt=colorbar_title_size_pt, family=family)
|
|
276
|
+
if colorbar_title
|
|
277
|
+
else (0.0, 0.0)
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# The square card floors its bottom-left margin at the badge, because there
|
|
281
|
+
# a cell of the matrix reaches that corner. Here nothing does: the last
|
|
282
|
+
# variable's only cell sits at u = 1/2 and the whole lower corner of the
|
|
283
|
+
# panel's box is empty by construction, so the mark can sit in a 4 mm
|
|
284
|
+
# margin without anything to collide with. The `axlogo` offset is still
|
|
285
|
+
# the house one; it is only the *floor* that does not apply.
|
|
286
|
+
#
|
|
287
|
+
# Top and bottom are then the same band. Nothing prints above the matrix
|
|
288
|
+
# and nothing below it, so an asymmetric pair would read as a figure
|
|
289
|
+
# sitting crookedly on the page rather than as a title band doing
|
|
290
|
+
# something.
|
|
291
|
+
bottom_block = m_bottom
|
|
292
|
+
top_block = m_top
|
|
293
|
+
far_block = m_right if side == "left" else m_left
|
|
294
|
+
|
|
295
|
+
left_block, right_block = (
|
|
296
|
+
(label_block, far_block) if side == "left" else (far_block, label_block)
|
|
297
|
+
)
|
|
298
|
+
|
|
299
|
+
# --- the pitch, and the two page bounds --------------------------------
|
|
300
|
+
u_lo, u_hi, v_lo, v_hi = diamond_extent(n, diag=diag)
|
|
301
|
+
u_span, v_span = u_hi - u_lo, v_hi - v_lo
|
|
302
|
+
|
|
303
|
+
# Height binds first on any matrix worth drawing this way -- the panel is
|
|
304
|
+
# about twice as tall as it is wide -- but both are checked, because a
|
|
305
|
+
# figure that fits the page vertically and runs off it sideways is just as
|
|
306
|
+
# useless. The pitch is what gives; the font never does, for the same
|
|
307
|
+
# reason as on the square card.
|
|
308
|
+
clamped = False
|
|
309
|
+
room_h = (max_height - bottom_block - top_block) / v_span
|
|
310
|
+
room_w = (max_width - left_block - right_block) / u_span
|
|
311
|
+
bound, room = ("height", room_h) if room_h <= room_w else ("width", room_w)
|
|
312
|
+
if room < pitch:
|
|
313
|
+
clamped = True
|
|
314
|
+
if room < pitch_min:
|
|
315
|
+
over = (
|
|
316
|
+
bottom_block + v_span * pitch_min + top_block - max_height
|
|
317
|
+
if bound == "height"
|
|
318
|
+
else left_block + u_span * pitch_min + right_block - max_width
|
|
319
|
+
)
|
|
320
|
+
notes.append(
|
|
321
|
+
"{} variables do not fit {:.0f} mm of {} at the minimum row "
|
|
322
|
+
"pitch ({:.2f} mm needed, {:.2f} mm floor). The figure keeps "
|
|
323
|
+
"the floor and overruns the page by {:.1f} mm. Below the floor "
|
|
324
|
+
"the names collide, so the only real fixes are fewer variables "
|
|
325
|
+
"or a taller page.".format(
|
|
326
|
+
n,
|
|
327
|
+
max_height if bound == "height" else max_width,
|
|
328
|
+
bound, room, pitch_min, over,
|
|
329
|
+
)
|
|
330
|
+
)
|
|
331
|
+
pitch = pitch_min
|
|
332
|
+
else:
|
|
333
|
+
notes.append(
|
|
334
|
+
"{} pinned to {:.0f} mm: row pitch {:.2f} -> {:.2f} mm ({} "
|
|
335
|
+
"variables). Font sizes are unchanged.".format(
|
|
336
|
+
bound,
|
|
337
|
+
max_height if bound == "height" else max_width,
|
|
338
|
+
pitch, room, n,
|
|
339
|
+
)
|
|
340
|
+
)
|
|
341
|
+
pitch = room
|
|
342
|
+
|
|
343
|
+
panel_w = u_span * pitch
|
|
344
|
+
panel_h = v_span * pitch
|
|
345
|
+
width = left_block + panel_w + right_block
|
|
346
|
+
height = bottom_block + panel_h + top_block
|
|
347
|
+
|
|
348
|
+
# --- fractions, in the order add_axes wants them -----------------------
|
|
349
|
+
panel_rect = (
|
|
350
|
+
left_block / width,
|
|
351
|
+
bottom_block / height,
|
|
352
|
+
panel_w / width,
|
|
353
|
+
panel_h / height,
|
|
354
|
+
)
|
|
355
|
+
|
|
356
|
+
# The bar, inside the empty triangle. Two things fix it: its top is the
|
|
357
|
+
# panel's top -- a key that starts where the thing it explains starts reads
|
|
358
|
+
# as belonging to it, and a bar floating below the top edge reads as having
|
|
359
|
+
# drifted -- and its outer edge stands `colorbar.offset` in from the paper.
|
|
360
|
+
bar_len = cb_len * panel_h
|
|
361
|
+
bar_x = (
|
|
362
|
+
width - cb_offset - cb_w if side == "left" else cb_offset
|
|
363
|
+
)
|
|
364
|
+
bar_top = bottom_block + panel_h
|
|
365
|
+
|
|
366
|
+
# The panel's upper boundary is the line `v = u - 1/2` (the first
|
|
367
|
+
# variable's cells), so the headroom above the matrix grows with distance
|
|
368
|
+
# from the label column. Under the bar's *near* edge that headroom is what
|
|
369
|
+
# the bar has to fit in -- less the numbers, when they are printed along
|
|
370
|
+
# that diagonal.
|
|
371
|
+
def _u_of(x_mm: float) -> float:
|
|
372
|
+
return (
|
|
373
|
+
(x_mm - left_block) if side == "left" else (left_block + panel_w - x_mm)
|
|
374
|
+
) / pitch
|
|
375
|
+
|
|
376
|
+
near = bar_x if side == "left" else bar_x + cb_w
|
|
377
|
+
inward = -1.0 if side == "left" else 1.0
|
|
378
|
+
# Half a cell is the diagonal's own overhang. The edge numbers add their
|
|
379
|
+
# offset plus half their height, and a perpendicular offset costs sqrt(2)
|
|
380
|
+
# as much measured straight down; 1.2 covers the card's own setting.
|
|
381
|
+
clearance = (1.2 if edge_numbers else 0.5) * pitch
|
|
382
|
+
|
|
383
|
+
def _head(reach_mm: float, allow: float) -> float:
|
|
384
|
+
"""Page above the matrix, ``reach_mm`` inside the bar's near edge."""
|
|
385
|
+
return (_u_of(near + inward * reach_mm) - 0.5) * pitch - allow
|
|
386
|
+
|
|
387
|
+
def _fits(reach_mm: float, half_extent_mm) -> float:
|
|
388
|
+
"""How long the bar may be with something standing ``reach_mm`` inside.
|
|
389
|
+
|
|
390
|
+
``half_extent_mm`` is half of what that something occupies *along* the
|
|
391
|
+
bar, or ``None`` for text running its whole length. A wall clears the
|
|
392
|
+
diagonal only when the bar's own bottom does; a single line at the
|
|
393
|
+
bar's mid height only needs half the bar plus half itself to.
|
|
394
|
+
"""
|
|
395
|
+
head = _head(reach_mm, clearance)
|
|
396
|
+
return head if half_extent_mm is None else 2.0 * (head - half_extent_mm)
|
|
397
|
+
|
|
398
|
+
# The numbers print on the bar's left and the label on its right, whichever
|
|
399
|
+
# way the figure is mirrored -- so *which* of them stands between the bar
|
|
400
|
+
# and the diagonal depends on the mirror, and the two are obstructions of
|
|
401
|
+
# different shapes. The numbers are a column as tall as the bar: a wall.
|
|
402
|
+
# The label is one line at its mid height, turned on its side, so what it
|
|
403
|
+
# reaches inward by is its line height and what it takes up along the bar
|
|
404
|
+
# is its text width.
|
|
405
|
+
numbers = (colorbar_tick_pad_mm + cblab, None) if cblab else None
|
|
406
|
+
title = (cb_label_gap + cbtitle_h, cbtitle_w / 2.0) if cbtitle_h else None
|
|
407
|
+
inward_text, outward_text = (
|
|
408
|
+
(numbers, title) if side == "left" else (title, numbers)
|
|
409
|
+
)
|
|
410
|
+
# These three are *measurements*, not limits. The bar's top, length and
|
|
411
|
+
# offset are the author's three numbers and the solve realises them; what
|
|
412
|
+
# it does here is say when they are tight, not quietly pick others. An
|
|
413
|
+
# earlier version shortened the bar to fit its own clearance allowance and
|
|
414
|
+
# so drew a figure that did not have the length it was asked for -- which
|
|
415
|
+
# is a worse fault than a tight one, because nothing on the page says so.
|
|
416
|
+
cells = _head(0.0, 0.0)
|
|
417
|
+
if bar_len > cells:
|
|
418
|
+
notes.append(
|
|
419
|
+
"the colorbar is {:.1f} mm and only {:.1f} mm of page stands above "
|
|
420
|
+
"the matrix under it, so it is drawn across the cells. A smaller "
|
|
421
|
+
"colorbar.length, or a smaller colorbar.offset -- which moves the "
|
|
422
|
+
"bar out toward the paper, where the triangle is taller -- clears "
|
|
423
|
+
"them.".format(bar_len, max(cells, 0.0))
|
|
424
|
+
)
|
|
425
|
+
elif inward_text is not None and bar_len > _fits(*inward_text):
|
|
426
|
+
notes.append(
|
|
427
|
+
"the colorbar clears the matrix, but the text on its inward side "
|
|
428
|
+
"comes within a cell of the diagonal. A smaller colorbar.offset "
|
|
429
|
+
"moves the bar out toward the paper, where the triangle is taller."
|
|
430
|
+
)
|
|
431
|
+
# ... and whatever is on the other side has the page margin to live in.
|
|
432
|
+
if outward_text is not None and outward_text[0] > cb_offset:
|
|
433
|
+
notes.append(
|
|
434
|
+
"the text on the outer side of the colorbar needs {:.1f} mm and "
|
|
435
|
+
"only {:.1f} mm of paper stands there, so it prints past the page "
|
|
436
|
+
"edge. A larger colorbar.offset moves the bar in.".format(
|
|
437
|
+
outward_text[0], cb_offset
|
|
438
|
+
)
|
|
439
|
+
)
|
|
440
|
+
colorbar_rect = (
|
|
441
|
+
bar_x / width,
|
|
442
|
+
(bar_top - bar_len) / height,
|
|
443
|
+
cb_w / width,
|
|
444
|
+
bar_len / height,
|
|
445
|
+
)
|
|
446
|
+
# The badge keeps the house offset -- 0.838 mm off two edges -- but not
|
|
447
|
+
# necessarily the *left* two. The corner beside the names is the one place
|
|
448
|
+
# on this card where something already is: the last variable's row sits on
|
|
449
|
+
# the panel's bottom edge and the lower run of numbers ends just inside it.
|
|
450
|
+
# The far corner is empty by construction, because the last variable's only
|
|
451
|
+
# cell is at u = 1/2. `logo.corner: bottom-left` puts it back.
|
|
452
|
+
logo_x = logo_off
|
|
453
|
+
if (logo_corner == "far" and side == "left") or logo_corner == "bottom-right":
|
|
454
|
+
logo_x = width - logo_off - logo_w
|
|
455
|
+
logo_rect = (
|
|
456
|
+
logo_x / width,
|
|
457
|
+
logo_off / height,
|
|
458
|
+
logo_w / width,
|
|
459
|
+
logo_h / height,
|
|
460
|
+
)
|
|
461
|
+
|
|
462
|
+
# `u` is negated for a right-hand column, so the triangle opens the other
|
|
463
|
+
# way and the names still sit against the panel's own edge. This is the
|
|
464
|
+
# entire difference between the two sides.
|
|
465
|
+
xlim = (u_lo, u_hi) if side == "left" else (-u_hi, -u_lo)
|
|
466
|
+
# Item 0 at the top, as on the square card and for the same reason: a
|
|
467
|
+
# matrix is read from its first row down.
|
|
468
|
+
ylim = (v_hi, v_lo)
|
|
469
|
+
|
|
470
|
+
return DiamondGeometry(
|
|
471
|
+
figsize=(width / MM_PER_INCH, height / MM_PER_INCH),
|
|
472
|
+
panel_rect=panel_rect,
|
|
473
|
+
colorbar_rect=colorbar_rect,
|
|
474
|
+
logo_rect=logo_rect,
|
|
475
|
+
xlim=xlim,
|
|
476
|
+
ylim=ylim,
|
|
477
|
+
pitch_mm=pitch,
|
|
478
|
+
width_mm=width,
|
|
479
|
+
height_mm=height,
|
|
480
|
+
label_block_mm=label_block,
|
|
481
|
+
label_text_mm=min(label_need, label_block),
|
|
482
|
+
name_pad_mm=name_pad,
|
|
483
|
+
number_pad_mm=number_pad,
|
|
484
|
+
number_size_pt=number_size_pt,
|
|
485
|
+
colorbar_w_mm=cb_w,
|
|
486
|
+
colorbar_label_gap_mm=cb_label_gap,
|
|
487
|
+
side=side,
|
|
488
|
+
clamped=clamped,
|
|
489
|
+
n_cells=n,
|
|
490
|
+
notes=notes,
|
|
491
|
+
)
|