forgegraph 0.7.0__tar.gz → 0.8.0__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 (373) hide show
  1. {forgegraph-0.7.0 → forgegraph-0.8.0}/CHANGELOG.md +26 -0
  2. {forgegraph-0.7.0 → forgegraph-0.8.0}/PKG-INFO +1 -1
  3. forgegraph-0.7.0/src/forgegraph/skill/forgegraph/examples/figure.schedule.yaml → forgegraph-0.8.0/docs/examples/cells.schedule.yaml +3 -3
  4. forgegraph-0.8.0/docs/examples/passenger_toggles.yaml +48 -0
  5. forgegraph-0.8.0/docs/examples/penguin_measures.yaml +38 -0
  6. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/forgegraph_default/graphspecs/graphspec_example.md +5 -5
  7. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/forgegraph_default/pack.md +2 -2
  8. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/forgegraph_default/themes/light_theme.md +6 -1
  9. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/guides/graphs.md +2 -2
  10. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/guides/layers.md +35 -2
  11. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/guides/layouts.md +1 -1
  12. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/guides/schedules.md +4 -4
  13. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/guides/series.md +1 -1
  14. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/help/troubleshooting.md +9 -1
  15. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/catalogs/graphtype_xy.md +2 -2
  16. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/graphspec_example.md +18 -6
  17. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/graphtype_xy.md +5 -4
  18. forgegraph-0.8.0/docs/specifications/layer_choice.md +15 -0
  19. forgegraph-0.8.0/docs/specifications/layer_toggle.md +14 -0
  20. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/pack.md +2 -2
  21. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/styles.md +1 -1
  22. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/theme.md +5 -1
  23. {forgegraph-0.7.0 → forgegraph-0.8.0}/pyproject.toml +1 -1
  24. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/build_example_data.py +3 -30
  25. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/docs_site.py +10 -5
  26. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/run_skill_evals.py +16 -1
  27. forgegraph-0.8.0/scripts/skill_examples.py +132 -0
  28. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/catalog_build/build.py +3 -1
  29. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/catalog_build/cards.py +7 -1
  30. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/axes.py +18 -5
  31. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/figure.py +12 -10
  32. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/key.py +59 -10
  33. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/labels.py +147 -38
  34. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/layers.py +161 -44
  35. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/layout.py +68 -11
  36. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/limits.py +21 -0
  37. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/lint.py +4 -3
  38. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/marks.py +7 -1
  39. forgegraph-0.8.0/src/forgegraph/drawing/owners.py +72 -0
  40. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/page.py +404 -33
  41. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/readout.py +50 -10
  42. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/spacing.py +41 -0
  43. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/style.py +17 -1
  44. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/ticks.py +7 -3
  45. forgegraph-0.8.0/src/forgegraph/drawing/toggles.py +104 -0
  46. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/xy.py +56 -12
  47. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/graph.py +251 -22
  48. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/layouts/__init__.py +264 -25
  49. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/graphspecs/graphspec_example.yaml +5 -5
  50. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/pack.yaml +2 -2
  51. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/themes/light_theme.yaml +6 -1
  52. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/skill/forgegraph/SKILL.md +10 -8
  53. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/air_passengers_by_month.parquet +0 -0
  54. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/cell_durability.parquet +0 -0
  55. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/cell_polarization.parquet +0 -0
  56. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/cells.layout.yaml +26 -0
  57. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/cells.schedule.yaml +12 -0
  58. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/co2.yaml +28 -0
  59. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/co2_monthly.parquet +0 -0
  60. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/dose_response.parquet +0 -0
  61. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/dose_response.yaml +33 -0
  62. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/durability.yaml +26 -0
  63. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/economics.parquet +0 -0
  64. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/passenger_toggles.yaml +48 -0
  65. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/penguin_measures.yaml +38 -0
  66. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/penguins.parquet +0 -0
  67. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/plate_spectra.parquet +0 -0
  68. forgegraph-0.7.0/src/forgegraph/skill/forgegraph/examples/heat_map.yaml → forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/plate_spectra.yaml +3 -3
  69. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/polarization.yaml +24 -0
  70. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/savings.yaml +58 -0
  71. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/tips.parquet +0 -0
  72. forgegraph-0.8.0/src/forgegraph/skill/forgegraph/examples/tips_stacked.yaml +42 -0
  73. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/skill/forgegraph/references/themes_formats_configs.md +1 -1
  74. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/layers.py +35 -1
  75. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/parameters.py +24 -2
  76. forgegraph-0.8.0/src/forgegraph/spec/toggles.py +97 -0
  77. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/validate.py +9 -2
  78. forgegraph-0.8.0/src/forgegraph/spec/views.py +131 -0
  79. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/catalogs/graphtype_xy.yaml +1 -1
  80. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/graphspec_example.yaml +17 -5
  81. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/graphtype_xy.yaml +4 -4
  82. forgegraph-0.8.0/src/forgegraph/specifications/layer_choice.yaml +10 -0
  83. forgegraph-0.8.0/src/forgegraph/specifications/layer_toggle.yaml +9 -0
  84. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/pack.yaml +2 -2
  85. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/styles.yaml +1 -1
  86. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/theme.yaml +4 -1
  87. forgegraph-0.8.0/tests/baselines/precipitation_loglog.png +0 -0
  88. forgegraph-0.8.0/tests/baselines/replicates.png +0 -0
  89. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_axes.py +43 -0
  90. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_catalog_files.py +5 -2
  91. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_cli.py +2 -2
  92. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_docs_site.py +2 -0
  93. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_key_position.py +138 -4
  94. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_layers.py +123 -8
  95. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_layout.py +2 -2
  96. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_perturbation.py +2 -1
  97. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_readout.py +24 -2
  98. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_render.py +64 -2
  99. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_series.py +45 -0
  100. forgegraph-0.8.0/tests/test_skill_examples.py +26 -0
  101. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_specs.py +5 -1
  102. forgegraph-0.8.0/tests/test_toggles.py +282 -0
  103. forgegraph-0.8.0/tests/test_views.py +255 -0
  104. {forgegraph-0.7.0 → forgegraph-0.8.0}/uv.lock +1 -1
  105. forgegraph-0.7.0/src/forgegraph/skill/forgegraph/examples/bars.yaml +0 -32
  106. forgegraph-0.7.0/src/forgegraph/skill/forgegraph/examples/figure.layout.yaml +0 -16
  107. forgegraph-0.7.0/src/forgegraph/skill/forgegraph/examples/heat_map.parquet +0 -0
  108. forgegraph-0.7.0/src/forgegraph/skill/forgegraph/examples/layers.yaml +0 -36
  109. forgegraph-0.7.0/src/forgegraph/skill/forgegraph/examples/xy.parquet +0 -0
  110. forgegraph-0.7.0/src/forgegraph/skill/forgegraph/examples/xy.yaml +0 -22
  111. forgegraph-0.7.0/tests/baselines/precipitation_loglog.png +0 -0
  112. forgegraph-0.7.0/tests/baselines/replicates.png +0 -0
  113. {forgegraph-0.7.0 → forgegraph-0.8.0}/.gitignore +0 -0
  114. {forgegraph-0.7.0 → forgegraph-0.8.0}/.pre-commit-config.yaml +0 -0
  115. {forgegraph-0.7.0 → forgegraph-0.8.0}/CITATION.cff +0 -0
  116. {forgegraph-0.7.0 → forgegraph-0.8.0}/CONTRIBUTING.md +0 -0
  117. {forgegraph-0.7.0 → forgegraph-0.8.0}/LICENSE +0 -0
  118. {forgegraph-0.7.0 → forgegraph-0.8.0}/README.md +0 -0
  119. {forgegraph-0.7.0 → forgegraph-0.8.0}/SECURITY.md +0 -0
  120. {forgegraph-0.7.0 → forgegraph-0.8.0}/TRADEMARKS.md +0 -0
  121. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/design/architecture.md +0 -0
  122. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/design/initial-specification.md +0 -0
  123. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/acme_polarization.yaml +0 -0
  124. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/assay_summary.yaml +0 -0
  125. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/cells.layout.yaml +0 -0
  126. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/co2.yaml +0 -0
  127. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/dose_response.yaml +0 -0
  128. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/durability.yaml +0 -0
  129. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/lab_polarization.yaml +0 -0
  130. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/packs/lab/formats/poster.yaml +0 -0
  131. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/packs/lab/pack.yaml +0 -0
  132. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/packs/lab/themes/lab_theme.yaml +0 -0
  133. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/penguins.yaml +0 -0
  134. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/plate_spectra.yaml +0 -0
  135. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/polarization.yaml +0 -0
  136. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/savings.yaml +0 -0
  137. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/tips_side_by_side.yaml +0 -0
  138. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/examples/tips_stacked.yaml +0 -0
  139. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/acme/formats/slide.md +0 -0
  140. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/acme/graphspecs/polarization-curve.md +0 -0
  141. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/acme/layouts/dashboard.md +0 -0
  142. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/acme/pack.md +0 -0
  143. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/acme/schedules/workday.md +0 -0
  144. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/acme/themes/acme.md +0 -0
  145. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/forgegraph_default/catalogs/formats/compact_format.md +0 -0
  146. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/forgegraph_default/catalogs/formats/wide_format.md +0 -0
  147. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/forgegraph_default/catalogs/themes/light_theme.md +0 -0
  148. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/forgegraph_default/formats/compact_format.md +0 -0
  149. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/forgegraph_default/formats/wide_format.md +0 -0
  150. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/forgegraph_default/layouts/layout.md +0 -0
  151. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/packs/forgegraph_default/schedules/schedule.md +0 -0
  152. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/gallery.md +0 -0
  153. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/get-started/installation.md +0 -0
  154. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/get-started/quickstart.md +0 -0
  155. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/get-started/skill.md +0 -0
  156. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/guides/configs.md +0 -0
  157. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/guides/provenance.md +0 -0
  158. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/guides/themes-formats-packs.md +0 -0
  159. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/index.md +0 -0
  160. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/reference/python-api.md +0 -0
  161. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/release-notes.md +0 -0
  162. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/site/stylesheets/extra.css +0 -0
  163. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/catalogs/layer_error_bar.md +0 -0
  164. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/catalogs/layer_note.md +0 -0
  165. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/catalogs/layer_reference.md +0 -0
  166. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/config.md +0 -0
  167. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/format.md +0 -0
  168. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/layer_error_bar.md +0 -0
  169. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/layer_note.md +0 -0
  170. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/layer_reference.md +0 -0
  171. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/layout_example.md +0 -0
  172. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/provenance.md +0 -0
  173. {forgegraph-0.7.0 → forgegraph-0.8.0}/docs/specifications/schedule.md +0 -0
  174. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/README.md +0 -0
  175. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/forgegraph.toml +0 -0
  176. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/lab_throughput.layout.md +0 -0
  177. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/lab_throughput.layout.yaml +0 -0
  178. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/lost_runs.parquet +0 -0
  179. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/lost_runs.yaml +0 -0
  180. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/ops/formats/dashboard.md +0 -0
  181. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/ops/formats/dashboard.yaml +0 -0
  182. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/ops/pack.yaml +0 -0
  183. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/prep_lab_dashboard.py +0 -0
  184. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/run_time.parquet +0 -0
  185. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/run_time.yaml +0 -0
  186. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/runs_gc_ms_01.yaml +0 -0
  187. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/runs_hplc_01.yaml +0 -0
  188. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/runs_hplc_02.yaml +0 -0
  189. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/runs_icp_oes_01.yaml +0 -0
  190. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/samples_weekly.yaml +0 -0
  191. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/throughput_weekly.yaml +0 -0
  192. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/weekly_gc_ms_01.parquet +0 -0
  193. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/weekly_hplc_01.parquet +0 -0
  194. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/weekly_hplc_02.parquet +0 -0
  195. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/weekly_icp_oes_01.parquet +0 -0
  196. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/weekly_runs.parquet +0 -0
  197. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/dashboard/weekly_samples.parquet +0 -0
  198. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/cell_durability.parquet +0 -0
  199. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/cell_performance.layout.md +0 -0
  200. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/cell_performance.layout.yaml +0 -0
  201. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/cell_polarization.parquet +0 -0
  202. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/forgegraph.toml +0 -0
  203. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/hfr_time.yaml +0 -0
  204. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/journal/formats/journal-double.md +0 -0
  205. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/journal/formats/journal-double.yaml +0 -0
  206. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/journal/pack.yaml +0 -0
  207. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/polarization.yaml +0 -0
  208. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/prep_cells.py +0 -0
  209. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/layouts/paper/voltage_time.yaml +0 -0
  210. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/packs/acme/formats/slide.yaml +0 -0
  211. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/packs/acme/graphspecs/polarization-curve.yaml +0 -0
  212. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/packs/acme/layouts/dashboard.yaml +0 -0
  213. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/packs/acme/pack.yaml +0 -0
  214. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/packs/acme/references/house.md +0 -0
  215. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/packs/acme/schedules/workday.yaml +0 -0
  216. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/packs/acme/themes/acme.yaml +0 -0
  217. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/README.md +0 -0
  218. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/air_passengers.csv +0 -0
  219. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/air_passengers_by_month.csv +0 -0
  220. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/anscombe.csv +0 -0
  221. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/assay_summary.csv +0 -0
  222. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/cell_durability.csv +0 -0
  223. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/cell_polarization.csv +0 -0
  224. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/co2_monthly.csv +0 -0
  225. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/diamonds.csv +0 -0
  226. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/dose_response.csv +0 -0
  227. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/economics.csv +0 -0
  228. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/enzyme_kinetics.csv +0 -0
  229. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/fmri.csv +0 -0
  230. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/gapminder.csv +0 -0
  231. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/geyser.csv +0 -0
  232. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/growth.csv +0 -0
  233. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/iris.csv +0 -0
  234. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/lab_export.xlsx +0 -0
  235. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/lab_runs.xlsx +0 -0
  236. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/penguins.csv +0 -0
  237. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/plate_spectra.csv +0 -0
  238. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/seaice.csv +0 -0
  239. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/sensor_log_eu.csv +0 -0
  240. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/stocks.csv +0 -0
  241. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/tips.csv +0 -0
  242. {forgegraph-0.7.0 → forgegraph-0.8.0}/examples/sample-data/weather.xlsx +0 -0
  243. {forgegraph-0.7.0 → forgegraph-0.8.0}/mkdocs.yml +0 -0
  244. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/build_recreations.py +0 -0
  245. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/build_sample_data.py +0 -0
  246. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/check_denylist.py +0 -0
  247. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/forgemark.py +0 -0
  248. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/mirror_specs.py +0 -0
  249. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/report_skill_evals.py +0 -0
  250. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/smoke_installed.py +0 -0
  251. {forgegraph-0.7.0 → forgegraph-0.8.0}/scripts/visual_changelog.py +0 -0
  252. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/__init__.py +0 -0
  253. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/__main__.py +0 -0
  254. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/canvas.py +0 -0
  255. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/catalog_build/__init__.py +0 -0
  256. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/catalog_build/examples.py +0 -0
  257. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/catalog_build/files.py +0 -0
  258. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/catalog_build/page.py +0 -0
  259. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/cli/__init__.py +0 -0
  260. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/cli/catalog.py +0 -0
  261. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/cli/graphs.py +0 -0
  262. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/cli/jobs.py +0 -0
  263. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/cli/schema.py +0 -0
  264. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/cli/skill.py +0 -0
  265. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/data.py +0 -0
  266. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/__init__.py +0 -0
  267. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/colorbar.py +0 -0
  268. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/dates.py +0 -0
  269. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/equation.py +0 -0
  270. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/errors.py +0 -0
  271. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/export.py +0 -0
  272. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/markup.py +0 -0
  273. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawing/text.py +0 -0
  274. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/drawn.py +0 -0
  275. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/IBMPlexSerif-Bold.ttf +0 -0
  276. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/IBMPlexSerif-Light.ttf +0 -0
  277. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/IBMPlexSerif-Medium.ttf +0 -0
  278. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/IBMPlexSerif-Regular.ttf +0 -0
  279. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/IBMPlexSerif-SemiBold.ttf +0 -0
  280. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/OFL-IBMPlexSerif.txt +0 -0
  281. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/OFL-Roboto.txt +0 -0
  282. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/OFL-SourceSans3.md +0 -0
  283. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/Roboto-Bold.ttf +0 -0
  284. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/Roboto-Italic.ttf +0 -0
  285. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/Roboto-Light.ttf +0 -0
  286. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/Roboto-Medium.ttf +0 -0
  287. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/Roboto-Regular.ttf +0 -0
  288. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/Roboto-SemiBold.ttf +0 -0
  289. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/SourceSans3-Bold.ttf +0 -0
  290. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/SourceSans3-It.ttf +0 -0
  291. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/SourceSans3-Light.ttf +0 -0
  292. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/SourceSans3-Medium.ttf +0 -0
  293. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/SourceSans3-Regular.ttf +0 -0
  294. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/SourceSans3-Semibold.ttf +0 -0
  295. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/fonts/__init__.py +0 -0
  296. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/forgemark.py +0 -0
  297. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/jobs/__init__.py +0 -0
  298. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/jobs/run.py +0 -0
  299. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/jobs/status.py +0 -0
  300. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/layouts/separators.py +0 -0
  301. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/__init__.py +0 -0
  302. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/catalogs/formats/compact_format.yaml +0 -0
  303. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/catalogs/formats/wide_format.yaml +0 -0
  304. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/catalogs/themes/light_theme.yaml +0 -0
  305. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/formats/compact_format.yaml +0 -0
  306. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/formats/wide_format.yaml +0 -0
  307. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/graphspecs/dated.parquet +0 -0
  308. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/graphspecs/fanned.parquet +0 -0
  309. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/graphspecs/polarization.parquet +0 -0
  310. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/graphspecs/reinforced.parquet +0 -0
  311. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/layouts/layout.yaml +0 -0
  312. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/packs/forgegraph_default/schedules/schedule.yaml +0 -0
  313. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/skill/__init__.py +0 -0
  314. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/skill/forgegraph/references/requests.md +0 -0
  315. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/__init__.py +0 -0
  316. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/access.py +0 -0
  317. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/common.py +0 -0
  318. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/explain.py +0 -0
  319. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/layout.py +0 -0
  320. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/loaded.py +0 -0
  321. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/provenance.py +0 -0
  322. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/registry.py +0 -0
  323. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/resolve.py +0 -0
  324. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/schedule.py +0 -0
  325. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/series.py +0 -0
  326. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/spec/tags.py +0 -0
  327. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/catalogs/layer_error_bar.yaml +0 -0
  328. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/catalogs/layer_note.yaml +0 -0
  329. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/catalogs/layer_reference.yaml +0 -0
  330. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/config.toml +0 -0
  331. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/format.yaml +0 -0
  332. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/layer_error_bar.yaml +0 -0
  333. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/layer_note.yaml +0 -0
  334. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/layer_reference.yaml +0 -0
  335. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/layout_example.yaml +0 -0
  336. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/provenance.yaml +0 -0
  337. {forgegraph-0.7.0 → forgegraph-0.8.0}/src/forgegraph/specifications/schedule.yaml +0 -0
  338. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/baselines/crowded_runs.png +0 -0
  339. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/baselines/flow_sweep_wide.png +0 -0
  340. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/baselines/fuel_by_size.png +0 -0
  341. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/baselines/layout_anode_layers.png +0 -0
  342. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/baselines/layout_screening_and_rate.png +0 -0
  343. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/baselines/polarization.png +0 -0
  344. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/baselines/polarization_narrow.png +0 -0
  345. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/baselines/screening_scatter.png +0 -0
  346. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/baselines/separator_colorbar.png +0 -0
  347. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/conftest.py +0 -0
  348. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/fixtures/catalog_comments.html +0 -0
  349. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/pack_helpers.py +0 -0
  350. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/recreations.py +0 -0
  351. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/render_helpers.py +0 -0
  352. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/spec_mirror.py +0 -0
  353. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_blank.py +0 -0
  354. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_catalog.py +0 -0
  355. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_catalog_inputs.py +0 -0
  356. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_catalog_page.py +0 -0
  357. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_dates.py +0 -0
  358. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_denylist.py +0 -0
  359. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_jobs.py +0 -0
  360. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_labels.py +0 -0
  361. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_lint.py +0 -0
  362. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_marks.py +0 -0
  363. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_markup.py +0 -0
  364. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_packaging.py +0 -0
  365. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_packs.py +0 -0
  366. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_regression.py +0 -0
  367. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_schedule.py +0 -0
  368. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_smoke.py +0 -0
  369. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_spec_comments.py +0 -0
  370. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_spec_mirrors.py +0 -0
  371. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_styles.py +0 -0
  372. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_tags.py +0 -0
  373. {forgegraph-0.7.0 → forgegraph-0.8.0}/tests/test_text.py +0 -0
