jarvisplot 2.1.7__tar.gz → 2.1.9__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.
Files changed (286) hide show
  1. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/JarvisPLOT.egg-info/PKG-INFO +40 -1
  2. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/JarvisPLOT.egg-info/SOURCES.txt +19 -0
  3. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/PKG-INFO +40 -1
  4. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/README.md +39 -0
  5. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/config_runtime.py +3 -1
  6. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/debug_config.py +7 -0
  7. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/design_runtime.py +4 -0
  8. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/figure.py +31 -7
  9. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/figure_types.py +10 -1
  10. jarvisplot-2.1.9/jarvisplot/Figure/forest_debug.py +35 -0
  11. jarvisplot-2.1.9/jarvisplot/Figure/forest_legend.py +88 -0
  12. jarvisplot-2.1.9/jarvisplot/Figure/forest_runtime.py +294 -0
  13. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/layer_runtime.py +1 -1
  14. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/legend_runtime.py +3 -3
  15. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/preprocessor.py +28 -1
  16. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/preprocessor_runtime.py +27 -5
  17. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/style_runtime.py +14 -0
  18. jarvisplot-2.1.9/jarvisplot/cache_registry.py +346 -0
  19. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cache_store.py +78 -8
  20. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/capabilities.py +7 -0
  21. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/args.json +13 -2
  22. jarvisplot-2.1.9/jarvisplot/cards/forest/swiss_column.json +196 -0
  23. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/style_preference.json +3 -0
  24. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/column_demand.py +41 -0
  25. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/core.py +57 -7
  26. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/core_runtime.py +203 -43
  27. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/data_access.py +15 -15
  28. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/data_loader.py +45 -2
  29. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/data_loader_hdf5.py +0 -2
  30. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/data_loader_runtime.py +69 -20
  31. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/dryrun_runtime.py +62 -0
  32. jarvisplot-2.1.9/jarvisplot/forest_contract.py +436 -0
  33. jarvisplot-2.1.9/jarvisplot/forest_text.py +86 -0
  34. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/legend_cards.py +2 -2
  35. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/man_render_agent.py +7 -0
  36. jarvisplot-2.1.9/jarvisplot/manual_cards/cache.yaml +57 -0
  37. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/cli-map.yaml +3 -1
  38. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/manifest.yaml +3 -0
  39. jarvisplot-2.1.9/jarvisplot/manual_cards/type-forest.yaml +244 -0
  40. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/core/figure.json +297 -3
  41. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/manifest.json +5 -2
  42. jarvisplot-2.1.9/jarvisplot/schema/types/forest.json +824 -0
  43. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/templates_catalog.py +18 -0
  44. jarvisplot-2.1.9/jarvisplot/utils/expression.py +425 -0
  45. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/validation.py +40 -2
  46. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/__init__.py +1 -0
  47. jarvisplot-2.1.9/jarvisplot/verbs/cache.py +179 -0
  48. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/config_cmd.py +9 -2
  49. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/doctor.py +1 -0
  50. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/pyproject.toml +1 -1
  51. jarvisplot-2.1.9/tests/test_add_column.py +58 -0
  52. jarvisplot-2.1.9/tests/test_cache_cleanup.py +75 -0
  53. jarvisplot-2.1.9/tests/test_cache_registry.py +455 -0
  54. jarvisplot-2.1.9/tests/test_column_pruning.py +251 -0
  55. jarvisplot-2.1.9/tests/test_examples_validate.py +29 -0
  56. jarvisplot-2.1.9/tests/test_expression_semantics.py +185 -0
  57. jarvisplot-2.1.9/tests/test_forest.py +619 -0
  58. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_parse_data_metadata.py +75 -0
  59. jarvisplot-2.1.9/tests/test_render_lifecycle.py +175 -0
  60. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_template_catalog.py +7 -0
  61. jarvisplot-2.1.7/jarvisplot/utils/expression.py +0 -125
  62. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/JarvisPLOT.egg-info/dependency_links.txt +0 -0
  63. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/JarvisPLOT.egg-info/entry_points.txt +0 -0
  64. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/JarvisPLOT.egg-info/requires.txt +0 -0
  65. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/JarvisPLOT.egg-info/top_level.txt +0 -0
  66. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/__init__.py +0 -0
  67. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/adapters_rect.py +0 -0
  68. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/adapters_ternary.py +0 -0
  69. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/adaptive_cdf_runtime.py +0 -0
  70. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/bin_stat_runtime.py +0 -0
  71. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/cards/std_axes_adapter_config.json +0 -0
  72. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/colorbar_runtime.py +0 -0
  73. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/corr_layout.py +0 -0
  74. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/corr_layout_diamond.py +0 -0
  75. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/corr_order.py +0 -0
  76. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/correlation_runtime.py +0 -0
  77. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/corrplot_runtime.py +0 -0
  78. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/data_pipelines.py +0 -0
  79. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/density_cell_runtime.py +0 -0
  80. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/distribution_1d_runtime.py +0 -0
  81. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/dynesty_runtime.py +0 -0
  82. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/helper.py +0 -0
  83. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/interp_2d_runtime.py +0 -0
  84. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/interp_natural_neighbor.py +0 -0
  85. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/interp_natural_neighbor_exact.py +0 -0
  86. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/layout_runtime.py +0 -0
  87. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/method_registry.py +0 -0
  88. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/posterior_density_runtime.py +0 -0
  89. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/posterior_hpd.py +0 -0
  90. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/posterior_mesh.py +0 -0
  91. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/profile_runtime.py +0 -0
  92. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/Figure/significance_runtime.py +0 -0
  93. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/__init__.py +0 -0
  94. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/agent_digest.py +0 -0
  95. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/agent_io.py +0 -0
  96. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/1x1/ternary.json +0 -0
  97. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/2x1/dynesty_runplot.json +0 -0
  98. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/2x1/rect.json +0 -0
  99. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/2x1/rect5x1.json +0 -0
  100. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/2x1/rect_cmap.json +0 -0
  101. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/2x1/rect_marginal.json +0 -0
  102. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/2x1/rectratio.json +0 -0
  103. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/2x1/ternary.json +0 -0
  104. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/2x1/ternary_cmap.json +0 -0
  105. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/4x1/rect.json +0 -0
  106. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/4x1/rect_cmap.json +0 -0
  107. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/4x1/ternary.json +0 -0
  108. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/a4paper/4x1/ternary_cmap.json +0 -0
  109. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/colors/colormaps.json +0 -0
  110. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/corrplot/diamond.json +0 -0
  111. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/corrplot/matrix.json +0 -0
  112. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/default/output.json +0 -0
  113. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/flowchart/default.json +0 -0
  114. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/gambit/1x1/ternary.json +0 -0
  115. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/gambit/2x1/rect_cmap.json +0 -0
  116. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/gambit/2x1/ternary.json +0 -0
  117. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/gambit/2x1/ternary_cmap.json +0 -0
  118. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/icons/JarvisHEP.png +0 -0
  119. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/icons/flowchart/JarvisHEP.png +0 -0
  120. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/icons/flowchart/calculator.png +0 -0
  121. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/icons/flowchart/inputfile.png +0 -0
  122. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/icons/flowchart/opera.png +0 -0
  123. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/icons/flowchart/outputfile.png +0 -0
  124. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/icons/flowchart/sampler.png +0 -0
  125. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/icons/gambit.png +0 -0
  126. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/icons/gambit_small.png +0 -0
  127. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/legends/compact/legend-card.json +0 -0
  128. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/legends/default/legend-card.json +0 -0
  129. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/legends/paper/legend-card.json +0 -0
  130. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cards/legends/presentation/legend-card.json +0 -0
  131. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cli.py +0 -0
  132. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/cli_help.py +0 -0
  133. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/client.py +0 -0
  134. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/column_probe.py +0 -0
  135. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/config.py +0 -0
  136. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/config_address.py +0 -0
  137. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/core_assets.py +0 -0
  138. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/data_generation_contracts.py +0 -0
  139. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/data_loader_summary.py +0 -0
  140. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/dataset_types.py +0 -0
  141. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/diagnostic_guidance.py +0 -0
  142. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/diagnostics.py +0 -0
  143. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/distribution_1d_config.py +0 -0
  144. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/expr_names.py +0 -0
  145. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/fix_apply.py +0 -0
  146. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/flowchart.py +0 -0
  147. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/generated_data.py +0 -0
  148. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/inner_func.py +0 -0
  149. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/man_catalog.py +0 -0
  150. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/man_methods.py +0 -0
  151. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/man_render_human.py +0 -0
  152. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/man_transforms.py +0 -0
  153. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/agent-output.yaml +0 -0
  154. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/data-columns.yaml +0 -0
  155. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/debug-overlay.yaml +0 -0
  156. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/diagnostics.yaml +0 -0
  157. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/dryrun-viz.yaml +0 -0
  158. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/field-interp.yaml +0 -0
  159. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/generated-data.yaml +0 -0
  160. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/layer-method.yaml +0 -0
  161. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/legend.yaml +0 -0
  162. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/method_notes.yaml +0 -0
  163. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/style-axes.yaml +0 -0
  164. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/type-correlation-matrix.yaml +0 -0
  165. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/type-posterior-2d.yaml +0 -0
  166. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/type-profile-2d.yaml +0 -0
  167. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/validate.yaml +0 -0
  168. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/workflow.yaml +0 -0
  169. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/manual_cards/yaml-root.yaml +0 -0
  170. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/memtrace.py +0 -0
  171. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/method_contracts.py +0 -0
  172. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/render_health.py +0 -0
  173. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/core/common.json +0 -0
  174. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/core/dataset.json +0 -0
  175. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/core/distribution-1d.json +0 -0
  176. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/core/generated-data.json +0 -0
  177. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/core/layer.json +0 -0
  178. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/core/legend-card.json +0 -0
  179. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/core/legend.json +0 -0
  180. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/core/transform.json +0 -0
  181. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/bar.json +0 -0
  182. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/barh.json +0 -0
  183. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/contour.json +0 -0
  184. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/contourf.json +0 -0
  185. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/corrplot.json +0 -0
  186. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/dynesty_runplot.json +0 -0
  187. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/errorbar.json +0 -0
  188. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/fill.json +0 -0
  189. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/fill_between.json +0 -0
  190. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/fill_betweenx.json +0 -0
  191. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/hist.json +0 -0
  192. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/hist2d.json +0 -0
  193. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/imshow.json +0 -0
  194. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/jpcontour.json +0 -0
  195. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/jpcontourf.json +0 -0
  196. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/jpfield.json +0 -0
  197. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/pcolor.json +0 -0
  198. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/pcolormesh.json +0 -0
  199. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/plot.json +0 -0
  200. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/quiver.json +0 -0
  201. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/scatter.json +0 -0
  202. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/stairs.json +0 -0
  203. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/step.json +0 -0
  204. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/tricontour.json +0 -0
  205. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/tricontourf.json +0 -0
  206. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/tripcolor.json +0 -0
  207. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/tripcolor_axes.json +0 -0
  208. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/triplot.json +0 -0
  209. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/voronoi.json +0 -0
  210. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/methods/voronoif.json +0 -0
  211. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema/plot-config.json +0 -0
  212. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema_catalog.py +0 -0
  213. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/schema_diagnostics.py +0 -0
  214. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/transform_contracts.py +0 -0
  215. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/utils/__init__.py +0 -0
  216. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/utils/cmaps.py +0 -0
  217. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/utils/dataframes.py +0 -0
  218. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/utils/interpolator.py +0 -0
  219. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/utils/pathing.py +0 -0
  220. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/cap.py +0 -0
  221. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/data.py +0 -0
  222. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/dryrun.py +0 -0
  223. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/explain.py +0 -0
  224. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/man.py +0 -0
  225. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/suggest.py +0 -0
  226. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/template.py +0 -0
  227. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/verbs/validate.py +0 -0
  228. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/jarvisplot/yaml_io.py +0 -0
  229. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/setup.cfg +0 -0
  230. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_adaptive_cdf.py +0 -0
  231. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_agent_digest.py +0 -0
  232. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_agent_envelope.py +0 -0
  233. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_axis_title.py +0 -0
  234. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_capabilities.py +0 -0
  235. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_card_debug_shape.py +0 -0
  236. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_cli_help.py +0 -0
  237. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_cli_verbs.py +0 -0
  238. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_cmaps.py +0 -0
  239. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_column_existence.py +0 -0
  240. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_config_addressing.py +0 -0
  241. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_config_edit.py +0 -0
  242. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_config_expand.py +0 -0
  243. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_correlation_runtime.py +0 -0
  244. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_corrplot.py +0 -0
  245. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_data_access.py +0 -0
  246. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_data_describe.py +0 -0
  247. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_data_head_eval.py +0 -0
  248. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_data_loader_contracts.py +0 -0
  249. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_data_pipelines.py +0 -0
  250. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_debug_config.py +0 -0
  251. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_debug_switches.py +0 -0
  252. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_debug_yaml_override.py +0 -0
  253. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_density_cell_transform.py +0 -0
  254. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_design_runtime.py +0 -0
  255. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_diagnostic_guidance.py +0 -0
  256. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_distribution_1d_transform.py +0 -0
  257. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_docs_status_labels.py +0 -0
  258. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_doctor_partial.py +0 -0
  259. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_explain.py +0 -0
  260. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_figure_contracts.py +0 -0
  261. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_figure_type_expander.py +0 -0
  262. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_fix_application.py +0 -0
  263. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_flowchart_renderer.py +0 -0
  264. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_generated_data.py +0 -0
  265. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_imshow_adapter.py +0 -0
  266. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_interp_2d_transform.py +0 -0
  267. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_interp_natural_neighbor.py +0 -0
  268. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_interpolator_contracts.py +0 -0
  269. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_jpcontour_methods.py +0 -0
  270. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_layer_legend.py +0 -0
  271. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_legend_cards.py +0 -0
  272. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_legend_runtime.py +0 -0
  273. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_man_cli.py +0 -0
  274. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_method_contracts.py +0 -0
  275. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_pathing_contracts.py +0 -0
  276. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_posterior_hpd.py +0 -0
  277. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_profile_runtime.py +0 -0
  278. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_render_health.py +0 -0
  279. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_row_ledger.py +0 -0
  280. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_schema_catalog.py +0 -0
  281. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_suggest.py +0 -0
  282. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_suggest_axes.py +0 -0
  283. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_template_json.py +0 -0
  284. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_ternary_debug.py +0 -0
  285. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_transform_contracts.py +0 -0
  286. {jarvisplot-2.1.7 → jarvisplot-2.1.9}/tests/test_validate_no_matplotlib.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: JarvisPLOT
