jarvisplot 2.1.4__tar.gz → 2.1.5__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 (248) hide show
  1. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/JarvisPLOT.egg-info/PKG-INFO +1 -1
  2. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/JarvisPLOT.egg-info/SOURCES.txt +6 -0
  3. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/PKG-INFO +1 -1
  4. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/adapters_rect.py +28 -9
  5. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/design_runtime.py +6 -2
  6. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/figure.py +38 -10
  7. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/figure_types.py +11 -1
  8. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/interp_2d_runtime.py +39 -4
  9. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/interp_natural_neighbor.py +274 -8
  10. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/interp_natural_neighbor_exact.py +330 -59
  11. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/layer_runtime.py +113 -93
  12. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/posterior_density_runtime.py +1 -0
  13. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/preprocessor.py +30 -3
  14. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/profile_runtime.py +16 -26
  15. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/capabilities.py +33 -0
  16. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/column_demand.py +15 -1
  17. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/column_probe.py +6 -0
  18. jarvisplot-2.1.5/jarvisplot/data_generation_contracts.py +22 -0
  19. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/data_loader.py +33 -4
  20. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/dataset_types.py +11 -2
  21. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/dryrun_runtime.py +108 -28
  22. jarvisplot-2.1.5/jarvisplot/generated_data.py +131 -0
  23. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/man_methods.py +2 -1
  24. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/man_render_agent.py +28 -3
  25. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/man_transforms.py +16 -16
  26. jarvisplot-2.1.5/jarvisplot/manual_cards/field-interp.yaml +138 -0
  27. jarvisplot-2.1.5/jarvisplot/manual_cards/generated-data.yaml +94 -0
  28. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/manifest.yaml +13 -0
  29. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/method_notes.yaml +37 -5
  30. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/type-profile-2d.yaml +7 -1
  31. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/yaml-root.yaml +4 -1
  32. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/core/dataset.json +12 -4
  33. jarvisplot-2.1.5/jarvisplot/schema/core/generated-data.json +90 -0
  34. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/core/layer.json +15 -2
  35. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/manifest.json +1 -0
  36. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/transform_contracts.py +127 -5
  37. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/validation.py +2 -1
  38. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/cap.py +52 -5
  39. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/man.py +2 -1
  40. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/pyproject.toml +1 -1
  41. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_capabilities.py +23 -0
  42. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_data_loader_contracts.py +37 -0
  43. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_density_cell_transform.py +36 -0
  44. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_figure_contracts.py +43 -0
  45. jarvisplot-2.1.5/tests/test_generated_data.py +276 -0
  46. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_interp_2d_transform.py +99 -9
  47. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_interp_natural_neighbor.py +29 -0
  48. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_jpcontour_methods.py +12 -3
  49. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_man_cli.py +18 -0
  50. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_profile_runtime.py +51 -1
  51. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_schema_catalog.py +3 -2
  52. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/JarvisPLOT.egg-info/dependency_links.txt +0 -0
  53. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/JarvisPLOT.egg-info/entry_points.txt +0 -0
  54. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/JarvisPLOT.egg-info/requires.txt +0 -0
  55. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/JarvisPLOT.egg-info/top_level.txt +0 -0
  56. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/README.md +0 -0
  57. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/__init__.py +0 -0
  58. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/adapters_ternary.py +0 -0
  59. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/bin_stat_runtime.py +0 -0
  60. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/cards/std_axes_adapter_config.json +0 -0
  61. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/colorbar_runtime.py +0 -0
  62. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/config_runtime.py +0 -0
  63. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/corr_layout.py +0 -0
  64. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/corr_layout_diamond.py +0 -0
  65. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/corr_order.py +0 -0
  66. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/correlation_runtime.py +0 -0
  67. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/corrplot_runtime.py +0 -0
  68. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/data_pipelines.py +0 -0
  69. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/debug_config.py +0 -0
  70. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/density_cell_runtime.py +0 -0
  71. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/dynesty_runtime.py +0 -0
  72. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/helper.py +0 -0
  73. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/layout_runtime.py +0 -0
  74. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/method_registry.py +0 -0
  75. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/posterior_hpd.py +0 -0
  76. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/posterior_mesh.py +0 -0
  77. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/preprocessor_runtime.py +0 -0
  78. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/significance_runtime.py +0 -0
  79. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/Figure/style_runtime.py +0 -0
  80. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/__init__.py +0 -0
  81. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/agent_digest.py +0 -0
  82. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/agent_io.py +0 -0
  83. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cache_store.py +0 -0
  84. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/1x1/ternary.json +0 -0
  85. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/2x1/dynesty_runplot.json +0 -0
  86. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/2x1/rect.json +0 -0
  87. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/2x1/rect5x1.json +0 -0
  88. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/2x1/rect_cmap.json +0 -0
  89. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/2x1/rect_marginal.json +0 -0
  90. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/2x1/rectratio.json +0 -0
  91. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/2x1/ternary.json +0 -0
  92. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/2x1/ternary_cmap.json +0 -0
  93. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/4x1/rect.json +0 -0
  94. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/4x1/rect_cmap.json +0 -0
  95. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/4x1/ternary.json +0 -0
  96. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/a4paper/4x1/ternary_cmap.json +0 -0
  97. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/args.json +0 -0
  98. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/colors/colormaps.json +0 -0
  99. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/corrplot/diamond.json +0 -0
  100. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/corrplot/matrix.json +0 -0
  101. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/default/output.json +0 -0
  102. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/flowchart/default.json +0 -0
  103. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/gambit/1x1/ternary.json +0 -0
  104. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/gambit/2x1/rect_cmap.json +0 -0
  105. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/gambit/2x1/ternary.json +0 -0
  106. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/gambit/2x1/ternary_cmap.json +0 -0
  107. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/icons/JarvisHEP.png +0 -0
  108. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/icons/flowchart/JarvisHEP.png +0 -0
  109. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/icons/flowchart/calculator.png +0 -0
  110. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/icons/flowchart/inputfile.png +0 -0
  111. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/icons/flowchart/opera.png +0 -0
  112. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/icons/flowchart/outputfile.png +0 -0
  113. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/icons/flowchart/sampler.png +0 -0
  114. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/icons/gambit.png +0 -0
  115. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/icons/gambit_small.png +0 -0
  116. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cards/style_preference.json +0 -0
  117. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cli.py +0 -0
  118. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/cli_help.py +0 -0
  119. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/client.py +0 -0
  120. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/config.py +0 -0
  121. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/config_address.py +0 -0
  122. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/core.py +0 -0
  123. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/core_assets.py +0 -0
  124. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/core_runtime.py +0 -0
  125. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/data_access.py +0 -0
  126. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/data_loader_hdf5.py +0 -0
  127. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/data_loader_runtime.py +0 -0
  128. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/data_loader_summary.py +0 -0
  129. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/diagnostic_guidance.py +0 -0
  130. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/diagnostics.py +0 -0
  131. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/expr_names.py +0 -0
  132. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/fix_apply.py +0 -0
  133. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/flowchart.py +0 -0
  134. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/inner_func.py +0 -0
  135. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/man_catalog.py +0 -0
  136. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/man_render_human.py +0 -0
  137. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/agent-output.yaml +0 -0
  138. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/cli-map.yaml +0 -0
  139. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/data-columns.yaml +0 -0
  140. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/debug-overlay.yaml +0 -0
  141. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/diagnostics.yaml +0 -0
  142. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/dryrun-viz.yaml +0 -0
  143. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/layer-method.yaml +0 -0
  144. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/style-axes.yaml +0 -0
  145. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/type-correlation-matrix.yaml +0 -0
  146. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/type-posterior-2d.yaml +0 -0
  147. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/validate.yaml +0 -0
  148. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/manual_cards/workflow.yaml +0 -0
  149. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/memtrace.py +0 -0
  150. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/method_contracts.py +0 -0
  151. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/render_health.py +0 -0
  152. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/core/common.json +0 -0
  153. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/core/figure.json +0 -0
  154. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/core/transform.json +0 -0
  155. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/bar.json +0 -0
  156. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/barh.json +0 -0
  157. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/contour.json +0 -0
  158. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/contourf.json +0 -0
  159. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/corrplot.json +0 -0
  160. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/dynesty_runplot.json +0 -0
  161. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/errorbar.json +0 -0
  162. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/fill.json +0 -0
  163. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/fill_between.json +0 -0
  164. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/fill_betweenx.json +0 -0
  165. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/hist.json +0 -0
  166. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/hist2d.json +0 -0
  167. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/imshow.json +0 -0
  168. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/jpcontour.json +0 -0
  169. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/jpcontourf.json +0 -0
  170. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/jpfield.json +0 -0
  171. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/pcolor.json +0 -0
  172. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/pcolormesh.json +0 -0
  173. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/plot.json +0 -0
  174. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/quiver.json +0 -0
  175. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/scatter.json +0 -0
  176. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/stairs.json +0 -0
  177. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/step.json +0 -0
  178. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/tricontour.json +0 -0
  179. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/tricontourf.json +0 -0
  180. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/tripcolor.json +0 -0
  181. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/tripcolor_axes.json +0 -0
  182. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/triplot.json +0 -0
  183. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/voronoi.json +0 -0
  184. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/methods/voronoif.json +0 -0
  185. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema/plot-config.json +0 -0
  186. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema_catalog.py +0 -0
  187. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/schema_diagnostics.py +0 -0
  188. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/templates_catalog.py +0 -0
  189. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/utils/__init__.py +0 -0
  190. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/utils/cmaps.py +0 -0
  191. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/utils/dataframes.py +0 -0
  192. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/utils/expression.py +0 -0
  193. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/utils/interpolator.py +0 -0
  194. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/utils/pathing.py +0 -0
  195. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/__init__.py +0 -0
  196. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/config_cmd.py +0 -0
  197. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/data.py +0 -0
  198. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/doctor.py +0 -0
  199. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/dryrun.py +0 -0
  200. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/explain.py +0 -0
  201. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/suggest.py +0 -0
  202. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/template.py +0 -0
  203. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/verbs/validate.py +0 -0
  204. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/jarvisplot/yaml_io.py +0 -0
  205. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/setup.cfg +0 -0
  206. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_agent_digest.py +0 -0
  207. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_agent_envelope.py +0 -0
  208. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_axis_title.py +0 -0
  209. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_card_debug_shape.py +0 -0
  210. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_cli_help.py +0 -0
  211. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_cli_verbs.py +0 -0
  212. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_cmaps.py +0 -0
  213. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_column_existence.py +0 -0
  214. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_config_addressing.py +0 -0
  215. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_config_edit.py +0 -0
  216. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_config_expand.py +0 -0
  217. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_correlation_runtime.py +0 -0
  218. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_corrplot.py +0 -0
  219. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_data_access.py +0 -0
  220. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_data_describe.py +0 -0
  221. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_data_head_eval.py +0 -0
  222. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_data_pipelines.py +0 -0
  223. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_debug_config.py +0 -0
  224. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_debug_switches.py +0 -0
  225. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_debug_yaml_override.py +0 -0
  226. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_design_runtime.py +0 -0
  227. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_diagnostic_guidance.py +0 -0
  228. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_docs_status_labels.py +0 -0
  229. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_doctor_partial.py +0 -0
  230. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_explain.py +0 -0
  231. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_figure_type_expander.py +0 -0
  232. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_fix_application.py +0 -0
  233. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_flowchart_renderer.py +0 -0
  234. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_imshow_adapter.py +0 -0
  235. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_interpolator_contracts.py +0 -0
  236. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_method_contracts.py +0 -0
  237. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_parse_data_metadata.py +0 -0
  238. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_pathing_contracts.py +0 -0
  239. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_posterior_hpd.py +0 -0
  240. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_render_health.py +0 -0
  241. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_row_ledger.py +0 -0
  242. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_suggest.py +0 -0
  243. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_suggest_axes.py +0 -0
  244. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_template_catalog.py +0 -0
  245. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_template_json.py +0 -0
  246. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_ternary_debug.py +0 -0
  247. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/tests/test_transform_contracts.py +0 -0
  248. {jarvisplot-2.1.4 → jarvisplot-2.1.5}/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.4