@@ -2,6 +2,32 @@
2
2
 
3
3
  ForgeGraph follows [semantic versioning](https://semver.org). Before 1.0, a minor version may change how graphs look or how specs are written.
4
4
 
5
+ ## 0.8.0 (2026-11-07)
6
+
7
+ ### New Features
8
+
9
+ - **Controls on the HTML page.** Two new layers add controls to a graph's web page. A `choice` layer lists views, such as other columns for a series or a log axis, and readers switch between them with a dropdown or radio buttons. A `toggle` layer adds checkboxes that show or hide series and layers; a series named in a key gets its checkbox in the key. Every view is drawn ahead of time, so the page needs no server, and the graph keeps its size and position as you switch. The controls go to the right of the graph, or above or below it, and the theme sets their text. In a layout, controls of the same name in different panels work together. Saved images show the first view, without the items hidden at first.
10
+ - **Axis limits that leave out outliers.** An axis's `min` or `max` can be `3IQR`, which ends the axis 3 interquartile ranges beyond the quartile, so a few extreme values don't squash the rest of the data.
11
+ - **Geometric statistics.** `geom_mean`, `geom_stddev` and `geom_ci` work wherever the other statistics do: combining points, error bars and reference lines. They suit values that vary by a factor, such as concentrations, and their error bars are longer above the point than below it.
12
+ - **Star and asterisk markers.**
13
+ - **Long titles can wrap.** A theme's `title.max_wrap` lets a title run onto more lines. By default a title doesn't wrap, and one that's too long now gives an error that names it.
14
+ - **Named parts in SVG files.** In an SVG, each series' and layer's parts have ids that start with its name, such as `fg-series-Voltage-1`, so a web page can find them.
15
+
16
+ ### Changes
17
+
18
+ - **Fewer tick labels when they'd run together.** Automatic ticks on a number axis now space out until their labels fit.
19
+ - **Ticks on an extended axis.** When an axis grows to make room for a key, note or label, its ticks carry on into the new part.
20
+ - **Keys and notes keep clear of reference lines and bands.** Keys, notes and reference labels no longer sit on a reference line, a band, or the edge of a large marker. The axis grows to make room, or the error says what's in the way. Some graphs will place their key differently.
21
+ - **Reference lines past a set limit.** A reference line or band beyond an axis limit you've set is now left out, and lint says so, rather than stopping the graph.
22
+ - **Clearer label errors.** When a reference label at `position: auto` has no room, the error says what's in the way at each place it tried.
23
+ - **The agent skill** knows about the new controls, and its examples are now the ones in the documentation.
24
+
25
+ ### Bug Fixes
26
+
27
+ - Points and bars beyond a set axis limit still had a hover box on the HTML page. Only what's drawn inside the plot has one now.
28
+ - Cross and plus markers were drawn in black instead of their series' color.
29
+ - After an axis grew to fit a key, a new top tick label could run off the figure.
30
+
5
31
  ## 0.7.0 (2026-11-02)
6
32
 
7
33
  ### New Features
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: forgegraph
3
- Version: 0.7.0
3
+ Version: 0.8.0
4
4
  Summary: Fast, consistent, publication-quality graphs from pandas DataFrames, usable by people and AI agents.
5
5
  Project-URL: Repository, https://github.com/sskaye/forgegraph
6
6
  Project-URL: Issues, https://github.com/sskaye/forgegraph/issues
@@ -1,11 +1,11 @@
1
- name: figure
1
+ name: cells
2
2
  version: 0
3
- description: The example layout, rendered every weekday at 06:00.
3
+ description: The cells layout, rendered every weekday at 06:00.
4
4
  extends: forgegraph_default/schedule
5
5
 
6
6
  parameters: # !var: a schedule that extends it may change it; !fix: it may not; on a category, all in it. Each parameter is tagged here or in the schedule it extends.
7
7
  targets:
8
- files: [figure.layout.yaml]
8
+ files: [cells.layout.yaml]
9
9
  cadence:
10
10
  interval:
11
11
  unit: week
@@ -0,0 +1,48 @@
1
+ name: passenger_toggles
2
+ version: 0
3
+ description: Airline passengers in March, July and November of each year, each month and July's mean shown or hidden on the HTML page.
4
+ extends: None
5
+ parameters: !var
6
+ specifications:
7
+ graph_type: xy
8
+ theme: forgegraph_default/light_theme
9
+ format: forgegraph_default/compact_format
10
+ text:
11
+ title: Airline passengers by month
12
+ data:
13
+ file: air_passengers_by_month.parquet
14
+ preprocessing: examples/sample-data/air_passengers_by_month.csv, unchanged
15
+ axis:
16
+ x:
17
+ data:
18
+ column: Year
19
+ title: None
20
+ y:
21
+ title: Passengers (thousands)
22
+ series:
23
+ July:
24
+ column: Jul
25
+ March:
26
+ column: Mar
27
+ November:
28
+ column: Nov
29
+ legend:
30
+ method: direct
31
+ key:
32
+ title:
33
+ text: None
34
+ layers:
35
+ mean:
36
+ type: reference
37
+ axis: y
38
+ line_1:
39
+ value: Jul
40
+ aggregation:
41
+ function: mean
42
+ label:
43
+ text: aggregation_value
44
+ show:
45
+ type: toggle
46
+ label: Show
47
+ items: [series, mean]
48
+ hidden: [mean]
@@ -0,0 +1,38 @@
1
+ name: penguin_measures
2
+ version: 0
3
+ description: A penguin measurement against bill length for three species, the measurement chosen on the HTML page.
4
+ extends: None
5
+ parameters: !var
6
+ specifications:
7
+ graph_type: xy
8
+ theme: forgegraph_default/light_theme
9
+ format: forgegraph_default/compact_format
10
+ text:
11
+ title: Penguin measurements
12
+ data:
13
+ file: penguins.parquet
14
+ preprocessing: examples/sample-data/penguins.csv, unchanged
15
+ axis:
16
+ x:
17
+ data:
18
+ column: bill_length_mm
19
+ title: Bill length (mm)
20
+ y:
21
+ title: Bill depth (mm)
22
+ series:
23
+ measure:
24
+ column: bill_depth_mm
25
+ color: species
26
+ line:
27
+ show: false
28
+ marker:
29
+ shape: species
30
+ size: 0.3
31
+ layers:
32
+ measure:
33
+ type: choice
34
+ label: Measurement
35
+ views:
36
+ Bill depth: {}
37
+ Flipper length: {series.measure.column: flipper_length_mm, axis.y.title: Flipper length (mm)}
38
+ Body mass: {series.measure.column: body_mass_g, axis.y.title: Body mass (g)}
@@ -27,8 +27,8 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
27
27
                      direction: ascending          *# \[ascending, descending\]; The direction of the category order.*\
28
28
              title: column_name          *# \[None, column_name, text\]; The axis title. column_name uses the name of data.column if it's the base_axis or the series' column if it's not. With several series, use text or None.*\
29
29
              scale: linear          *# \[linear, log\]; The axis scale.*\
30
-             min: None          *# \[None, float, date\]; The axis minimum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the lowest value minus plot_area.gap × the data's range.*\
31
-             max: None          *# \[None, float, date\]; The axis maximum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the highest value plus plot_area.gap × the data's range.*\
30
+             min: None          *# \[None, float, date, IQR rule\]; The axis minimum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the lowest value minus plot_area.gap × the data's range. 3IQR moves it in to the lower quartile minus 3 × the interquartile range.*\
31
+             max: None          *# \[None, float, date, IQR rule\]; The axis maximum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the highest value plus plot_area.gap × the data's range. 3IQR moves it in to the upper quartile plus 3 × the interquartile range.*\
32
32
              tick:\
33
33
                  algorithm: auto          *# \[auto, all, manual, none\]; How the ticks are placed. auto uses the theme's algorithm, or on dates, the boundaries of one calendar unit. all places a tick at every value. manual places one every tick.step. none draws no ticks or tick labels.*\
34
34
                  step: None          *# \[None, float > 0, text\]; The distance between ticks when algorithm is manual, e.g. 5 or "2 week". On a log axis, it's a factor.*\
@@ -43,8 +43,8 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
43
43
                      direction: ascending          *# \[ascending, descending\]; The direction of the category order.*\
44
44
              title: column_name          *# \[None, column_name, text\]; The axis title. column_name uses the name of data.column if it's the base_axis or the series' column if it's not. With several series, use text or None.*\
45
45
              scale: linear          *# \[linear, log\]; The axis scale.*\
46
-             min: None          *# \[None, float, date\]; The axis minimum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the lowest value minus plot_area.gap × the data's range.*\
47
-             max: None          *# \[None, float, date\]; The axis maximum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the highest value plus plot_area.gap × the data's range.*\
46
+             min: None          *# \[None, float, date, IQR rule\]; The axis minimum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the lowest value minus plot_area.gap × the data's range. 3IQR moves it in to the lower quartile minus 3 × the interquartile range.*\
47
+             max: None          *# \[None, float, date, IQR rule\]; The axis maximum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the highest value plus plot_area.gap × the data's range. 3IQR moves it in to the upper quartile plus 3 × the interquartile range.*\
48
48
              tick:\
49
49
                  algorithm: auto          *# \[auto, all, manual, none\]; How the ticks are placed. auto uses the theme's algorithm, or on dates, the boundaries of one calendar unit. all places a tick at every value. manual places one every tick.step. none draws no ticks or tick labels.*\
50
50
                  step: None          *# \[None, float > 0, text\]; The distance between ticks when algorithm is manual, e.g. 5 or "2 week". On a log axis, it's a factor.*\
@@ -73,7 +73,7 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
73
73
                  missing_values: drop          *# \[drop, gap\]; What happens to rows missing x or y. drop joins the line across them, and gap breaks the line. Lint counts both in dropped-rows.*\
74
74
              marker:\
75
75
                  show: true          *# \[true, false\]; Whether to draw markers.*\
76
-                 shape: first          *# \[first, series, circle, square, triangle_up, triangle_down, diamond, cross, plus, grid_cell, column\]; The marker shape. first is the theme's first marker shape, series takes the next one, and a column gives each of its values its own. grid_cell fills the grid the points lie on, for a heat map.*\
76
+                 shape: first          *# \[first, series, circle, square, triangle_up, triangle_down, diamond, cross, plus, star, asterisk, grid_cell, column\]; The marker shape. first is the theme's first marker shape, series takes the next one, and a column gives each of its values its own. grid_cell fills the grid the points lie on, for a heat map.*\
77
77
                  fill: first          *# \[first, series, filled, open, column\]; The marker fill. first is the theme's first marker fill, series takes the next one, and a column gives each of its values its own.*\
78
78
                  size: 0.5          *# \[float > 0\]; The marker size, × base size.*\
79
79
              bar:\
@@ -3,7 +3,7 @@
3
3
  This page mirrors src/forgegraph/packs/forgegraph_default/pack.yaml, which is the specification. A test fails if they ever differ.
4
4
 
5
5
  name: forgegraph_default          *# \[text\]; The pack's name, which its specs' names start with (pack/name); a pip pack's must match its entry point.*\
6
- version: 0.7.0          *# \[text\]; The pack's release version.*\
6
+ version: 0.8.0          *# \[text\]; The pack's release version.*\
7
7
  description: ForgeGraph's built-in default pack. So it’s always possible to create a graph.          *# \[text\]; One line, describing what the pack is.*\
8
8
  issues: https://github.com/sskaye/forgegraph/issues          *# \[text\]; Where to file feature requests and bug reports about the pack.*\
9
- requires: ">=0.7, <0.8"          *# \[None, version specifier\]; The ForgeGraph version required for the pack. pip format, e.g. ">=0.6, <1". If None, it works with any version.*
9
+ requires: ">=0.8, <0.9"          *# \[None, version specifier\]; The ForgeGraph version required for the pack. pip format, e.g. ">=0.6, <1". If None, it works with any version.*
@@ -27,6 +27,7 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
27
27
          size: 1.05          *# \[float > 0\]; The size, × base size.*\
28
28
          weight: semibold          *# \[light, regular, medium, semibold, bold\]; The weight.*\
29
29
          gap: 0.41          *# \[float ≥ 0\]; The gap between the text and whatever is around it, × base size.*\
30
+         max_wrap: 0          *# \[int ≥ 0\]; The number of times the title may wrap onto a new line to fit above the plot. If 0, it never wraps.*\
30
31
      axis:\
31
32
          title:          *# \[text style\]; The axis titles.*\
32
33
              size: 1.05          *# \[float > 0\]; The size, × base size.*\
@@ -67,7 +68,7 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
67
68
              width: 0.15          *# \[float ≥ 0\]; The width, × base size. If 0, no line is drawn.*\
68
69
              styles: !fix \[solid, dashed, dotted, dashdot\]          *# \[solid, dashed, dotted, dashdot\]; The line styles given to the series, or to the values of a series' line.style column.*\
69
70
          marker:\
70
-             shapes: !fix \[circle, square, triangle_up, diamond, triangle_down, cross\]          *# \[circle, square, triangle_up, triangle_down, diamond, cross, plus\]; The marker shapes given to the series, or to the values of a series' marker.shape column.*\
71
+             shapes: !fix \[circle, square, triangle_up, diamond, triangle_down, cross\]          *# \[circle, square, triangle_up, triangle_down, diamond, cross, plus, star, asterisk\]; The marker shapes given to the series, or to the values of a series' marker.shape column.*\
71
72
              fills: !fix \[filled, open\]          *# \[filled, open\]; The marker fills given to the series, or to the values of a series' marker.fill column. open draws only the outline.*\
72
73
              size: 0.5          *# \[float > 0\]; The marker size, × base size.*\
73
74
              edge:          *# \[line style\]; The outline of filled markers. Open markers are outlined at its width, in their series' color.*\
@@ -139,6 +140,10 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
139
140
              size: 0.8          *# \[float > 0\]; The size, × base size.*\
140
141
              color: "#404040"          *# \[hex color\]; The color.*\
141
142
              gap: 0.5          *# \[float ≥ 0\]; The gap between the text and whatever is around it, × base size.*\
143
+         choice:          *# \[text style\]; A choice layer's label and its views' names on an HTML page. Its gap is between the label and the control.*\
144
+             alignment: left          *# \[left, center, right\]; The text alignment.*\
145
+         toggle:          *# \[text style\]; A toggle layer's label and its items' names on an HTML page. Its gap is between the label and the checkboxes.*\
146
+             alignment: left          *# \[left, center, right\]; The text alignment.*\
142
147
      watermark:          *# \[text style\]; The watermark drawn on non-standard graphs.*\
143
148
          weight: bold          *# \[light, regular, medium, semibold, bold\]; The weight.*\
144
149
          color: "#CC0000"          *# \[hex color\]; The color.*\
@@ -16,7 +16,7 @@ These are the polarization curves of three fuel cells, from `cell_polarization.c
16
16
  - **extends** is the GraphSpec this one builds on. With `None`, the file lists every parameter it sets, and `!var` on `parameters` lets a GraphSpec that extends it change any of them (see [Building on a GraphSpec](#building-on-a-graphspec)).
17
17
  - **specifications** names the graph type, the theme and the format. The theme sets the look and the format sets the size and the file types. Both come from a [pack](themes-formats-packs.md), and are named `pack/name`.
18
18
  - **data.file** is the Parquet file holding the DataFrame, as a path from the GraphSpec's folder. `data.preprocessing` says where the code that made it is; it's recorded in the saved files and never read.
19
- - **axis.x.data.column** is the column along the x-axis. Each axis can also set its `title`, `scale` (`linear` or `log`), `min` and `max`, its ticks and their label format.
19
+ - **axis.x.data.column** is the column along the x-axis. Each axis can also set its `title`, `scale` (`linear` or `log`), `min` and `max`, its ticks and their label format. `max: 3IQR` keeps a few far outliers from squashing the data: the axis stops at the upper quartile plus 3 × the interquartile range, where that's nearer than it would be, and lint counts the points beyond it.
20
20
  - **series** lists what's drawn against it, each under its name. A series draws the column with its name unless it sets `column`, and `color: cell` gives each cell its own color. The [Series guide](series.md) covers the rest.
21
21
 
22
22
  Titles are written in label markup: `^2` or `^{...}` makes a superscript and `_{...}` a subscript, so `A/cm^2` draws as A/cm². A column's name is always drawn as it's written.
@@ -29,7 +29,7 @@ Every parameter, with its default, the values it allows and its description, is
29
29
  forgegraph render polarization.yaml
30
30
  ```
31
31
 
32
- `render` saves the graph in each file type its format lists, beside the GraphSpec, and reports the lint. `--out` saves it elsewhere, and a suffix there picks one file type: `--out curves.svg`.
32
+ `render` saves the graph in each file type its format lists, beside the GraphSpec, and reports the lint. `--out` saves it elsewhere, and a suffix there picks one file type: `--out curves.svg`. In an SVG, each part of a series or a layer has an id that names it, such as `fg-series-Cell_A-1` for a series' line or `fg-layer-target-1` for a reference line, so a page can style or hide a whole series by the start of its ids.
33
33
 
34
34
  The format's file types, size and resolution can be set in the GraphSpec too, where the format allows it. The built-in formats allow all of them:
35
35
 
@@ -1,6 +1,6 @@
1
1
  # Layers
2
2
 
3
- Layers are drawn over a graph: reference lines and bands, error bars, and notes. A GraphSpec lists its layers under `layers`, each under a name it chooses, with its `type`. They're drawn in the order they're listed. The [layer specifications](../reference/specifications/layer_reference.md) list every parameter.
3
+ Layers are drawn over a graph: reference lines and bands, error bars, and notes. Choice and toggle layers add controls to the graph's HTML page instead. A GraphSpec lists its layers under `layers`, each under a name it chooses, with its `type`. They're drawn in the order they're listed. The [layer specifications](../reference/specifications/layer_reference.md) list every parameter.
4
4
 
5
5
  ## Reference lines and bands
6
6
 
@@ -54,6 +54,39 @@ A `note` layer writes a block of text in or around the plot. Its `text` is writt
54
54
 
55
55
  ![The mean response of three compounds at each dose, with error bars and the note Mean ± SD of 3 replicates in the lower right.](../images/dose_response.png){ width="480" }
56
56
 
57
+ ## Views
58
+
59
+ A `choice` layer draws nothing on the graph. It lists views, and the graph's HTML page gets a control that switches between them. Each view is a set of the GraphSpec's parameters and their values, under the name the control shows, such as another column for a series and its axis title; `{}` changes nothing. ForgeGraph draws every view ahead of time, so the page needs no server. A png, pdf or svg file shows the first view. Every view has the same figure size and plot box, so the graph stays put as the views switch.
60
+
61
+ ```yaml
62
+ --8<-- "docs/examples/penguin_measures.yaml"
63
+ ```
64
+
65
+ [Open its HTML page](../pages/penguin_measures.html) to choose the measurement.
66
+
67
+ - **control** shows the views' names as a `dropdown`, or as `radio` buttons, and **label** is the text before it.
68
+ - **position** puts the control to the figure's `right` (the default), with the label above it, or at its `top` or `bottom`, with the label before it. On a narrow window, the right side moves below the figure.
69
+ - A view can't change the data, the specifications, output or provenance. Each view is checked as the GraphSpec it makes, so a view can set a parameter only where the GraphSpec could.
70
+ - Two choice layers, such as one for each axis, draw every combination of their views: four views each make 16 images. The page's size, and the time it takes to draw, grow with the number of images. Two choice layers can't set the same parameter.
71
+ - In a layout, choice layers of the same name in several tiles share one control, which switches every tile that has it. Their views need the same names, in the same order, and the same position.
72
+
73
+ ## Toggles
74
+
75
+ A `toggle` layer adds a checkbox to the graph's HTML page for each of its `items`, which shows the item when it's checked: `series` for every series, `layers` for every layer, or series and layers by name. `hidden` lists those hidden when the page opens, and png, pdf and svg files leave them out too.
76
+
77
+ ```yaml
78
+ --8<-- "docs/examples/passenger_toggles.yaml"
79
+ ```
80
+
81
+ [Open its HTML page](../pages/passenger_toggles.html) to show July's mean, or hide a month.
82
+
83
+ - **label** is the text before the checkboxes, and **position** puts them to the figure's `right`, one under another, or in a row at its `top` or `bottom`.
84
+ - A series named in a key gets its checkbox in the key, before its sample, on the page only: png, pdf and svg files are drawn without the room for it.
85
+ - The graph is drawn once, with everything shown, so the axes don't change when an item is hidden, and the key keeps its entries.
86
+ - A hidden series loses its lines, markers, bars, error bars, value labels, direct label and readouts. A hidden layer loses its lines, fill and label.
87
+ - The page cuts the figure into images laid over each other, in the order the figure draws them, so it grows with the number of items. With choice layers, each view has its own.
88
+ - A GraphSpec has at most one toggle layer. In a layout, the items of the same name in tiles with toggle layers share one checkbox, so they start hidden in every tile or in none, and the toggle layers share one list, so they need the same position.
89
+
57
90
  ## The layers' look
58
91
 
59
- Each layer's lines, labels, fill and text take their look from the theme's `layer` category. A layer may set the parts its theme marks `!var`, such as `line_1.line.style: None` above, which draws a band without its edges.
92
+ Each layer's lines, labels, fill and text take their look from the theme's `layer` category: a choice or toggle layer's text from `layer.choice` and `layer.toggle`. A layer may set the parts its theme marks `!var`, such as `line_1.line.style: None` above, which draws a band without its edges.
@@ -56,7 +56,7 @@ Tabs that hold tabs look like this, with a tab bar for each level on the HTML pa
56
56
 
57
57
  ## The HTML page
58
58
 
59
- A layout's HTML page, or a GraphSpec's, shows each figure as an image that shrinks to fit a narrow window. On a layout of several tabs, the tab names sit above the figures, in `tab_bar.label`'s look, with `tab_bar.line` under them; by default, they follow the first tile's theme. The tabs work where the page's scripts don't run. Where they run, each tab also has its own link, such as `#by-instrument`. The tab names stay at the top of the window as the page scrolls, and switching tabs leaves the page where it is, so the same tile stays in view.
59
+ A layout's HTML page, or a GraphSpec's, shows each figure as an image that shrinks to fit a narrow window. On a layout of several tabs, the tab names sit above the figures, in `tab_bar.label`'s look, with `tab_bar.line` under them; by default, they follow the first tile's theme. The tabs work where the page's scripts don't run. Where they run, each tab also has its own link, such as `#by-instrument`. The tab names stay at the top of the window as the page scrolls, and switching tabs leaves the page where it is, so the same tile stays in view. A tile's [choice](layers.md#views) and [toggle](layers.md#toggles) layers add their controls under the tab names, and a control shows only on the tabs that use it.
60
60
 
61
61
  **Readouts.** Pointing at a data point on the page, or tapping it, shows its values in a box above it, with a ring around the point:
62
62
 
@@ -4,10 +4,10 @@ A **schedule** re-renders GraphSpecs and layouts on a cadence, so a dashboard ke
4
4
 
5
5
  ## A schedule file
6
6
 
7
- This one, from the agent skill's examples, renders a layout every weekday at 06:00:
7
+ This one, which the agent skill also uses as its example, renders a layout every weekday at 06:00:
8
8
 
9
9
  ```yaml
10
- --8<-- "src/forgegraph/skill/forgegraph/examples/figure.schedule.yaml"
10
+ --8<-- "docs/examples/cells.schedule.yaml"
11
11
  ```
12
12
 
13
13
  - **targets.files** are the GraphSpec and layout files rendered on each run, as paths from the schedule's folder. `targets.output_folder` saves their outputs elsewhere; by default, each is saved beside its file.
@@ -20,7 +20,7 @@ A schedule usually extends the built-in pack's `schedule`, or a pack's own, such
20
20
  ## Running it
21
21
 
22
22
  ```bash
23
- forgegraph job run figure.schedule.yaml
23
+ forgegraph job run cells.schedule.yaml
24
24
  ```
25
25
 
26
26
  `job run` runs the schedule once: it renders every target, writes the status file, and runs on_failure or on_success. A target that fails is recorded, and the others still render; the command exits with 1 if any failed.
@@ -28,7 +28,7 @@ forgegraph job run figure.schedule.yaml
28
28
  ForgeGraph doesn't schedule the command itself. Whatever schedules commands where you work runs it at the schedule's times: cron, launchd, systemd, Task Scheduler, a GitHub Actions workflow, or an agent's scheduled task. For the schedule above, a cron line is:
29
29
 
30
30
  ```text
31
- 0 6 * * 1-5 forgegraph job run /path/to/figure.schedule.yaml
31
+ 0 6 * * 1-5 forgegraph job run /path/to/cells.schedule.yaml
32
32
  ```
33
33
 
34
34
  Each run renders the data files as they are; keeping them current is up to you. On macOS, a background job that writes into a cloud-synced folder needs Full Disk Access.
@@ -47,7 +47,7 @@ A series' rows can be split into groups by a column. Each of `color`, `line.styl
47
47
 
48
48
  ## Combining rows
49
49
 
50
- `aggregation` combines the rows at each x into one point: their mean, median, sum, minimum, maximum, a percentile, standard deviation, standard error, or half the 95 % confidence interval of the mean (`ci`). `multiplier` scales the result, and `percentile` sets which percentile.
50
+ `aggregation` combines the rows at each x into one point: their mean, median, sum, minimum, maximum, a percentile, standard deviation, standard error, or half the 95 % confidence interval of the mean (`ci`). `multiplier` scales the result, and `percentile` sets which percentile. For positive values that vary by a factor, such as ratios or concentrations, `geom_mean` is the geometric mean, worked on the values' logs. `geom_stddev` and `geom_ci` are the geometric standard deviation and the 95 % confidence interval of the geometric mean: as a reference line's offset or an error bar, they multiply and divide, so an error bar's two sides differ.
51
51
 
52
52
  ```yaml
53
53
  aggregation:
@@ -38,7 +38,7 @@ Use a linear scale, or leave those values out.
38
38
 
39
39
  ### outside-limits
40
40
 
41
- Points lie beyond an axis's fixed `min` or `max`, so they aren't drawn.
41
+ Points, or a reference line or part of a band, lie beyond an axis's fixed `min` or `max`, so they aren't drawn.
42
42
 
43
43
  Widen the limits, or set them to None so the axis fits the data.
44
44
 
@@ -116,6 +116,14 @@ titel: unknown category; did you mean 'title'?
116
116
 
117
117
  A misspelled or misplaced parameter, with the nearest one ForgeGraph knows. The [specifications](../reference/specifications/index.md) list every parameter in its place.
118
118
 
119
+ ### A title too long for the figure
120
+
121
+ ```text
122
+ text.title: too long for the figure: the title is 631 pt wide, and the figure 419 pt; ...
123
+ ```
124
+
125
+ Shorten the title, put line breaks in it, or let a theme wrap it: `title.max_wrap` is how many more lines a title may take. It's 0, no wrapping, in the built-in theme.
126
+
119
127
  ### No way to name the series
120
128
 
121
129
  ```text
@@ -11,7 +11,6 @@ baseline: forgegraph_default/graphspec_example          *# \[graphspec
11
11
  baselines:          *# Generic scenarios, each the baseline with one or more changes, numbered in the order they're first used. Every parameter gets one card, chosen by a rule: the first candidate value that changes the drawing, on the baseline or on the first of these scenarios where it does. The page shows the cards of the variable parameters. If there are no scenarios, this is None.*\
12
12
      key_shown: {legend.method: key}          *# \[parameters and their values, or non-standard\]; Series named in a key, so the key's parameters act.*\
13
13
      colored_by_temperature: {series.color: "Temperature (°C)"}          *# \[parameters and their values, or non-standard\]; A numeric color column, so a color bar is drawn.*\
14
-     colored_by_run: {series.color: Run}          *# \[parameters and their values, or non-standard\]; Colored by run, a column of numbers, so auto draws a color scale.*\
15
14
      temperatures:          *# \[parameters and their values, or non-standard\]; Each cell's peak power density at each temperature it ran at.*\
16
15
          axis.x.data.column: "Temperature (°C)"\
17
16
          series: {"Power Density (mW/cm²)": {color: Cell, split: None, aggregation: {function: max}}}\
@@ -52,4 +51,5 @@ baselines:          *# Generic scenarios, each the baseline with one o
52
51
          axis.y.data.column: Cell\
53
52
          axis.x.data.column: None\
54
53
          series: {"Temperature (°C)": {color: series, split: None, aggregation: {function: max}, line: {show: false}}}\
55
-     dated: {data.file: dated.parquet, axis.x.data.column: Date}          *# \[parameters and their values, or non-standard\]; Daily dates on x.*
54
+     dated: {data.file: dated.parquet, axis.x.data.column: Date}          *# \[parameters and their values, or non-standard\]; Daily dates on x.*\
55
+     temperature_key_outside: {series.color: "Temperature (°C)", legend.key.inside: false}          *# \[parameters and their values, or non-standard\]; A numeric color column with any key outside the plot area, so a key of each temperature fits.*
@@ -28,8 +28,8 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
28
28
                      direction: ascending          *# \[ascending, descending\]; The direction of the category order.*\
29
29
              title: column_name          *# \[None, column_name, text\]; The axis title. column_name uses the name of data.column if it's the base_axis or the series' column if it's not. With several series, use text or None.*\
30
30
              scale: linear          *# \[linear, log\]; The axis scale.*\
31
-             min: None          *# \[None, float, date\]; The axis minimum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the lowest value minus plot_area.gap × the data's range.*\
32
-             max: None          *# \[None, float, date\]; The axis maximum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the highest value plus plot_area.gap × the data's range.*\
31
+             min: None          *# \[None, float, date, IQR rule\]; The axis minimum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the lowest value minus plot_area.gap × the data's range. 3IQR moves it in to the lower quartile minus 3 × the interquartile range.*\
32
+             max: None          *# \[None, float, date, IQR rule\]; The axis maximum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the highest value plus plot_area.gap × the data's range. 3IQR moves it in to the upper quartile plus 3 × the interquartile range.*\
33
33
              tick:\
34
34
                  algorithm: auto          *# \[auto, all, manual, none\]; How the ticks are placed. auto uses the theme's algorithm, or on dates, the boundaries of one calendar unit. all places a tick at every value. manual places one every tick.step. none draws no ticks or tick labels.*\
35
35
                  step: None          *# \[None, float > 0, text\]; The distance between ticks when algorithm is manual, e.g. 5 or "2 week". On a log axis, it's a factor.*\
@@ -44,8 +44,8 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
44
44
                      direction: ascending          *# \[ascending, descending\]; The direction of the category order.*\
45
45
              title: column_name          *# \[None, column_name, text\]; The axis title. column_name uses the name of data.column if it's the base_axis or the series' column if it's not. With several series, use text or None.*\
46
46
              scale: linear          *# \[linear, log\]; The axis scale.*\
47
-             min: None          *# \[None, float, date\]; The axis minimum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the lowest value minus plot_area.gap × the data's range.*\
48
-             max: None          *# \[None, float, date\]; The axis maximum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the highest value plus plot_area.gap × the data's range.*\
47
+             min: None          *# \[None, float, date, IQR rule\]; The axis minimum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the lowest value minus plot_area.gap × the data's range. 3IQR moves it in to the lower quartile minus 3 × the interquartile range.*\
48
+             max: None          *# \[None, float, date, IQR rule\]; The axis maximum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the highest value plus plot_area.gap × the data's range. 3IQR moves it in to the upper quartile plus 3 × the interquartile range.*\
49
49
              tick:\
50
50
                  algorithm: auto          *# \[auto, all, manual, none\]; How the ticks are placed. auto uses the theme's algorithm, or on dates, the boundaries of one calendar unit. all places a tick at every value. manual places one every tick.step. none draws no ticks or tick labels.*\
51
51
                  step: None          *# \[None, float > 0, text\]; The distance between ticks when algorithm is manual, e.g. 5 or "2 week". On a log axis, it's a factor.*\
@@ -74,7 +74,7 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
74
74
                  missing_values: drop          *# \[drop, gap\]; What happens to rows missing x or y. drop joins the line across them, and gap breaks the line. Lint counts both in dropped-rows.*\
75
75
              marker:\
76
76
                  show: true          *# \[true, false\]; Whether to draw markers.*\
77
-                 shape: first          *# \[first, series, circle, square, triangle_up, triangle_down, diamond, cross, plus, grid_cell, column\]; The marker shape. first is the theme's first marker shape, series takes the next one, and a column gives each of its values its own. grid_cell fills the grid the points lie on, for a heat map.*\
77
+                 shape: first          *# \[first, series, circle, square, triangle_up, triangle_down, diamond, cross, plus, star, asterisk, grid_cell, column\]; The marker shape. first is the theme's first marker shape, series takes the next one, and a column gives each of its values its own. grid_cell fills the grid the points lie on, for a heat map.*\
78
78
                  fill: first          *# \[first, series, filled, open, column\]; The marker fill. first is the theme's first marker fill, series takes the next one, and a column gives each of its values its own.*\
79
79
                  size: 0.5          *# \[float > 0\]; The marker size, × base size.*\
80
80
              bar:\
@@ -126,4 +126,16 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
126
126
                      text: Target 1.2 V          *# \[None, aggregation, value, aggregation_value, text\]; aggregation writes e.g. Mean, value e.g. 14.9, and aggregation_value e.g. Mean: 14.9. With an equation, value writes e.g. y = 2x. Other text is written as given.*\
127
127
          conditions:\
128
128
              type: note          *# \[layer type\]; The layer's type: one of the graph type's layer.types.*\
129
-             text: "60 °C, 1 atm, H₂/air"          *# \[text\]; The note's text, in label markup. A line break starts a new line.*
129
+             text: "60 °C, 1 atm, H₂/air"          *# \[text\]; The note's text, in label markup. A line break starts a new line.*\
130
+         metric:\
131
+             type: choice          *# \[layer type\]; The layer's type: one of the graph type's layer.types.*\
132
+             label: Metric          *# \[None, text\]; The text before the control, e.g. Metric. If None, there is none.*\
133
+             position: right          *# \[top, bottom, right\]; Where the control is on the HTML page: above the figure, below it, or to its right, with the label above it.*\
134
+             views:          *# The views, each under the name the control shows. A GraphSpec lists two or more, and the page opens on the first.*\
135
+                 Voltage: {}          *# \[parameters and their values\]; What the view changes, e.g. a series' column and the y-axis title. {} changes nothing.*\
136
+                 Power: {series.SERIES_1.column: Power Density (mW/cm²), axis.y.title: Power density (mW/cm²)}          *# \[parameters and their values\]; A series' column and the y-axis title.*\
137
+         hide:\
138
+             type: toggle          *# \[layer type\]; The layer's type: one of the graph type's layer.types.*\
139
+             label: Show          *# \[None, text\]; The text before the checkboxes, e.g. Show. If None, there is none.*\
140
+             position: right          *# \[top, bottom, right\]; Where the checkboxes are on the HTML page: above the figure, below it, or to its right, under the label.*\
141
+             items: \[series, target\]          *# \[series, layers, text\]; What can be hidden: series for all series, layers for all layers, or those named.*
@@ -18,8 +18,8 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
18
18
                      direction: ascending          *# \[ascending, descending\]; The direction of the category order.*\
19
19
              title: column_name          *# \[None, column_name, text\]; The axis title. column_name uses the name of data.column if it's the base_axis or the series' column if it's not. With several series, use text or None.*\
20
20
              scale: linear          *# \[linear, log\]; The axis scale.*\
21
-             min: None          *# \[None, float, date\]; The axis minimum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the lowest value minus plot_area.gap × the data's range.*\
22
-             max: None          *# \[None, float, date\]; The axis maximum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the highest value plus plot_area.gap × the data's range.*\
21
+             min: None          *# \[None, float, date, IQR rule\]; The axis minimum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the lowest value minus plot_area.gap × the data's range. 3IQR moves it in to the lower quartile minus 3 × the interquartile range.*\
22
+             max: None          *# \[None, float, date, IQR rule\]; The axis maximum. On a datetime axis, it's a date, e.g. 2025-08-25 or "2025-08-25T06:00". If None, it's the highest value plus plot_area.gap × the data's range. 3IQR moves it in to the upper quartile plus 3 × the interquartile range.*\
23
23
              tick:\
24
24
                  algorithm: auto          *# \[auto, all, manual, none\]; How the ticks are placed. auto uses the theme's algorithm, or on dates, the boundaries of one calendar unit. all places a tick at every value. manual places one every tick.step. none draws no ticks or tick labels.*\
25
25
                  step: None          *# \[None, float > 0, text\]; The distance between ticks when algorithm is manual, e.g. 5 or "2 week". On a log axis, it's a factor.*\
@@ -48,7 +48,7 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
48
48
                  missing_values: drop          *# \[drop, gap\]; What happens to rows missing x or y. drop joins the line across them, and gap breaks the line. Lint counts both in dropped-rows.*\
49
49
              marker:\
50
50
                  show: true          *# \[true, false\]; Whether to draw markers.*\
51
-                 shape: first          *# \[first, series, circle, square, triangle_up, triangle_down, diamond, cross, plus, grid_cell, column\]; The marker shape. first is the theme's first marker shape, series takes the next one, and a column gives each of its values its own. grid_cell fills the grid the points lie on, for a heat map.*\
51
+                 shape: first          *# \[first, series, circle, square, triangle_up, triangle_down, diamond, cross, plus, star, asterisk, grid_cell, column\]; The marker shape. first is the theme's first marker shape, series takes the next one, and a column gives each of its values its own. grid_cell fills the grid the points lie on, for a heat map.*\
52
52
                  fill: first          *# \[first, series, filled, open, column\]; The marker fill. first is the theme's first marker fill, series takes the next one, and a column gives each of its values its own.*\
53
53
              bar:\
54
54
                  show: false          *# \[true, false\]; Whether to draw bars. Bars start at 0, or at 1 on a log axis, and the value axis then always includes that value.*\
@@ -71,4 +71,5 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
71
71
              title:\
72
72
                  text: column_name          *# \[None, column_name, text\]; The color bar's title. column_name uses the name of the series' color column. If None, there is no title.*\
73
73
      layer:\
74
-         types: !fix \[reference, note, error_bar\]          *# \[layer types\]; The layer types that a GraphSpec of this graph type may use.*
74
+         types: !fix \[reference, note, error_bar, choice, toggle\]          *# \[layer types\]; The layer types that a GraphSpec of this graph type may use.*
75
+
@@ -0,0 +1,15 @@
1
+ # Layer specification: choice
2
+
3
+ This page mirrors src/forgegraph/specifications/layer_choice.yaml, which is the specification. A test fails if they ever differ.
4
+
5
+ name: choice          *# \[text\]; The name of the layer type.*\
6
+ version: 0          *# \[int ≥ 0\]; The version number of the specification.*\
7
+ description: A control on an HTML page that switches between views, each drawn ahead of time.          *# \[text\]; The description of the layer type.*\
8
+  \
9
+ parameters:          *# \[text style, look from layer.choice\]; The control.*\
10
+     label: None          *# \[None, text\]; The text before the control, e.g. Metric. If None, there is none.*\
11
+     control: dropdown          *# \[dropdown, radio\]; How the page shows the views' names: as a dropdown, or as a row of radio buttons.*\
12
+     position: right          *# \[top, bottom, right\]; Where the control is on the HTML page: above the figure, below it, or to its right, with the label above it.*\
13
+     views:          *# The views, each under the name the control shows. A GraphSpec lists two or more, and the page opens on the first.*\
14
+         VIEW_1: {}          *# \[parameters and their values\]; What the view changes, e.g. a series' column and the y-axis title. {} changes nothing.*
15
+
@@ -0,0 +1,14 @@
1
+ # Layer specification: toggle
2
+
3
+ This page mirrors src/forgegraph/specifications/layer_toggle.yaml, which is the specification. A test fails if they ever differ.
4
+
5
+ name: toggle          *# \[text\]; The name of the layer type.*\
6
+ version: 0          *# \[int ≥ 0\]; The version number of the specification.*\
7
+ description: Checkboxes on an HTML page that show or hide series and layers, each drawn ahead of time.          *# \[text\]; The description of the layer type.*\
8
+  \
9
+ parameters:          *# \[text style, look from layer.toggle\]; The checkboxes.*\
10
+     label: None          *# \[None, text\]; The text before the checkboxes, e.g. Show. If None, there is none.*\
11
+     position: right          *# \[top, bottom, right\]; Where the checkboxes are on the HTML page: above the figure, below it, or to its right, under the label.*\
12
+     items: \[series\]          *# \[series, layers, text\]; What can be hidden: series for all series, layers for all layers, or those named.*\
13
+     hidden: None          *# \[None, texts\]; The series and layers hidden when the page opens. If None, everything is shown.*
14
+
@@ -3,7 +3,7 @@
3
3
  This page mirrors src/forgegraph/specifications/pack.yaml, which is the specification. A test fails if they ever differ.
4
4
 
5
5
  name: forgegraph_specifications          *# \[text\]; The pack's name, which its specs' names start with (pack/name); a pip pack's must match its entry point.*\
6
- version: 0.7.0          *# \[text\]; The pack's release version.*\
6
+ version: 0.8.0          *# \[text\]; The pack's release version.*\
7
7
  description: ForgeGraph's base specs, to define the specifications.          *# \[text\]; One line, describing what the pack is.*\
8
8
  issues: https://github.com/sskaye/forgegraph/issues          *# \[text\]; Where to file feature requests and bug reports about the pack's specs.*\
9
- requires: ">=0.7, <0.8"          *# \[None, version specifier\]; The ForgeGraph versions the pack works with, as pip writes them, e.g. ">=0.6, <1". If None, it works with any version.*
9
+ requires: ">=0.8, <0.9"          *# \[None, version specifier\]; The ForgeGraph versions the pack works with, as pip writes them, e.g. ">=0.6, <1". If None, it works with any version.*
@@ -7,6 +7,6 @@ version: 0          *# \[int ≥ 0\]; The version number of the specif
7
7
  description: Styles that graph types and layers share. A category marked with a style has its parameters, with these defaults, and lists only those it changes.          *# \[text\]; The description of the specification.*\
8
8
   \
9
9
  aggregation_style:          *# How a column's rows are combined into one number. Marked \[aggregation style\].*\
10
-     function: None          *# \[None, mean, median, sum, min, max, percentile, stddev, stderr, ci\]; The aggregate. ci is half the 95 % confidence interval of the mean. If None, each row's value is used.*\
10
+     function: None          *# \[None, mean, median, sum, min, max, percentile, stddev, stderr, ci, geom_mean, geom_stddev, geom_ci\]; The aggregate. ci is half the 95 % confidence interval of the mean. geom\_ functions work on the logs of values above 0; geom_stddev and geom_ci are factors, which multiply as an offset or error bar. If None, each row's value is used.*\
11
11
      multiplier: 1          *# \[float\]; The number the aggregate is multiplied by, e.g. 2 for twice the standard deviation.*\
12
12
      percentile: 50          *# \[0-100\]; The percentile when function is percentile.*
@@ -24,6 +24,7 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
24
24
      background:\
25
25
          color: "#FFFFFF"          *# \[None, hex color\]; The background color of the figure and the plot area. If None, the background is transparent.*\
26
26
      title:          *# \[text style\]; The graph's title. Its gap is measured from the line its letters sit on.*\
27
+         max_wrap: 0          *# \[int ≥ 0\]; The number of times the title may wrap onto a new line to fit above the plot. If 0, it never wraps.*\
27
28
      axis:\
28
29
          title:          *# \[text style\]; The axis titles.*\
29
30
          tick:          *# \[line style\]; The tick marks.*\
@@ -62,7 +63,7 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
62
63
          line:          *# \[line style\]; The series lines.*\
63
64
              styles: \[solid, dashed, dotted, dashdot\]          *# \[solid, dashed, dotted, dashdot\]; The line styles given to the series, or to the values of a series' line.style column.*\
64
65
          marker:\
65
-             shapes: \[circle, square, triangle_up, diamond, triangle_down, cross\]          *# \[circle, square, triangle_up, triangle_down, diamond, cross, plus\]; The marker shapes given to the series, or to the values of a series' marker.shape column.*\
66
+             shapes: \[circle, square, triangle_up, diamond, triangle_down, cross\]          *# \[circle, square, triangle_up, triangle_down, diamond, cross, plus, star, asterisk\]; The marker shapes given to the series, or to the values of a series' marker.shape column.*\
66
67
              fills: \[filled, open\]          *# \[filled, open\]; The marker fills given to the series, or to the values of a series' marker.fill column. open draws only the outline.*\
67
68
              size: 0.5          *# \[float > 0\]; The marker size, × base size.*\
68
69
              edge:          *# \[line style\]; The outline of filled markers. Open markers are outlined at its width, in their series' color.*\
@@ -107,9 +108,12 @@ parameters: !var          *# !var/!fix sets whether a GraphSpec may ch
107
108
                  color: "#808080"          *# \[None, series, hex color\]; The fill color. series uses the series' color. If None, there is no fill.*\
108
109
                  opacity: 0.15          *# \[0-1\]; The fill opacity.*\
109
110
          note:          *# \[text style\]; The notes.*\
111
+         choice:          *# \[text style\]; A choice layer's label and its views' names on an HTML page. Its gap is between the label and the control.*\
112
+         toggle:          *# \[text style\]; A toggle layer's label and its items' names on an HTML page. Its gap is between the label and the checkboxes.*\
110
113
      watermark:          *# \[text style\]; The watermark drawn on non-standard graphs.*\
111
114
          text: NON-STANDARD          *# \[text\]; The watermark's text.*\
112
115
          opacity: 0.18          *# \[0-1\]; The watermark's opacity.*\
113
116
          angle: 30          *# \[-90-90\]; The watermark's angle, in degrees counterclockwise.*\
114
117
          span: 0.8          *# \[0-1\]; The fraction of the plot area's width or height that the watermark spans, whichever it reaches first.*\
115
118
      footnote:          *# \[text style\]; The footnotes below the figure.*
119
+
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "forgegraph"
3
- version = "0.7.0"
3
+ version = "0.8.0"
4
4
  description = "Fast, consistent, publication-quality graphs from pandas DataFrames, usable by people and AI agents."
5
5
  readme = "README.md"
6
6
  license = "MIT AND OFL-1.1"