3
- Version: 2.1.7
3
+ Version: 2.1.9
4
4
  Summary: Jarvis-PLOT: YAML-driven plotting engine
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -66,6 +66,7 @@ Render with a bare path — there is no `jplot run`:
66
66
  ```bash
67
67
  jplot path/to/config.yaml
68
68
  jplot path/to/config.yaml --rebuild-cache
69
+ jplot path/to/config.yaml --print
69
70
  ```
70
71
 
71
72
  Everything else is discovery and judgement, in three groups.
@@ -218,9 +219,45 @@ from jarvisplot import render_flowchart, render_flowchart_file
218
219
  - You can set `project.workdir` in YAML.
219
220
  - If `output.dir` is omitted, Jarvis-PLOT defaults to `<workdir>/plots/`.
220
221
  - Data cache is stored in `<workdir>/.cache/`.
222
+ - `--print` accepts the current settings and renders final figures without the logo. It announces that, after all enabled figures are saved successfully, cache payloads used or created by this run will be deleted (pipeline data and metadata, named/shared data, summaries, and HDF5 materialization slots). Rendering failures or a run with no enabled figures keep the cache. Unrelated cache entries and the lightweight fingerprint manifest are retained; later renders rebuild deleted entries as needed.
221
223
  - Profiling pipelines are prebuilt once and reused from cache when source fingerprint and profile settings are unchanged.