3
+ Version: 2.1.5
4
4
  Summary: Jarvis-PLOT: YAML-driven plotting engine
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -22,6 +22,7 @@ jarvisplot/core.py
22
22
  jarvisplot/core_assets.py
23
23
  jarvisplot/core_runtime.py
24
24
  jarvisplot/data_access.py
25
+ jarvisplot/data_generation_contracts.py
25
26
  jarvisplot/data_loader.py
26
27
  jarvisplot/data_loader_hdf5.py
27
28
  jarvisplot/data_loader_runtime.py
@@ -33,6 +34,7 @@ jarvisplot/dryrun_runtime.py
33
34
  jarvisplot/expr_names.py
34
35
  jarvisplot/fix_apply.py
35
36
  jarvisplot/flowchart.py
37
+ jarvisplot/generated_data.py
36
38
  jarvisplot/inner_func.py
37
39
  jarvisplot/man_catalog.py
38
40
  jarvisplot/man_methods.py
@@ -121,6 +123,8 @@ jarvisplot/manual_cards/data-columns.yaml
121
123
  jarvisplot/manual_cards/debug-overlay.yaml
122
124
  jarvisplot/manual_cards/diagnostics.yaml
123
125
  jarvisplot/manual_cards/dryrun-viz.yaml
126
+ jarvisplot/manual_cards/field-interp.yaml
127
+ jarvisplot/manual_cards/generated-data.yaml
124
128
  jarvisplot/manual_cards/layer-method.yaml