222
224
  - Profiling uses a fast two-stage grid reduction (`pregrid` + render `bin`) for large datasets.
223
225
 
226
+ Plot caches are automatically registered in `~/.jarvis/plot.json` (or
227
+ `$JARVIS_HOME/plot.json`). The registry groups caches by workdir and records
228
+ associated YAML paths and last use; payloads stay in their original directories.
229
+ This includes caches created by `data describe` and default `dryrun --with-data`
230
+ exports. Sizes are calculated when listing, rather than stored in the registry.
231
+
232
+ ```bash
233
+ jplot cache list
234
+ jplot cache scan ~/Jarvis-Workshop # register existing plot caches
235
+ jplot cache clean --workdir /path/to/project # this directory and all nested projects; repeatable
236
+ jplot cache clean --all --older-than 30 # unused for at least 30 days
237
+ jplot cache clean --all --dry-run # preview; no deletion/index changes
238
+ jplot cache clean --all # clean all registered inactive caches
239
+ jplot cache -h
240
+ jplot man cache
241
+ ```
242
+
243
+ `--workdir PATH` selects registered caches in PATH itself and all of its
244
+ subdirectories, even when PATH has no cache of its own. Repeat it to select
245
+ multiple directory trees; overlapping selections are deduplicated. Use
246
+ `cache scan PATH` first for old caches that have not been registered.
247
+
248
+ All cache subcommands accept `--json` and use the existing CLI envelope and
249
+ exit codes (0 success/partial, 1 failure, 2 usage). Non-TTY stdout defaults to
250
+ JSON; human results go to stderr. Active caches are skipped (`ok: null` when
251
+ the remaining operation succeeds), and records for missing paths are pruned
252
+ during cleanup. Only marked Jarvis-PLOT components are removed; source data,
253
+ plots, and unrelated `.cache` content are retained. Failed deletions retain
254
+ their registry entries. Scanning adopts legacy caches only when the four
255
+ pipeline directories and a compatible `manifest.json` identify them; old
256
+ unmarked twin-only directories need a new `dryrun --with-data` run to register.
257
+ An explicitly supplied `--out-dir` is an export directory and is not registered.
258
+ Concurrent registry writes use a lock and atomic replacement. Registration
259
+ failures warn without preventing rendering.
260
+
224
261
  ### Example: SUSYRun2 Ternary Plots
225
262
 
226
263
  ```bash
@@ -313,3 +350,5 @@ Read the context docs and roadmap before changing parsing, transforms, rendering
313
350
  ## License
314
351
 
315
352
  MIT License
353
+
354
+ Create a continuous forest figure with `type: forest`, a generic row table and optional point table. The default Swiss-column card uses 82.5 mm width and 5.5 mm row pitch; every row shares one numerical x domain. See [the forest contract](docs/specs/FOREST.md), [native examples](Example/forest/README.md), or `jplot man forest --json`.
@@ -9,6 +9,7 @@ JarvisPLOT.egg-info/top_level.txt
9
9
  jarvisplot/__init__.py
10
10
  jarvisplot/agent_digest.py
11
11
  jarvisplot/agent_io.py
12
+ jarvisplot/cache_registry.py
12
13
  jarvisplot/cache_store.py
13
14
  jarvisplot/capabilities.py
14
15
  jarvisplot/cli.py
@@ -35,6 +36,8 @@ jarvisplot/dryrun_runtime.py
35
36
  jarvisplot/expr_names.py
36
37
  jarvisplot/fix_apply.py
37
38
  jarvisplot/flowchart.py
39
+ jarvisplot/forest_contract.py
40
+ jarvisplot/forest_text.py
38
41
  jarvisplot/generated_data.py
39
42
  jarvisplot/inner_func.py
40
43
  jarvisplot/legend_cards.py
@@ -72,6 +75,9 @@ jarvisplot/Figure/distribution_1d_runtime.py
72
75
  jarvisplot/Figure/dynesty_runtime.py
73
76
  jarvisplot/Figure/figure.py
74
77
  jarvisplot/Figure/figure_types.py
78
+ jarvisplot/Figure/forest_debug.py
79
+ jarvisplot/Figure/forest_legend.py
80
+ jarvisplot/Figure/forest_runtime.py
75
81
  jarvisplot/Figure/helper.py
76
82
  jarvisplot/Figure/interp_2d_runtime.py
77
83
  jarvisplot/Figure/interp_natural_neighbor.py
@@ -109,6 +115,7 @@ jarvisplot/cards/corrplot/diamond.json
109
115
  jarvisplot/cards/corrplot/matrix.json
110
116
  jarvisplot/cards/default/output.json
111
117
  jarvisplot/cards/flowchart/default.json
118
+ jarvisplot/cards/forest/swiss_column.json
112
119
  jarvisplot/cards/gambit/1x1/ternary.json
113
120
  jarvisplot/cards/gambit/2x1/rect_cmap.json
114
121
  jarvisplot/cards/gambit/2x1/ternary.json
@@ -127,6 +134,7 @@ jarvisplot/cards/legends/default/legend-card.json
127
134
  jarvisplot/cards/legends/paper/legend-card.json
128
135
  jarvisplot/cards/legends/presentation/legend-card.json
129
136
  jarvisplot/manual_cards/agent-output.yaml
137
+ jarvisplot/manual_cards/cache.yaml
130
138
  jarvisplot/manual_cards/cli-map.yaml
131
139
  jarvisplot/manual_cards/data-columns.yaml
132
140
  jarvisplot/manual_cards/debug-overlay.yaml
@@ -140,6 +148,7 @@ jarvisplot/manual_cards/manifest.yaml
140
148
  jarvisplot/manual_cards/method_notes.yaml
141
149
  jarvisplot/manual_cards/style-axes.yaml
142
150
  jarvisplot/manual_cards/type-correlation-matrix.yaml
151
+ jarvisplot/manual_cards/type-forest.yaml
143
152
  jarvisplot/manual_cards/type-posterior-2d.yaml
144
153
  jarvisplot/manual_cards/type-profile-2d.yaml
145
154
  jarvisplot/manual_cards/validate.yaml
@@ -186,6 +195,7 @@ jarvisplot/schema/methods/tripcolor_axes.json
186
195
  jarvisplot/schema/methods/triplot.json
187
196
  jarvisplot/schema/methods/voronoi.json
188
197
  jarvisplot/schema/methods/voronoif.json
198
+ jarvisplot/schema/types/forest.json
189
199
  jarvisplot/utils/__init__.py
190
200
  jarvisplot/utils/cmaps.py
191
201
  jarvisplot/utils/dataframes.py
@@ -193,6 +203,7 @@ jarvisplot/utils/expression.py
193
203
  jarvisplot/utils/interpolator.py
194
204
  jarvisplot/utils/pathing.py
195
205
  jarvisplot/verbs/__init__.py
206
+ jarvisplot/verbs/cache.py
196
207
  jarvisplot/verbs/cap.py
197
208
  jarvisplot/verbs/config_cmd.py
198
209
  jarvisplot/verbs/data.py
@@ -204,15 +215,19 @@ jarvisplot/verbs/suggest.py
204
215
  jarvisplot/verbs/template.py
205
216
  jarvisplot/verbs/validate.py
206
217
  tests/test_adaptive_cdf.py
218
+ tests/test_add_column.py
207
219
  tests/test_agent_digest.py
208
220
  tests/test_agent_envelope.py
209
221
  tests/test_axis_title.py
222
+ tests/test_cache_cleanup.py
223
+ tests/test_cache_registry.py
210
224
  tests/test_capabilities.py
211
225
  tests/test_card_debug_shape.py
212
226
  tests/test_cli_help.py
213
227
  tests/test_cli_verbs.py
214
228
  tests/test_cmaps.py
215
229
  tests/test_column_existence.py
230
+ tests/test_column_pruning.py
216
231
  tests/test_config_addressing.py
217
232
  tests/test_config_edit.py
218
233
  tests/test_config_expand.py
@@ -232,11 +247,14 @@ tests/test_diagnostic_guidance.py
232
247
  tests/test_distribution_1d_transform.py
233
248
  tests/test_docs_status_labels.py
234
249
  tests/test_doctor_partial.py
250
+ tests/test_examples_validate.py
235
251
  tests/test_explain.py
252
+ tests/test_expression_semantics.py
236
253
  tests/test_figure_contracts.py
237
254
  tests/test_figure_type_expander.py
238
255
  tests/test_fix_application.py
239
256
  tests/test_flowchart_renderer.py
257
+ tests/test_forest.py
240
258
  tests/test_generated_data.py
241
259
  tests/test_imshow_adapter.py
242
260
  tests/test_interp_2d_transform.py
@@ -253,6 +271,7 @@ tests/test_pathing_contracts.py
253
271
  tests/test_posterior_hpd.py
254
272
  tests/test_profile_runtime.py
255
273
  tests/test_render_health.py
274
+ tests/test_render_lifecycle.py
256
275
  tests/test_row_ledger.py
257
276
  tests/test_schema_catalog.py
258
277
  tests/test_suggest.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: JarvisPLOT
3
- Version: 2.1.7
3
+ Version: 2.1.9
4
4
  Summary: Jarvis-PLOT: YAML-driven plotting engine
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -66,6 +66,7 @@ Render with a bare path — there is no `jplot run`:
66
66
  ```bash