125
129
  jarvisplot/manual_cards/manifest.yaml
126
130
  jarvisplot/manual_cards/method_notes.yaml
@@ -136,6 +140,7 @@ jarvisplot/schema/plot-config.json
136
140
  jarvisplot/schema/core/common.json
137
141
  jarvisplot/schema/core/dataset.json
138
142
  jarvisplot/schema/core/figure.json
143
+ jarvisplot/schema/core/generated-data.json
139
144
  jarvisplot/schema/core/layer.json
140
145
  jarvisplot/schema/core/transform.json
141
146
  jarvisplot/schema/methods/bar.json
@@ -217,6 +222,7 @@ tests/test_figure_contracts.py
217
222
  tests/test_figure_type_expander.py
218
223
  tests/test_fix_application.py
219
224
  tests/test_flowchart_renderer.py
225
+ tests/test_generated_data.py
220
226
  tests/test_imshow_adapter.py
221
227
  tests/test_interp_2d_transform.py
222
228
  tests/test_interp_natural_neighbor.py
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: JarvisPLOT
3
- Version: 2.1.4
3
+ Version: 2.1.5
4
4
  Summary: Jarvis-PLOT: YAML-driven plotting engine
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -12,7 +12,11 @@ from matplotlib.collections import PolyCollection
12
12
  #