67
67
  jplot path/to/config.yaml
68
68
  jplot path/to/config.yaml --rebuild-cache
69
+ jplot path/to/config.yaml --print
69
70
  ```
70
71
 
71
72
  Everything else is discovery and judgement, in three groups.
@@ -218,9 +219,45 @@ from jarvisplot import render_flowchart, render_flowchart_file
218
219
  - You can set `project.workdir` in YAML.
219
220
  - If `output.dir` is omitted, Jarvis-PLOT defaults to `<workdir>/plots/`.
220
221
  - Data cache is stored in `<workdir>/.cache/`.
222
+ - `--print` accepts the current settings and renders final figures without the logo. It announces that, after all enabled figures are saved successfully, cache payloads used or created by this run will be deleted (pipeline data and metadata, named/shared data, summaries, and HDF5 materialization slots). Rendering failures or a run with no enabled figures keep the cache. Unrelated cache entries and the lightweight fingerprint manifest are retained; later renders rebuild deleted entries as needed.
221
223
  - Profiling pipelines are prebuilt once and reused from cache when source fingerprint and profile settings are unchanged.
222
224
  - Profiling uses a fast two-stage grid reduction (`pregrid` + render `bin`) for large datasets.
223
225
 
226
+ Plot caches are automatically registered in `~/.jarvis/plot.json` (or
227
+ `$JARVIS_HOME/plot.json`). The registry groups caches by workdir and records
228
+ associated YAML paths and last use; payloads stay in their original directories.
229
+ This includes caches created by `data describe` and default `dryrun --with-data`
230
+ exports. Sizes are calculated when listing, rather than stored in the registry.
231
+
232
+ ```bash
233
+ jplot cache list
234
+ jplot cache scan ~/Jarvis-Workshop # register existing plot caches
235
+ jplot cache clean --workdir /path/to/project # this directory and all nested projects; repeatable
236
+ jplot cache clean --all --older-than 30 # unused for at least 30 days
237
+ jplot cache clean --all --dry-run # preview; no deletion/index changes
238
+ jplot cache clean --all # clean all registered inactive caches
239
+ jplot cache -h
240
+ jplot man cache
241
+ ```
242
+
243
+ `--workdir PATH` selects registered caches in PATH itself and all of its
244
+ subdirectories, even when PATH has no cache of its own. Repeat it to select
245
+ multiple directory trees; overlapping selections are deduplicated. Use
246
+ `cache scan PATH` first for old caches that have not been registered.
247
+
248
+ All cache subcommands accept `--json` and use the existing CLI envelope and
249
+ exit codes (0 success/partial, 1 failure, 2 usage). Non-TTY stdout defaults to
250
+ JSON; human results go to stderr. Active caches are skipped (`ok: null` when
251
+ the remaining operation succeeds), and records for missing paths are pruned
252
+ during cleanup. Only marked Jarvis-PLOT components are removed; source data,
253
+ plots, and unrelated `.cache` content are retained. Failed deletions retain
254
+ their registry entries. Scanning adopts legacy caches only when the four
255
+ pipeline directories and a compatible `manifest.json` identify them; old
256
+ unmarked twin-only directories need a new `dryrun --with-data` run to register.
257
+ An explicitly supplied `--out-dir` is an export directory and is not registered.
258
+ Concurrent registry writes use a lock and atomic replacement. Registration
259
+ failures warn without preventing rendering.
260
+
224
261
  ### Example: SUSYRun2 Ternary Plots
225
262
 
226
263
  ```bash
@@ -313,3 +350,5 @@ Read the context docs and roadmap before changing parsing, transforms, rendering
313
350
  ## License
314
351
 
315
352
  MIT License
353
+
354
+ Create a continuous forest figure with `type: forest`, a generic row table and optional point table. The default Swiss-column card uses 82.5 mm width and 5.5 mm row pitch; every row shares one numerical x domain. See [the forest contract](docs/specs/FOREST.md), [native examples](Example/forest/README.md), or `jplot man forest --json`.
@@ -44,6 +44,7 @@ Render with a bare path — there is no `jplot run`:
44
44
  ```bash
45
45
  jplot path/to/config.yaml
46
46
  jplot path/to/config.yaml --rebuild-cache
47
+ jplot path/to/config.yaml --print
47
48
  ```
48
49
 
49
50
  Everything else is discovery and judgement, in three groups.
@@ -196,9 +197,45 @@ from jarvisplot import render_flowchart, render_flowchart_file
196
197
  - You can set `project.workdir` in YAML.
197
198
  - If `output.dir` is omitted, Jarvis-PLOT defaults to `<workdir>/plots/`.
198
199
  - Data cache is stored in `<workdir>/.cache/`.
200
+ - `--print` accepts the current settings and renders final figures without the logo. It announces that, after all enabled figures are saved successfully, cache payloads used or created by this run will be deleted (pipeline data and metadata, named/shared data, summaries, and HDF5 materialization slots). Rendering failures or a run with no enabled figures keep the cache. Unrelated cache entries and the lightweight fingerprint manifest are retained; later renders rebuild deleted entries as needed.
199
201
  - Profiling pipelines are prebuilt once and reused from cache when source fingerprint and profile settings are unchanged.
200
202
  - Profiling uses a fast two-stage grid reduction (`pregrid` + render `bin`) for large datasets.
201
203
 
204
+ Plot caches are automatically registered in `~/.jarvis/plot.json` (or
205
+ `$JARVIS_HOME/plot.json`). The registry groups caches by workdir and records
206
+ associated YAML paths and last use; payloads stay in their original directories.
207
+ This includes caches created by `data describe` and default `dryrun --with-data`
208
+ exports. Sizes are calculated when listing, rather than stored in the registry.
209
+
210
+ ```bash
211
+ jplot cache list
212
+ jplot cache scan ~/Jarvis-Workshop # register existing plot caches
213
+ jplot cache clean --workdir /path/to/project # this directory and all nested projects; repeatable
214
+ jplot cache clean --all --older-than 30 # unused for at least 30 days
215
+ jplot cache clean --all --dry-run # preview; no deletion/index changes
216
+ jplot cache clean --all # clean all registered inactive caches
217
+ jplot cache -h
218
+ jplot man cache
219
+ ```
220
+
221
+ `--workdir PATH` selects registered caches in PATH itself and all of its
222
+ subdirectories, even when PATH has no cache of its own. Repeat it to select
223
+ multiple directory trees; overlapping selections are deduplicated. Use
224
+ `cache scan PATH` first for old caches that have not been registered.
225
+
226
+ All cache subcommands accept `--json` and use the existing CLI envelope and
227
+ exit codes (0 success/partial, 1 failure, 2 usage). Non-TTY stdout defaults to
228
+ JSON; human results go to stderr. Active caches are skipped (`ok: null` when
229
+ the remaining operation succeeds), and records for missing paths are pruned
230
+ during cleanup. Only marked Jarvis-PLOT components are removed; source data,
231
+ plots, and unrelated `.cache` content are retained. Failed deletions retain
232
+ their registry entries. Scanning adopts legacy caches only when the four
233
+ pipeline directories and a compatible `manifest.json` identify them; old
234
+ unmarked twin-only directories need a new `dryrun --with-data` run to register.
235
+ An explicitly supplied `--out-dir` is an export directory and is not registered.
236
+ Concurrent registry writes use a lock and atomic replacement. Registration
237
+ failures warn without preventing rendering.
238
+
202
239
  ### Example: SUSYRun2 Ternary Plots
203
240
 