13
13
  from .helper import _auto_clip, _mask_by_extend, voronoi_finite_polygons_2d, _clip_poly_to_rect
14
14
  from .profile_runtime import grid_from_metadata, regular_grid_mesh
15
- from .interp_natural_neighbor import resolve_backend
15
+ from .interp_natural_neighbor import (
16
+ drawing_backend_options,
17
+ log_backend_diagnostics,
18
+ resolve_backend,
19
+ )
16
20
  from .posterior_hpd import prepare_hpd_contour_style
17
21
 
18
22
  DEFAULT_JP_SAMPLE_GRID = 500
@@ -242,8 +246,9 @@ class StdAxesAdapter:
242
246
  ny: Optional[int] = None,
243
247
  xlim=None,
244
248
  ylim=None,
245
- nan_policy: str = "strict",
249
+ nan_policy: str = "ignore",
246
250
  backend_options: Optional[dict[str, Any]] = None,
251
+ logger=None,
247
252
  ):
248
253
  x = np.asarray(x, dtype=float).reshape(-1)
249
254
  y = np.asarray(y, dtype=float).reshape(-1)
@@ -273,8 +278,9 @@ class StdAxesAdapter:
273
278
  X,
274
279
  Y,
275
280
  nan_policy=nan_policy,
276
- backend_options=backend_options,
281
+ backend_options=drawing_backend_options(backend_options),
277
282
  )
283
+ log_backend_diagnostics(logger, getattr(backend, "last_diagnostics", None))
278
284
  return X, Y, np.asarray(Z, dtype=float)
279
285
 
280
286
  def _build_jpcontour_grid(
@@ -322,9 +328,10 @@ class StdAxesAdapter:
322
328
  ny: Optional[int] = None,
323
329
  xlim=None,
324
330
  ylim=None,
325
- nan_policy: str = "strict",
331
+ nan_policy: str = "ignore",
326
332
  diagnostics: bool = False,
327
333
  backend_options: Optional[dict[str, Any]] = None,
334
+ logger=None,
328
335
  ):
329
336
  """Interpolate scattered data on an axes-fraction grid for contour rendering.
330
337
 
@@ -361,8 +368,9 @@ class StdAxesAdapter:
361
368
  Y,
362
369
  nan_policy=nan_policy,
363
370
  diagnostics=diagnostics,
364
- backend_options=backend_options,
371
+ backend_options=drawing_backend_options(backend_options),
365
372
  )
373
+ log_backend_diagnostics(logger, getattr(backend, "last_diagnostics", None))
366
374
  return X, Y, np.asarray(Z, dtype=float)
367
375
 
368
376
  # —— Common method forwarding (add as needed) ——
@@ -518,12 +526,18 @@ class StdAxesAdapter:
518
526
  ny: Optional[int] = None,
519
527
  xlim=None,
520
528
  ylim=None,
521
- nan_policy: str = "strict",
529
+ nan_policy: str = "ignore",
522
530
  diagnostics: bool = False,
523
531
  backend_options: Optional[dict[str, Any]] = None,
524
532
  **kwargs,
525
533
  ):
526
- """Scattered-data contour plot rendered in axes-fraction coordinates."""
534
+ """Scattered-data contour plot rendered in axes-fraction coordinates.
535
+
536
+ ``nan_policy`` defaults to ``ignore`` here: a sample whose z is NaN --
537
+ an empty profile-likelihood cell, say -- is not a measurement, and
538
+ letting it propagate would blank the cells around it as well. Pass
539
+ ``nan_policy="strict"`` to keep those neighbourhoods masked instead.
540
+ """
527
541
  kw = self._merge("contour", kwargs)
528
542
  kw.pop("transform", None)
529
543
  logger = kw.pop("_logger", None)
@@ -540,6 +554,7 @@ class StdAxesAdapter:
540
554
  nan_policy=nan_policy,
541
555
  diagnostics=diagnostics,
542
556
  backend_options=backend_options,
557
+ logger=logger,
543
558
  )
544
559
  kw = prepare_hpd_contour_style(Z, X, Y, kw, logger=logger)
545
560
  label_map = kw.pop("_hpd_label_map", None)
@@ -570,7 +585,7 @@ class StdAxesAdapter:
570
585
  ny: Optional[int] = None,
571
586
  xlim=None,
572
587
  ylim=None,
573
- nan_policy: str = "strict",
588
+ nan_policy: str = "ignore",
574
589
  diagnostics: bool = False,
575
590
  backend_options: Optional[dict[str, Any]] = None,
576
591
  **kwargs,
@@ -578,6 +593,7 @@ class StdAxesAdapter:
578
593
  """Filled scattered-data contour plot rendered in axes-fraction coordinates."""
579
594
  kw = self._merge("contourf", kwargs)
580
595
  kw.pop("transform", None)
596
+ logger = kw.pop("_logger", None)
581
597
  X, Y, Z = self._interpolate_jpcontour_grid(
582
598
  x,
583
599
  y,
@@ -591,6 +607,7 @@ class StdAxesAdapter:
591
607
  nan_policy=nan_policy,
592
608
  diagnostics=diagnostics,
593
609
  backend_options=backend_options,
610
+ logger=logger,
594
611
  )
595
612
  artists = self.ax.contourf(
596
613
  X,
@@ -614,7 +631,7 @@ class StdAxesAdapter:
614
631
  ny: Optional[int] = None,
615
632
  xlim=None,
616
633
  ylim=None,
617
- nan_policy: str = "strict",
634
+ nan_policy: str = "ignore",
618
635
  backend_options: Optional[dict[str, Any]] = None,
619
636
  shading: str = "auto",
620
637
  **kwargs,
@@ -633,6 +650,7 @@ class StdAxesAdapter:
633
650
  kw.pop(k, None)
634
651
  kw.pop("shading", None)
635
652
  kw.pop("transform", None)
653
+ logger = kw.pop("_logger", None)
636
654
  X, Y, Z = self._interpolate_jpfield_grid(
637
655
  x,
638
656
  y,
@@ -645,6 +663,7 @@ class StdAxesAdapter:
645
663
  ylim=ylim,
646
664
  nan_policy=nan_policy,
647
665
  backend_options=backend_options,
666
+ logger=logger,
648
667
  )
649
668
  X = np.asarray(X, dtype=float)
650
669
  Y = np.asarray(Y, dtype=float)
@@ -129,8 +129,12 @@ def _preview_colorbar(fig, name, cfg):
129
129
 
130
130
  from .colorbar_runtime import axc_color_config, axc_is_horizontal
131
131
 
132
- cmap = axc_color_config(fig.frame, name).get("cmap") or cfg["fallback_cmap"]
133
- is_h = axc_is_horizontal(fig.frame, name)
132
+ # Lightweight wrappers used by design tooling may expose only ``fig`` and
133
+ # ``axes``. An absent frame means there is no colorbar override, not that
134
+ # the rest of the debug overlay should be abandoned halfway through.
135
+ frame = getattr(fig, "frame", {})
136
+ cmap = axc_color_config(frame, name).get("cmap") or cfg["fallback_cmap"]
137
+ is_h = axc_is_horizontal(frame, name)
134
138
  ramp = np.linspace(0.0, 1.0, int(cfg["samples"])).reshape(-1, 1)
135
139
  if is_h:
136
140
  ramp = ramp.reshape(1, -1)
@@ -18,6 +18,7 @@ from .layer_runtime import (
18
18
  load_layer_runtime_data as runtime_load_layer_runtime_data,
19
19
  release_layer_runtime_data as runtime_release_layer_runtime_data,
20
20
  render_layer as runtime_render_layer,
21
+ separate_block_options,
21
22
  )
22
23
  from .layout_runtime import (
23
24
  apply_axis_endpoints,
@@ -987,14 +988,28 @@ class Figure:
987
988
  coor = ly.get("coor", {})
988
989
  style = dict(ly.get("style") or {})
989
990
  method_key = str(ly.get("method", "scatter")).lower()
991
+ is_separate = str(ly.get("combine", "concat")).strip().lower() in {
992
+ "separate",
993
+ "seperate",
994
+ }
995
+ block_options = (
996
+ separate_block_options(ly.get("layer_spec") or {}) if is_separate else {}
997
+ )
998
+ candidate_styles = [style]
999
+ candidate_styles.extend(
1000
+ {**style, **dict(option.get("style") or {})}
1001
+ for option in block_options.values()
1002
+ )
990
1003
 
991
- if not layer_uses_color(style, coor, method_key):
1004
+ if not any(layer_uses_color(item, coor, method_key) for item in candidate_styles):
992
1005
  continue
993
1006
 
994
- if style.get("cmap") is not None and layer_cmap_wins(
995
- self, cb_name, axc_color_config(self.frame, cb_name)
996
- ):
997
- cb_style_cmaps.setdefault(cb_name, style.get("cmap"))
1007
+ for candidate_style in candidate_styles:
1008
+ if candidate_style.get("cmap") is not None and layer_cmap_wins(
1009
+ self, cb_name, axc_color_config(self.frame, cb_name)
1010
+ ):
1011
+ cb_style_cmaps.setdefault(cb_name, candidate_style.get("cmap"))
1012
+ break
998
1013
 
999
1014
  # Load data for color range only — do not append health observations
1000
1015
  # (render loop will load again and observe once).
@@ -1003,11 +1018,24 @@ class Figure:
1003
1018
  if df is not None:
1004
1019
  df = self._ensure_pandas_data(df, reason="prescan:colorbar")
1005
1020
  color_cfg = axc_color_config(self.frame, cb_name)
1006
- lo, hi = collect_layer_color_range(
1007
- df, coor, style, scale=color_cfg.get("scale"), method_key=method_key
1008
- )
1009
- if lo is not None or hi is not None:
1010
- cb_ranges.setdefault(cb_name, []).append((lo, hi))
1021
+ blocks = df.items() if isinstance(df, dict) else ((None, df),)
1022
+ for block_key, block_df in blocks:
1023
+ block_style = dict(style)
1024
+ if block_key is not None:
1025
+ block_style.update(
1026
+ (block_options.get(block_key) or {}).get("style") or {}
1027
+ )
1028
+ if not layer_uses_color(block_style, coor, method_key):
1029
+ continue
1030
+ lo, hi = collect_layer_color_range(
1031
+ block_df,
1032
+ coor,
1033
+ block_style,
1034
+ scale=color_cfg.get("scale"),
1035
+ method_key=method_key,
1036
+ )
1037
+ if lo is not None or hi is not None:
1038
+ cb_ranges.setdefault(cb_name, []).append((lo, hi))
1011
1039
  # Release immediately to preserve memory profile
1012
1040
  runtime_release_layer_runtime_data(self, ly, consume_sources=False)
1013
1041
 
@@ -238,7 +238,10 @@ def _profile_interp_transform(info: Mapping[str, Any], opts: Mapping[str, Any])
238
238
  "z": {"expr": z_name, "name": z_name},
239
239
  },
240
240
  "grid": opts.get("grid", interp_cfg.get("grid", 500)),
241
- "nan_policy": interp_cfg.get("nan_policy", "strict"),
241
+ # A cell that caught no sample is not a core with an unknown value;
242
+ # make_interp_2d drops it either way, but the expanded YAML should say
243
+ # so rather than reading `strict` and meaning `ignore`.
244
+ "nan_policy": interp_cfg.get("nan_policy", "ignore"),
242
245
  "as_density": False,
243
246
  "normalize": False,
244
247
  }
@@ -249,6 +252,13 @@ def _profile_interp_transform(info: Mapping[str, Any], opts: Mapping[str, Any])
249
252
  for key, value in interp_cfg.items():
250
253
  if key not in {"method", "grid", "nan_policy"}:
251
254
  transform[key] = deepcopy(value)
255
+ # A profile map is a picture, not an integral: close the half-cell frame
256
+ # the hull of the cell centres leaves around the domain. posterior_density
257
+ # deliberately does not do this -- extrapolating a normalized density past
258
+ # its support would move the integral.
259
+ options = transform.get("backend_options", None)
260
+ transform["backend_options"] = dict(options) if isinstance(options, Mapping) else {}
261
+ transform["backend_options"].setdefault("boundary", "clamp")
252
262
  return transform
253
263
 
254
264
 
@@ -7,6 +7,7 @@ import pandas as pd
7
7
 
8
8
  from ..utils.expression import eval_dataframe_expression
9
9
  from .interp_natural_neighbor import resolve_backend
10
+ from .interp_natural_neighbor_exact import _apply_nan_core_policy, _normalize_nan_policy
10
11
  from .posterior_mesh import (
11
12
  clipped_voronoi_cells,
12
13
  regular_support_areas,
@@ -363,17 +364,27 @@ def make_interp_2d(df: pd.DataFrame, cfg: Mapping[str, Any], logger=None) -> pd.
363
364
 
364
365
  x = _project_axis(x_raw, xlim, xscale, "x")
365
366
  y = _project_axis(y_raw, ylim, yscale, "y")
366
- valid = np.isfinite(x) & np.isfinite(y) & np.isfinite(z_raw)
367
+ valid = np.isfinite(x) & np.isfinite(y)
367
368
  valid &= (x >= 0.0) & (x <= 1.0) & (y >= 0.0) & (y <= 1.0)
368
369
  valid_count = int(np.count_nonzero(valid))
369
370
  if valid_count < 3:
370
- raise ValueError("make_interp_2d requires at least three finite support points inside the interpolation limits.")
371
+ raise ValueError("make_interp_2d requires at least three finite support coordinates inside the interpolation limits.")
371
372
  if valid_count != n:
372
373
  _logger_emit(logger, "warning", f"make_interp_2d dropped {n - valid_count} invalid or outside-domain support points.")
373
374
 
374
375
  as_density = bool(cfg.get("as_density", False))
375
376
  reducer = "sum" if as_density else "mean"
376
- x, y, z = _dedupe_points(x[valid], y[valid], z_raw[valid], reducer=reducer)
377
+ # Missing values are background cores, not invalid coordinates. Resolve
378
+ # their policy before merging duplicates (ignore must not poison a finite
379
+ # sample at the same site; strict must retain the missing contribution).
380
+ nan_policy = _normalize_nan_policy(str(cfg.get("nan_policy", "strict")).strip() or "strict")
381
+ cfg = dict(cfg, nan_policy=nan_policy)
382
+ options = cfg.get("backend_options", {})
383
+ options = options if isinstance(options, Mapping) else {}
384
+ coords, z, nan_info = _apply_nan_core_policy(
385
+ np.column_stack([x[valid], y[valid]]), z_raw[valid], nan_policy, options
386
+ )
387
+ x, y, z = _dedupe_points(coords[:, 0], coords[:, 1], z, reducer=reducer)
377
388
  if len(x) < 3:
378
389
  raise ValueError("make_interp_2d requires at least three unique support points after duplicate merging.")
379
390
  x_phys = _unproject_axis(x, xlim, xscale)
@@ -432,6 +443,10 @@ def make_interp_2d(df: pd.DataFrame, cfg: Mapping[str, Any], logger=None) -> pd.
432
443
  f"\t method \t-> {method_name}\n"
433
444
  f"\t input_points \t-> {n}\n"
434
445
  f"\t valid_points \t-> {valid_count}\n"
446
+ f"\t nan_policy \t-> {nan_policy}\n"
447
+ f"\t missing_cores -> {nan_info['nan_cores']}\n"
448
+ f"\t dropped_cores -> {nan_info['dropped']}\n"
449
+ f"\t filled_cores \t-> {nan_info['filled']}\n"
435
450
  f"\t unique_points \t-> {len(x)}\n"
436
451
  f"\t xlim \t\t-> [{xlim[0]}, {xlim[1]}]\n"
437
452
  f"\t ylim \t\t-> [{ylim[0]}, {ylim[1]}]\n"
@@ -447,10 +462,30 @@ def make_interp_2d(df: pd.DataFrame, cfg: Mapping[str, Any], logger=None) -> pd.
447
462
  f"\t z_minmax \t-> {z_range}",
448
463
  )
449
464
 
450
- return pd.DataFrame(
465
+ # The samples in this table are grid *nodes*, not arbitrary scattered
466
+ # points. Preserve that geometry for pcolormesh: the axes may later use a
467
+ # narrower view than this interpolation domain. Re-binning the nodes
468
+ # against that view changes their cell ownership (especially on a log
469
+ # axis), which leaves unpainted slivers between cells.
470
+ ix_grid, iy_grid = np.meshgrid(
471
+ np.arange(nx, dtype=np.int32),
472
+ np.arange(ny, dtype=np.int32),
473
+ )
474
+ out = pd.DataFrame(
451
475
  {
452
476
  x_out: Xp.ravel(),
453
477
  y_out: Yp.ravel(),
454
478
  z_out: np.asarray(Z, dtype=float).ravel(),
479
+ "__grid_ix__": ix_grid.ravel(),
480
+ "__grid_iy__": iy_grid.ravel(),
455
481
  }
456
482
  )
483
+ out["__grid_nx__"] = np.int32(nx)
484
+ out["__grid_ny__"] = np.int32(ny)
485
+ out["__grid_xmin__"] = float(xlim[0])
486
+ out["__grid_xmax__"] = float(xlim[1])
487
+ out["__grid_ymin__"] = float(ylim[0])
488
+ out["__grid_ymax__"] = float(ylim[1])
489
+ out["__grid_xscale__"] = xscale
490
+ out["__grid_yscale__"] = yscale
491
+ return out