204
241
  ```bash
@@ -291,3 +328,5 @@ Read the context docs and roadmap before changing parsing, transforms, rendering
291
328
  ## License
292
329
 
293
330
  MIT License
331
+
332
+ Create a continuous forest figure with `type: forest`, a generic row table and optional point table. The default Swiss-column card uses 82.5 mm width and 5.5 mm row pitch; every row shares one numerical x domain. See [the forest contract](docs/specs/FOREST.md), [native examples](Example/forest/README.md), or `jplot man forest --json`.
@@ -3,6 +3,8 @@ from __future__ import annotations
3
3
  from pathlib import Path
4
4
  from typing import Mapping
5
5
 
6
+ from .style_runtime import normalize_style_tokens
7
+
6
8
 
7
9
  def apply_figure_config(fig, info: Mapping) -> bool:
8
10
  """Apply a YAML figure block to a Figure instance."""
@@ -55,7 +57,7 @@ def apply_figure_config(fig, info: Mapping) -> bool:
55
57
  )
56
58
 
57
59
  if "style" in info:
58
- style_tokens = info["style"]
60
+ style_tokens = normalize_style_tokens(info["style"])
59
61
  else:
60
62
  style_tokens = ["a4paper_2x1"]
61
63
  fig.style = style_tokens
@@ -71,6 +71,13 @@ _LABEL_FONT = {
71
71
 
72
72
 
73
73
  DEFAULT_DEBUG = {
74
+ "forest_grid": {
75
+ "show": True,
76
+ "columns": {"show": True, "plot": {"color": "#DA291C", "linewidth": 0.3, "linestyle": ":", "alpha": 0.7}},
77
+ "baselines": {"show": True, "plot": {"color": "#DA291C", "linewidth": 0.2, "linestyle": "--", "alpha": 0.5}},
78
+ "bands": {"show": True, "Rectangle": {"edgecolor": "#DA291C", "linewidth": 0.25, "fill": False, "alpha": 0.5}},
79
+ "labels": {"show": True, "text": {"color": "#DA291C", "fontsize": 4, "ha": "left", "va": "top"}},
80
+ },
74
81
  # Which axes gets fully dimensioned and hosts the info panel. First match wins.
75
82
  "primary_order": ["ax", "ax0", "ax1", "axtri"],
76
83
  "units": {"cm_per_inch": 2.54, "pt_per_inch": 72.0},
@@ -185,6 +185,10 @@ def draw_design_reference(fig) -> None:
185
185
 
186
186
 
187
187
  def _draw(fig) -> None:
188
+ if hasattr(fig, 'forest_layout'):
189
+ from .forest_debug import draw_forest_reference
190
+ draw_forest_reference(fig, _debug_config(fig)['forest_grid'])
191
+ return
188
192
  F = fig.fig
189
193
  w_in, h_in = (float(v) for v in F.get_size_inches())
190
194
  debug = _debug_config(fig)
@@ -11,7 +11,7 @@ from types import MethodType
11
11
  from .adapters_rect import StdAxesAdapter
12
12
  from .adapters_ternary import TernaryAxesAdapter
13
13
  from .method_registry import resolve_callable
14
- from .style_runtime import resolve_style_bundle_payload
14
+ from .style_runtime import normalize_style_tokens, resolve_style_bundle_payload
15
15
  from .config_runtime import apply_figure_config
16
16
  from .design_runtime import draw_design_reference
17
17
  from .legend_runtime import apply_legend
@@ -399,10 +399,13 @@ class Figure:
399
399
 
400
400
 
401
401
  @style.setter
402
- def style(self, value) -> None:
403
- if len(value) not in (1, 2):
404
- self.logger.error("Undefined style -> {}".format(value))
405
- raise TypeError
402
+ def style(self, value) -> None:
403
+ value = normalize_style_tokens(value)
404
+ if not isinstance(value, list) or len(value) not in (1, 2):
405
+ raise TypeError(
406
+ "style must name a card family or [family, variant], e.g. "
407
+ "a4paper_2x1 or [a4paper_2x1, rect]; got {!r}".format(value)
408
+ )
406
409
  family, selected, bundle = resolve_style_bundle_payload(self.jpstyles, value)
407
410
  self._frame = deepcopy(bundle["Frame"])
408
411
  self._legend_disabled_axes = set()
@@ -508,7 +511,7 @@ class Figure:
508
511
  return {kk: self._ensure_pandas_data(vv, reason=reason) for kk, vv in data.items()}
509
512
  return data
510
513
 
511
- def _concat_loaded_data(self, items):
514
+ def _concat_loaded_data(self, items, layer_name: str = ""):
512
515
  if len(items) == 0:
513
516
  return None
514
517
  if len(items) == 1:
@@ -519,7 +522,28 @@ class Figure:
519
522
  pandas_items = [self._ensure_pandas_data(item, reason="concat-layer") for item in items]
520
523
  try:
521
524
  return pd.concat(pandas_items, ignore_index=False)
522
- except Exception:
525
+ except Exception as exc:
526
+ # Keep drawing what can be drawn, but never drop data silently.
527
+ if self.logger:
528
+ shapes = ", ".join(
529
+ str(getattr(item, "shape", type(item).__name__)) for item in pandas_items
530
+ )
531
+ self.logger.warning(
532
+ "Layer '{}': the {} data blocks could not be concatenated, so only "
533
+ "the first block is drawn and the other {} are dropped.\n"
534
+ "\t reason \t-> {}: {}\n"
535
+ "\t blocks \t-> {}\n"
536
+ "\t hint \t\t-> blocks combined with `combine: concat` must be tables "
537
+ "with compatible columns (no duplicated column names); use "
538
+ "`combine: separate` to draw them independently.".format(
539
+ layer_name or "<unnamed>",
540
+ len(pandas_items),
541
+ len(pandas_items) - 1,
542
+ type(exc).__name__,
543
+ exc,
544
+ shapes,
545
+ )
546
+ )
523
547
  return pandas_items[0]
524
548
 
525
549
  def _store_share_data_if_needed(self, layer, data, cache_ref: str | None = None):
@@ -752,7 +752,8 @@ def expand_correlation_matrix(info: Mapping[str, Any]) -> dict[str, Any]:
752
752
 
753
753
  # Types that expand_figure_type can lower to layers. Keep in sync with
754
754
  # expand_figure_type dispatch and capabilities.figure_types.
755
- KNOWN_FIGURE_TYPES = frozenset({"posterior_2d", "profile_2d", "correlation_matrix"})
755
+ NATIVE_FIGURE_TYPES = frozenset({"forest"})
756
+ KNOWN_FIGURE_TYPES = frozenset({"posterior_2d", "profile_2d", "correlation_matrix"}) | NATIVE_FIGURE_TYPES
756
757
 
757
758
 
758
759
  def expand_figure_type(info: Any) -> Any:
@@ -849,6 +850,7 @@ def expand_typed_figures(
849
850
  raise KeyError(f"figure(s) not found: {', '.join(missing)}")
850
851
 
851
852
  expanded_names: list[str] = []
853
+ native_found = False
852
854
  for index, fig in enumerate(figures):
853
855
  if not isinstance(fig, Mapping):
854
856
  continue
@@ -876,6 +878,12 @@ def expand_typed_figures(
876
878
  _note(logger, msg)
877
879
  continue
878
880
 
881
+ if fig_type in NATIVE_FIGURE_TYPES:
882
+ # Native table-driven formats keep their public contract. Their
883
+ # physical solve is inspectable, not a list of hand-authored layers.
884
+ native_found = True
885
+ continue
886
+
879
887
  try:
880
888
  out = expand_figure_type(fig)
881
889
  except Exception as exc:
@@ -897,6 +905,7 @@ def expand_typed_figures(
897
905
 
898
906
  if (
899
907
  not expanded_names
908
+ and not native_found
900
909
  and not allow_noop
901
910
  and raise_on_error
902
911
  and wanted is not None
@@ -0,0 +1,35 @@
1
+ """Read-only Swiss grid and physical band references on a separate overlay."""
2
+ from matplotlib.patches import Rectangle
3
+ from ..forest_text import font_properties
4
+
5
+
6
+ def draw_forest_reference(fig, cfg):
7
+ if not cfg['show'] or any(ax.get_label() == 'forest-design-reference' for ax in fig.fig.axes):
8
+ return
9
+ scene = fig.forest_layout
10
+ g = scene['geometry']
11
+ ax = fig.fig.add_axes([0, 0, 1, 1], label='forest-design-reference', zorder=10000)
12
+ ax.set(xlim=(0, scene['width_mm']), ylim=(scene['height_mm'], 0)); ax.axis('off')
13
+ ax.patch.set_alpha(0)
14
+ if cfg['columns']['show']:
15
+ for index, x in enumerate(g['grid_lines_mm']):
16
+ line, = ax.plot([x]*2, [0, scene['height_mm']], **cfg['columns']['plot'])
17
+ line.set_gid(f'forest-grid-{index:02d}')
18
+ if cfg['labels']['show']:
19
+ opts = dict(cfg['labels']['text'])
20
+ size = opts.pop('fontsize')
21
+ for index, x in enumerate(g['grid_lines_mm'][:-1]):
22
+ ax.text(x, g['top_axis_y_mm']+.35, f'{index+1:02d}', fontproperties=font_properties(size, scene['typography']['family']), **opts)
23
+ if cfg['baselines']['show']:
24
+ ys = [g[key] for key in ('meta_y_mm','title_y_mm','description_y_mm','x_label_y_mm','column_header_y_mm','top_tick_y_mm')]
25
+ ys += [r['top_mm']+g[key] for r in scene['rows'] for key in ('cell_y_mm','plot_y_mm')]
26
+ for index, y in enumerate(ys):
27
+ line, = ax.plot([g['plot_left_mm'], g['plot_right_mm']], [y]*2, **cfg['baselines']['plot'])
28
+ line.set_gid(f'forest-baseline-{index:03d}')
29
+ if cfg['bands']['show']:
30
+ for index, row in enumerate(scene['rows']):
31
+ for name, y, height in (('text', row['top_mm'], g['plot_y_mm']-g['point_band_mm']/2),
32
+ ('marks', row['top_mm']+g['plot_y_mm']-g['point_band_mm']/2, g['point_band_mm'])):
33
+ box = Rectangle((g['plot_left_mm'], y), scene['plot_width_mm'], height, **cfg['bands']['Rectangle'])
34
+ box.set_gid(f'forest-band-{name}-{index:03d}')
35
+ ax.add_patch(box)
@@ -0,0 +1,88 @@
1
+ """A native legend handler for the actual forest glyph artist container."""
2
+ from matplotlib.container import Container
3
+ from matplotlib.legend_handler import HandlerBase, HandlerPathCollection
4
+ from matplotlib.lines import Line2D
5
+ from matplotlib.patches import Rectangle
6
+ from matplotlib.offsetbox import VPacker
7
+
8
+
9
+ class PhysicalLegendColumn(VPacker):
10
+ """Recompute physical column width for each raster/vector renderer."""
11
+ def __init__(self, width_mm, **kwargs):
12
+ super().__init__(**kwargs)
13
+ self.width_pt = width_mm*72/25.4
14
+
15
+ def _get_bbox_and_child_offsets(self, renderer):
16
+ self.width = self.width_pt*renderer.points_to_pixels(1)
17
+ return super()._get_bbox_and_child_offsets(renderer)
18
+
19
+
20
+ class ForestGlyph(Container):
21
+ def __init__(self, artists, *, glyph):
22
+ super().__init__(artists)
23
+ self.glyph = glyph
24
+
25
+
26
+ class HandlerForestPoint(HandlerPathCollection):
27
+ """Place one point at the left of its compact native key."""
28
+ def __init__(self, key_width_pt):
29
+ super().__init__(numpoints=1)
30
+ self.key_width_pt = key_width_pt
31
+
32
+ def get_xdata(self, legend, xdescent, ydescent, width, height, fontsize):
33
+ x = -xdescent+self.key_width_pt/2
34
+ return [x, x], [x]
35
+
36
+
37
+ def group_glyph_and_points(legend, config, layers, glyph_object, *, base_dir=None):
38
+ """Use the canonical native items, with glyphs left and point classes right.
39
+
40
+ Matplotlib normally balances item counts across columns, which would place
41
+ some point classes beside the box sample. Repack its existing item boxes
42
+ without recreating handles, labels, or their handlers.
43
+ """
44
+ from matplotlib.offsetbox import DrawingArea
45
+ from ..legend_cards import resolve_axes_legend
46
+ kwargs, entries = resolve_axes_legend(config, layers, base_dir=base_dir)
47
+ if kwargs.get('ncols', kwargs.get('ncol', 1)) != 2:
48
+ return
49
+ legend._ncols = 2
50
+ if kwargs.get('reverse', False):
51
+ entries = list(reversed(entries))
52
+ objects = {id(text): entry['object'] for text, entry in zip(legend.get_texts(), entries)}
53
+ columns = legend._legend_handle_box.get_children()
54
+ groups = [[], []]
55
+ for column in columns:
56
+ for item in column.get_children():
57
+ label = item.get_children()[-1]._text
58
+ groups[0 if objects[id(label)] == glyph_object else 1].append(item)
59
+ # Preserve the empty semantic column when only one group is present.
60
+ legend._legend_handle_box._children = [
61
+ VPacker(pad=0, sep=legend.labelspacing*legend._fontsize,
62
+ align='left', children=items or [DrawingArea(0, 0)])
63
+ for items in groups
64
+ ]
65
+ legend._legend_handle_box.align = 'top'
66
+
67
+
68
+ class HandlerForestGlyph(HandlerBase):
69
+ def create_artists(self, legend, orig_handle, xdescent, ydescent, width, height, fontsize, trans):
70
+ whisker = orig_handle[0]
71
+ left, right = -xdescent, width-xdescent
72
+ yc = (height-ydescent)/2
73
+ half = height*.32
74
+ stroke = {'color': whisker.get_color(), 'linewidth': whisker.get_linewidth(), 'transform': trans}
75
+ artists = [Line2D([left, right], [yc, yc], **stroke)]
76
+ for xx in (left, right):
77
+ artists.append(Line2D([xx, xx], [yc-half, yc+half], **stroke))
78
+ if orig_handle.glyph == 'box':
79
+ box, median = orig_handle[1:]
80
+ artists.append(Rectangle((left+width*.25, yc-half), width*.5, half*2,
81
+ facecolor=box.get_facecolor(), edgecolor=box.get_edgecolor(),
82
+ linewidth=box.get_linewidth(), alpha=box.get_alpha(), transform=trans))
83
+ artists.append(Line2D([(left+right)/2]*2, [yc-half, yc+half], color=median.get_color(), linewidth=median.get_linewidth(), transform=trans))
84
+ else:
85
+ point = orig_handle[1]
86
+ artists.append(Line2D([(left+right)/2], [yc], linestyle='', marker=point.get_marker(), color=point.get_color(),
87
+ markersize=point.get_markersize(), markeredgewidth=point.get_markeredgewidth(), transform=trans))
88
+ return artists