forgegraph 0.2.0__tar.gz → 0.4.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 (397) hide show
  1. {forgegraph-0.2.0 → forgegraph-0.4.0}/.gitignore +6 -0
  2. {forgegraph-0.2.0 → forgegraph-0.4.0}/.pre-commit-config.yaml +4 -3
  3. forgegraph-0.4.0/CHANGELOG.md +122 -0
  4. forgegraph-0.4.0/CONTRIBUTING.md +44 -0
  5. forgegraph-0.2.0/README.md → forgegraph-0.4.0/PKG-INFO +73 -38
  6. forgegraph-0.2.0/PKG-INFO → forgegraph-0.4.0/README.md +43 -63
  7. {forgegraph-0.2.0/docs → forgegraph-0.4.0/docs/design}/architecture.md +223 -215
  8. forgegraph-0.4.0/docs/design/todo.md +10 -0
  9. forgegraph-0.4.0/docs/packs/acme/formats/slide.md +14 -0
  10. {forgegraph-0.2.0/docs/specs/pack → forgegraph-0.4.0/docs/packs}/acme/graphspecs/polarization-curve.md +14 -18
  11. forgegraph-0.4.0/docs/packs/acme/layouts/dashboard.md +17 -0
  12. {forgegraph-0.2.0/docs/specs/pack → forgegraph-0.4.0/docs/packs}/acme/pack.md +1 -1
  13. forgegraph-0.4.0/docs/packs/acme/schedules/workday.md +16 -0
  14. forgegraph-0.4.0/docs/packs/acme/themes/acme.md +26 -0
  15. forgegraph-0.4.0/docs/packs/forgegraph_default/catalogs/formats/compact_format.md +11 -0
  16. forgegraph-0.4.0/docs/packs/forgegraph_default/catalogs/formats/wide_format.md +11 -0
  17. forgegraph-0.4.0/docs/packs/forgegraph_default/catalogs/themes/light_theme.md +58 -0
  18. forgegraph-0.4.0/docs/packs/forgegraph_default/formats/compact_format.md +35 -0
  19. forgegraph-0.4.0/docs/packs/forgegraph_default/formats/wide_format.md +48 -0
  20. forgegraph-0.4.0/docs/packs/forgegraph_default/graphspecs/graphspec_example.md +116 -0
  21. forgegraph-0.4.0/docs/packs/forgegraph_default/layouts/layout.md +31 -0
  22. forgegraph-0.4.0/docs/packs/forgegraph_default/pack.md +29 -0
  23. forgegraph-0.4.0/docs/packs/forgegraph_default/schedules/schedule.md +30 -0
  24. forgegraph-0.4.0/docs/packs/forgegraph_default/themes/light_theme.md +153 -0
  25. forgegraph-0.4.0/docs/specifications/catalogs/graphtype_xy.md +55 -0
  26. forgegraph-0.4.0/docs/specifications/catalogs/layer_error_bar.md +18 -0
  27. forgegraph-0.4.0/docs/specifications/catalogs/layer_note.md +15 -0
  28. forgegraph-0.4.0/docs/specifications/catalogs/layer_reference.md +35 -0
  29. forgegraph-0.4.0/docs/specifications/config.md +24 -0
  30. forgegraph-0.4.0/docs/specifications/format.md +19 -0
  31. forgegraph-0.4.0/docs/specifications/graphspec_example.md +129 -0
  32. forgegraph-0.4.0/docs/specifications/graphtype_xy.md +74 -0
  33. forgegraph-0.4.0/docs/specifications/layer_error_bar.md +15 -0
  34. forgegraph-0.4.0/docs/specifications/layer_note.md +12 -0
  35. forgegraph-0.4.0/docs/specifications/layer_reference.md +55 -0
  36. forgegraph-0.4.0/docs/specifications/layout_example.md +28 -0
  37. forgegraph-0.4.0/docs/specifications/pack.md +25 -0
  38. {forgegraph-0.2.0/docs/specs/provenance → forgegraph-0.4.0/docs/specifications}/provenance.md +10 -10
  39. forgegraph-0.4.0/docs/specifications/schedule.md +30 -0
  40. forgegraph-0.4.0/docs/specifications/styles.md +12 -0
  41. forgegraph-0.4.0/docs/specifications/theme.md +109 -0
  42. forgegraph-0.4.0/docs/specs_and_packs_revisions/notes.docx +0 -0
  43. forgegraph-0.4.0/examples/layouts/README.md +10 -0
  44. forgegraph-0.4.0/examples/layouts/dashboard/forgegraph.toml +1 -0
  45. forgegraph-0.4.0/examples/layouts/dashboard/lab_throughput.layout.md +37 -0
  46. forgegraph-0.4.0/examples/layouts/dashboard/lab_throughput.layout.yaml +33 -0
  47. forgegraph-0.4.0/examples/layouts/dashboard/lost_runs.parquet +0 -0
  48. forgegraph-0.4.0/examples/layouts/dashboard/lost_runs.yaml +32 -0
  49. forgegraph-0.4.0/examples/layouts/dashboard/ops/formats/dashboard.md +17 -0
  50. forgegraph-0.4.0/examples/layouts/dashboard/ops/formats/dashboard.yaml +13 -0
  51. forgegraph-0.4.0/examples/layouts/dashboard/ops/pack.yaml +5 -0
  52. forgegraph-0.4.0/examples/layouts/dashboard/prep_lab_dashboard.py +40 -0
  53. forgegraph-0.4.0/examples/layouts/dashboard/run_time.parquet +0 -0
  54. forgegraph-0.4.0/examples/layouts/dashboard/run_time.yaml +32 -0
  55. forgegraph-0.4.0/examples/layouts/dashboard/runs_gc_ms_01.yaml +23 -0
  56. forgegraph-0.4.0/examples/layouts/dashboard/runs_hplc_01.yaml +23 -0
  57. forgegraph-0.4.0/examples/layouts/dashboard/runs_hplc_02.yaml +23 -0
  58. forgegraph-0.4.0/examples/layouts/dashboard/runs_icp_oes_01.yaml +23 -0
  59. forgegraph-0.4.0/examples/layouts/dashboard/samples_weekly.yaml +24 -0
  60. forgegraph-0.4.0/examples/layouts/dashboard/throughput_weekly.yaml +25 -0
  61. forgegraph-0.4.0/examples/layouts/dashboard/weekly_gc_ms_01.parquet +0 -0
  62. forgegraph-0.4.0/examples/layouts/dashboard/weekly_hplc_01.parquet +0 -0
  63. forgegraph-0.4.0/examples/layouts/dashboard/weekly_hplc_02.parquet +0 -0
  64. forgegraph-0.4.0/examples/layouts/dashboard/weekly_icp_oes_01.parquet +0 -0
  65. forgegraph-0.4.0/examples/layouts/dashboard/weekly_runs.parquet +0 -0
  66. forgegraph-0.4.0/examples/layouts/dashboard/weekly_samples.parquet +0 -0
  67. forgegraph-0.4.0/examples/layouts/paper/cell_durability.parquet +0 -0
  68. forgegraph-0.4.0/examples/layouts/paper/cell_performance.layout.md +22 -0
  69. forgegraph-0.4.0/examples/layouts/paper/cell_performance.layout.yaml +18 -0
  70. forgegraph-0.4.0/examples/layouts/paper/cell_polarization.parquet +0 -0
  71. forgegraph-0.4.0/examples/layouts/paper/forgegraph.toml +1 -0
  72. forgegraph-0.4.0/examples/layouts/paper/hfr_time.yaml +26 -0
  73. forgegraph-0.4.0/examples/layouts/paper/journal/formats/journal-double.md +16 -0
  74. forgegraph-0.4.0/examples/layouts/paper/journal/formats/journal-double.yaml +12 -0
  75. forgegraph-0.4.0/examples/layouts/paper/journal/pack.yaml +5 -0
  76. forgegraph-0.4.0/examples/layouts/paper/polarization.yaml +24 -0
  77. forgegraph-0.4.0/examples/layouts/paper/prep_cells.py +10 -0
  78. forgegraph-0.4.0/examples/layouts/paper/voltage_time.yaml +26 -0
  79. forgegraph-0.4.0/examples/packs/acme/formats/slide.yaml +10 -0
  80. forgegraph-0.4.0/examples/packs/acme/graphspecs/polarization-curve.yaml +27 -0
  81. forgegraph-0.4.0/examples/packs/acme/layouts/dashboard.yaml +13 -0
  82. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/packs/acme/pack.yaml +1 -1
  83. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/packs/acme/references/house.md +1 -1
  84. forgegraph-0.4.0/examples/packs/acme/schedules/workday.yaml +12 -0
  85. forgegraph-0.4.0/examples/packs/acme/themes/acme.yaml +22 -0
  86. {forgegraph-0.2.0 → forgegraph-0.4.0}/pyproject.toml +12 -10
  87. {forgegraph-0.2.0 → forgegraph-0.4.0}/scripts/build_example_data.py +11 -10
  88. {forgegraph-0.2.0 → forgegraph-0.4.0}/scripts/build_recreations.py +12 -22
  89. {forgegraph-0.2.0 → forgegraph-0.4.0}/scripts/forgemark.py +2 -2
  90. {forgegraph-0.2.0 → forgegraph-0.4.0}/scripts/mirror_specs.py +5 -5
  91. {forgegraph-0.2.0 → forgegraph-0.4.0}/scripts/report_skill_evals.py +4 -4
  92. {forgegraph-0.2.0 → forgegraph-0.4.0}/scripts/run_skill_evals.py +260 -158
  93. {forgegraph-0.2.0 → forgegraph-0.4.0}/scripts/smoke_installed.py +8 -11
  94. {forgegraph-0.2.0 → forgegraph-0.4.0}/scripts/visual_changelog.py +12 -9
  95. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/canvas.py +48 -58
  96. forgegraph-0.4.0/src/forgegraph/catalog_build/build.py +219 -0
  97. forgegraph-0.4.0/src/forgegraph/catalog_build/cards.py +426 -0
  98. forgegraph-0.4.0/src/forgegraph/catalog_build/examples.py +183 -0
  99. forgegraph-0.4.0/src/forgegraph/catalog_build/files.py +258 -0
  100. {forgegraph-0.2.0/src/forgegraph/catalog → forgegraph-0.4.0/src/forgegraph/catalog_build}/page.py +8 -0
  101. forgegraph-0.4.0/src/forgegraph/cli/__init__.py +135 -0
  102. forgegraph-0.4.0/src/forgegraph/cli/catalog.py +219 -0
  103. forgegraph-0.4.0/src/forgegraph/cli/graphs.py +171 -0
  104. forgegraph-0.4.0/src/forgegraph/cli/jobs.py +42 -0
  105. forgegraph-0.4.0/src/forgegraph/cli/schema.py +230 -0
  106. forgegraph-0.4.0/src/forgegraph/cli/skill.py +41 -0
  107. forgegraph-0.4.0/src/forgegraph/data.py +42 -0
  108. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/axes.py +98 -301
  109. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/colorbar.py +51 -21
  110. forgegraph-0.4.0/src/forgegraph/drawing/dates.py +283 -0
  111. forgegraph-0.4.0/src/forgegraph/drawing/errors.py +9 -0
  112. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/export.py +2 -1
  113. forgegraph-0.4.0/src/forgegraph/drawing/figure.py +157 -0
  114. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/key.py +34 -28
  115. forgegraph-0.4.0/src/forgegraph/drawing/labels.py +433 -0
  116. forgegraph-0.4.0/src/forgegraph/drawing/layers.py +874 -0
  117. forgegraph-0.4.0/src/forgegraph/drawing/layout.py +495 -0
  118. forgegraph-0.4.0/src/forgegraph/drawing/limits.py +50 -0
  119. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/lint.py +55 -39
  120. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/marks.py +252 -186
  121. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/spacing.py +29 -19
  122. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/style.py +112 -26
  123. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/text.py +60 -6
  124. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/ticks.py +97 -12
  125. forgegraph-0.4.0/src/forgegraph/drawing/xy.py +1196 -0
  126. forgegraph-0.4.0/src/forgegraph/drawn.py +144 -0
  127. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/__init__.py +28 -7
  128. forgegraph-0.4.0/src/forgegraph/forgemark.py +101 -0
  129. forgegraph-0.4.0/src/forgegraph/graph.py +401 -0
  130. forgegraph-0.4.0/src/forgegraph/jobs/__init__.py +9 -0
  131. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/jobs/run.py +42 -93
  132. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/jobs/status.py +1 -1
  133. forgegraph-0.4.0/src/forgegraph/layouts/__init__.py +553 -0
  134. forgegraph-0.4.0/src/forgegraph/layouts/separators.py +184 -0
  135. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/packs/__init__.py +34 -22
  136. forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default/catalogs/formats/compact_format.yaml +7 -0
  137. forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default/catalogs/formats/wide_format.yaml +7 -0
  138. forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default/catalogs/themes/light_theme.yaml +54 -0
  139. forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default/formats/compact_format.yaml +15 -0
  140. forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default/formats/wide_format.yaml +15 -0
  141. forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default/graphspecs/graphspec_example.yaml +112 -0
  142. forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default/layouts/layout.yaml +27 -0
  143. forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default/pack.yaml +5 -0
  144. forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default/schedules/schedule.yaml +26 -0
  145. forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default/themes/light_theme.yaml +149 -0
  146. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/skill/__init__.py +3 -11
  147. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/skill/forgegraph/SKILL.md +3 -3
  148. forgegraph-0.4.0/src/forgegraph/skill/forgegraph/examples/bars.yaml +32 -0
  149. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/skill/forgegraph/examples/figure.layout.yaml +4 -4
  150. forgegraph-0.4.0/src/forgegraph/skill/forgegraph/examples/figure.schedule.yaml +12 -0
  151. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/skill/forgegraph/examples/layers.yaml +13 -14
  152. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/skill/forgegraph/examples/xy.yaml +7 -10
  153. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/skill/forgegraph/references/themes_formats_configs.md +3 -3
  154. forgegraph-0.4.0/src/forgegraph/spec/__init__.py +12 -0
  155. forgegraph-0.4.0/src/forgegraph/spec/access.py +99 -0
  156. forgegraph-0.4.0/src/forgegraph/spec/common.py +38 -0
  157. forgegraph-0.4.0/src/forgegraph/spec/explain.py +83 -0
  158. forgegraph-0.4.0/src/forgegraph/spec/layers.py +229 -0
  159. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/spec/layout.py +43 -34
  160. forgegraph-0.4.0/src/forgegraph/spec/loaded.py +82 -0
  161. forgegraph-0.4.0/src/forgegraph/spec/parameters.py +858 -0
  162. forgegraph-0.4.0/src/forgegraph/spec/provenance.py +133 -0
  163. forgegraph-0.4.0/src/forgegraph/spec/registry.py +192 -0
  164. forgegraph-0.4.0/src/forgegraph/spec/resolve.py +231 -0
  165. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/spec/schedule.py +12 -10
  166. forgegraph-0.4.0/src/forgegraph/spec/series.py +169 -0
  167. forgegraph-0.4.0/src/forgegraph/spec/tags.py +230 -0
  168. forgegraph-0.4.0/src/forgegraph/spec/validate.py +416 -0
  169. forgegraph-0.4.0/src/forgegraph/specifications/catalogs/graphtype_xy.yaml +51 -0
  170. forgegraph-0.4.0/src/forgegraph/specifications/catalogs/layer_error_bar.yaml +14 -0
  171. forgegraph-0.4.0/src/forgegraph/specifications/catalogs/layer_note.yaml +11 -0
  172. forgegraph-0.4.0/src/forgegraph/specifications/catalogs/layer_reference.yaml +31 -0
  173. forgegraph-0.4.0/src/forgegraph/specifications/config.toml +1 -0
  174. forgegraph-0.4.0/src/forgegraph/specifications/format.yaml +15 -0
  175. forgegraph-0.4.0/src/forgegraph/specifications/graphspec_example.yaml +125 -0
  176. forgegraph-0.4.0/src/forgegraph/specifications/graphtype_xy.yaml +70 -0
  177. forgegraph-0.4.0/src/forgegraph/specifications/layer_error_bar.yaml +11 -0
  178. forgegraph-0.4.0/src/forgegraph/specifications/layer_note.yaml +8 -0
  179. forgegraph-0.4.0/src/forgegraph/specifications/layer_reference.yaml +22 -0
  180. forgegraph-0.4.0/src/forgegraph/specifications/layout_example.yaml +24 -0
  181. forgegraph-0.4.0/src/forgegraph/specifications/pack.yaml +5 -0
  182. {forgegraph-0.2.0/src/forgegraph/spec → forgegraph-0.4.0/src/forgegraph/specifications}/provenance.yaml +9 -9
  183. forgegraph-0.4.0/src/forgegraph/specifications/schedule.yaml +26 -0
  184. forgegraph-0.4.0/src/forgegraph/specifications/styles.yaml +8 -0
  185. forgegraph-0.4.0/src/forgegraph/specifications/theme.yaml +105 -0
  186. forgegraph-0.4.0/tests/baselines/crowded_runs.png +0 -0
  187. forgegraph-0.4.0/tests/baselines/flow_sweep_wide.png +0 -0
  188. forgegraph-0.4.0/tests/baselines/layout_anode_layers.png +0 -0
  189. forgegraph-0.4.0/tests/baselines/layout_screening_and_rate.png +0 -0
  190. forgegraph-0.4.0/tests/baselines/separator_colorbar.png +0 -0
  191. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/conftest.py +2 -2
  192. forgegraph-0.4.0/tests/pack_helpers.py +128 -0
  193. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/recreations.py +70 -84
  194. forgegraph-0.4.0/tests/render_helpers.py +121 -0
  195. forgegraph-0.4.0/tests/spec_mirror.py +204 -0
  196. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_axes.py +156 -43
  197. forgegraph-0.4.0/tests/test_blank.py +105 -0
  198. forgegraph-0.4.0/tests/test_catalog.py +148 -0
  199. forgegraph-0.4.0/tests/test_catalog_files.py +310 -0
  200. forgegraph-0.4.0/tests/test_catalog_inputs.py +131 -0
  201. forgegraph-0.4.0/tests/test_catalog_page.py +81 -0
  202. forgegraph-0.4.0/tests/test_cli.py +483 -0
  203. forgegraph-0.4.0/tests/test_dates.py +478 -0
  204. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_jobs.py +92 -55
  205. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_key_position.py +13 -7
  206. forgegraph-0.4.0/tests/test_labels.py +88 -0
  207. forgegraph-0.4.0/tests/test_layers.py +843 -0
  208. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_layout.py +240 -124
  209. forgegraph-0.4.0/tests/test_lint.py +229 -0
  210. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_marks.py +141 -69
  211. forgegraph-0.4.0/tests/test_packaging.py +30 -0
  212. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_packs.py +128 -88
  213. forgegraph-0.4.0/tests/test_perturbation.py +58 -0
  214. forgegraph-0.4.0/tests/test_regression.py +25 -0
  215. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_render.py +352 -90
  216. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_schedule.py +11 -12
  217. forgegraph-0.4.0/tests/test_series.py +294 -0
  218. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_smoke.py +38 -0
  219. forgegraph-0.4.0/tests/test_spec_comments.py +126 -0
  220. forgegraph-0.4.0/tests/test_specs.py +938 -0
  221. forgegraph-0.4.0/tests/test_styles.py +234 -0
  222. forgegraph-0.4.0/tests/test_tags.py +140 -0
  223. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_text.py +103 -4
  224. {forgegraph-0.2.0 → forgegraph-0.4.0}/uv.lock +3 -3
  225. forgegraph-0.2.0/CHANGELOG.md +0 -48
  226. forgegraph-0.2.0/CONTRIBUTING.md +0 -39
  227. forgegraph-0.2.0/docs/build-plan.md +0 -382
  228. forgegraph-0.2.0/docs/decisions.md +0 -222
  229. forgegraph-0.2.0/docs/forgemark-repro-reattach.md +0 -80
  230. forgegraph-0.2.0/docs/forgemark-request.md +0 -56
  231. forgegraph-0.2.0/docs/specs/catalog/base_format.md +0 -22
  232. forgegraph-0.2.0/docs/specs/catalog/base_theme.md +0 -222
  233. forgegraph-0.2.0/docs/specs/catalog/graph_type_xy.md +0 -202
  234. forgegraph-0.2.0/docs/specs/catalog/layer_error_bar.md +0 -26
  235. forgegraph-0.2.0/docs/specs/catalog/layer_note.md +0 -20
  236. forgegraph-0.2.0/docs/specs/catalog/layer_reference_line.md +0 -36
  237. forgegraph-0.2.0/docs/specs/config/config.md +0 -5
  238. forgegraph-0.2.0/docs/specs/format/base_format.md +0 -22
  239. forgegraph-0.2.0/docs/specs/format/base_layout_format.md +0 -14
  240. forgegraph-0.2.0/docs/specs/graph_type/xy.md +0 -90
  241. forgegraph-0.2.0/docs/specs/graphspec/polarization.md +0 -142
  242. forgegraph-0.2.0/docs/specs/layer/error_bar.md +0 -16
  243. forgegraph-0.2.0/docs/specs/layer/note.md +0 -12
  244. forgegraph-0.2.0/docs/specs/layer/reference_line.md +0 -19
  245. forgegraph-0.2.0/docs/specs/layout/base_layout.md +0 -30
  246. forgegraph-0.2.0/docs/specs/pack/acme/formats/slide.md +0 -16
  247. forgegraph-0.2.0/docs/specs/pack/acme/layouts/dashboard.md +0 -18
  248. forgegraph-0.2.0/docs/specs/pack/acme/schedules/workday.md +0 -17
  249. forgegraph-0.2.0/docs/specs/pack/acme/themes/acme.md +0 -28
  250. forgegraph-0.2.0/docs/specs/pack/forgegraph_base.md +0 -9
  251. forgegraph-0.2.0/docs/specs/schedule/base_schedule.md +0 -30
  252. forgegraph-0.2.0/docs/specs/theme/base_theme.md +0 -161
  253. forgegraph-0.2.0/examples/packs/acme/formats/slide.yaml +0 -12
  254. forgegraph-0.2.0/examples/packs/acme/graphspecs/polarization-curve.yaml +0 -31
  255. forgegraph-0.2.0/examples/packs/acme/layouts/dashboard.yaml +0 -14
  256. forgegraph-0.2.0/examples/packs/acme/schedules/workday.yaml +0 -13
  257. forgegraph-0.2.0/examples/packs/acme/themes/acme.yaml +0 -24
  258. forgegraph-0.2.0/scripts/build_api_notebook.py +0 -196
  259. forgegraph-0.2.0/scripts/build_bundled_skill.py +0 -48
  260. forgegraph-0.2.0/src/forgegraph/catalog/build.py +0 -362
  261. forgegraph-0.2.0/src/forgegraph/catalog/examples.py +0 -120
  262. forgegraph-0.2.0/src/forgegraph/catalog/files.py +0 -224
  263. forgegraph-0.2.0/src/forgegraph/catalog/forgemark.py +0 -59
  264. forgegraph-0.2.0/src/forgegraph/catalogs/graph_types/xy.yaml +0 -198
  265. forgegraph-0.2.0/src/forgegraph/catalogs/layers/error_bar.yaml +0 -22
  266. forgegraph-0.2.0/src/forgegraph/catalogs/layers/note.yaml +0 -16
  267. forgegraph-0.2.0/src/forgegraph/catalogs/layers/reference_line.yaml +0 -32
  268. forgegraph-0.2.0/src/forgegraph/cli/__init__.py +0 -740
  269. forgegraph-0.2.0/src/forgegraph/drawing/figure.py +0 -319
  270. forgegraph-0.2.0/src/forgegraph/drawing/labels.py +0 -312
  271. forgegraph-0.2.0/src/forgegraph/drawing/layers.py +0 -560
  272. forgegraph-0.2.0/src/forgegraph/drawing/xy.py +0 -852
  273. forgegraph-0.2.0/src/forgegraph/graph.py +0 -563
  274. forgegraph-0.2.0/src/forgegraph/graph_types/__init__.py +0 -1
  275. forgegraph-0.2.0/src/forgegraph/graph_types/xy.yaml +0 -85
  276. forgegraph-0.2.0/src/forgegraph/jobs/__init__.py +0 -9
  277. forgegraph-0.2.0/src/forgegraph/layers/error_bar.yaml +0 -12
  278. forgegraph-0.2.0/src/forgegraph/layers/note.yaml +0 -8
  279. forgegraph-0.2.0/src/forgegraph/layers/reference_line.yaml +0 -15
  280. forgegraph-0.2.0/src/forgegraph/layouts/__init__.py +0 -639
  281. forgegraph-0.2.0/src/forgegraph/layouts/arrange.py +0 -403
  282. forgegraph-0.2.0/src/forgegraph/packs/config.toml +0 -1
  283. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base/catalogs/formats/base_format.yaml +0 -18
  284. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base/catalogs/formats/base_layout_format.yaml +0 -9
  285. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base/catalogs/themes/base_theme.yaml +0 -218
  286. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base/formats/base_format.yaml +0 -18
  287. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base/formats/base_layout_format.yaml +0 -10
  288. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base/graphspecs/polarization.yaml +0 -138
  289. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base/layouts/base_layout.yaml +0 -26
  290. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base/pack.yaml +0 -5
  291. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base/schedules/base_schedule.yaml +0 -26
  292. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base/themes/base_theme.yaml +0 -157
  293. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base_2/catalogs/formats/compact_format.yaml +0 -9
  294. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base_2/catalogs/themes/base_theme.yaml +0 -26
  295. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base_2/formats/compact_format.yaml +0 -13
  296. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base_2/graphspecs/dated.parquet +0 -0
  297. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base_2/graphspecs/example.yaml +0 -13
  298. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base_2/graphspecs/fanned.parquet +0 -0
  299. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base_2/graphspecs/polarization.parquet +0 -0
  300. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base_2/graphspecs/reinforced.parquet +0 -0
  301. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base_2/pack.yaml +0 -5
  302. forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base_2/themes/base_theme.yaml +0 -72
  303. forgegraph-0.2.0/src/forgegraph/skill/forgegraph/examples/bars.yaml +0 -35
  304. forgegraph-0.2.0/src/forgegraph/skill/forgegraph/examples/figure.schedule.yaml +0 -11
  305. forgegraph-0.2.0/src/forgegraph/spec/__init__.py +0 -9
  306. forgegraph-0.2.0/src/forgegraph/spec/common.py +0 -11
  307. forgegraph-0.2.0/src/forgegraph/spec/documents.py +0 -874
  308. forgegraph-0.2.0/src/forgegraph/spec/parameters.py +0 -468
  309. forgegraph-0.2.0/src/forgegraph/spec/provenance.py +0 -63
  310. forgegraph-0.2.0/tests/baselines/crowded_runs.png +0 -0
  311. forgegraph-0.2.0/tests/baselines/flow_sweep_wide.png +0 -0
  312. forgegraph-0.2.0/tests/baselines/layout_anode_layers.png +0 -0
  313. forgegraph-0.2.0/tests/baselines/layout_screening_and_rate.png +0 -0
  314. forgegraph-0.2.0/tests/baselines/separator_colorbar.png +0 -0
  315. forgegraph-0.2.0/tests/pack_helpers.py +0 -25
  316. forgegraph-0.2.0/tests/render_helpers.py +0 -96
  317. forgegraph-0.2.0/tests/spec_mirror.py +0 -221
  318. forgegraph-0.2.0/tests/test_blank.py +0 -56
  319. forgegraph-0.2.0/tests/test_catalog.py +0 -290
  320. forgegraph-0.2.0/tests/test_cli.py +0 -364
  321. forgegraph-0.2.0/tests/test_layers.py +0 -513
  322. forgegraph-0.2.0/tests/test_lint.py +0 -105
  323. forgegraph-0.2.0/tests/test_perturbation.py +0 -48
  324. forgegraph-0.2.0/tests/test_regression.py +0 -42
  325. forgegraph-0.2.0/tests/test_specs.py +0 -542
  326. {forgegraph-0.2.0 → forgegraph-0.4.0}/LICENSE +0 -0
  327. {forgegraph-0.2.0 → forgegraph-0.4.0}/TRADEMARKS.md +0 -0
  328. /forgegraph-0.2.0/docs/initial specification.md → /forgegraph-0.4.0/docs/design/initial-specification.md +0 -0
  329. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/README.md +0 -0
  330. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/air_passengers.csv +0 -0
  331. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/air_passengers_by_month.csv +0 -0
  332. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/anscombe.csv +0 -0
  333. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/assay_summary.csv +0 -0
  334. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/cell_durability.csv +0 -0
  335. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/cell_polarization.csv +0 -0
  336. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/co2_monthly.csv +0 -0
  337. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/diamonds.csv +0 -0
  338. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/dose_response.csv +0 -0
  339. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/economics.csv +0 -0
  340. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/enzyme_kinetics.csv +0 -0
  341. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/fmri.csv +0 -0
  342. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/gapminder.csv +0 -0
  343. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/geyser.csv +0 -0
  344. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/growth.csv +0 -0
  345. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/iris.csv +0 -0
  346. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/lab_export.xlsx +0 -0
  347. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/lab_runs.xlsx +0 -0
  348. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/penguins.csv +0 -0
  349. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/seaice.csv +0 -0
  350. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/sensor_log_eu.csv +0 -0
  351. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/stocks.csv +0 -0
  352. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/tips.csv +0 -0
  353. {forgegraph-0.2.0 → forgegraph-0.4.0}/examples/sample-data/weather.xlsx +0 -0
  354. {forgegraph-0.2.0 → forgegraph-0.4.0}/scripts/build_sample_data.py +0 -0
  355. {forgegraph-0.2.0 → forgegraph-0.4.0}/scripts/check_denylist.py +0 -0
  356. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/__init__.py +0 -0
  357. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/__main__.py +0 -0
  358. {forgegraph-0.2.0/src/forgegraph/catalog → forgegraph-0.4.0/src/forgegraph/catalog_build}/__init__.py +0 -0
  359. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/__init__.py +0 -0
  360. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/markup.py +0 -0
  361. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/drawing/page.py +0 -0
  362. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/IBMPlexSerif-Bold.ttf +0 -0
  363. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/IBMPlexSerif-Light.ttf +0 -0
  364. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/IBMPlexSerif-Medium.ttf +0 -0
  365. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/IBMPlexSerif-Regular.ttf +0 -0
  366. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/IBMPlexSerif-SemiBold.ttf +0 -0
  367. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/OFL-IBMPlexSerif.txt +0 -0
  368. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/OFL-Roboto.txt +0 -0
  369. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/OFL-SourceSans3.md +0 -0
  370. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/Roboto-Bold.ttf +0 -0
  371. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/Roboto-Italic.ttf +0 -0
  372. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/Roboto-Light.ttf +0 -0
  373. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/Roboto-Medium.ttf +0 -0
  374. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/Roboto-Regular.ttf +0 -0
  375. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/Roboto-SemiBold.ttf +0 -0
  376. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/SourceSans3-Bold.ttf +0 -0
  377. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/SourceSans3-It.ttf +0 -0
  378. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/SourceSans3-Light.ttf +0 -0
  379. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/SourceSans3-Medium.ttf +0 -0
  380. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/SourceSans3-Regular.ttf +0 -0
  381. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/fonts/SourceSans3-Semibold.ttf +0 -0
  382. {forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base → forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default}/graphspecs/dated.parquet +0 -0
  383. {forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base → forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default}/graphspecs/fanned.parquet +0 -0
  384. {forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base → forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default}/graphspecs/polarization.parquet +0 -0
  385. {forgegraph-0.2.0/src/forgegraph/packs/forgegraph_base → forgegraph-0.4.0/src/forgegraph/packs/forgegraph_default}/graphspecs/reinforced.parquet +0 -0
  386. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/skill/forgegraph/examples/xy.parquet +0 -0
  387. {forgegraph-0.2.0 → forgegraph-0.4.0}/src/forgegraph/skill/forgegraph/references/requests.md +0 -0
  388. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/baselines/fuel_by_size.png +0 -0
  389. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/baselines/polarization.png +0 -0
  390. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/baselines/polarization_narrow.png +0 -0
  391. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/baselines/precipitation_loglog.png +0 -0
  392. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/baselines/replicates.png +0 -0
  393. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/baselines/screening_scatter.png +0 -0
  394. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/fixtures/catalog_comments.html +0 -0
  395. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_denylist.py +0 -0
  396. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_markup.py +0 -0
  397. {forgegraph-0.2.0 → forgegraph-0.4.0}/tests/test_spec_mirrors.py +0 -0
@@ -19,3 +19,9 @@ dist/
19
19
  htmlcov/
20
20
  .ipynb_checkpoints/
21
21
  .cache/
22
+
23
+ # Claude Code's local settings
24
+ .claude/
25
+
26
+ # The skill evals' image sheets: kept locally, or attached to their PR
27
+ review/*/skill-eval-graphs/
@@ -3,14 +3,15 @@ repos:
3
3
  rev: v6.0.0
4
4
  hooks:
5
5
  - id: check-yaml
6
+ args: [--unsafe] # syntax only, so specs may carry !var and !fix tags
6
7
  - id: check-toml
7
8
  - id: end-of-file-fixer
8
- exclude: \.md$|^(review|catalog)/
9
+ exclude: \.md$|^(review|catalog|docs/visual-changelog)/
9
10
  - id: trailing-whitespace
10
- exclude: \.md$|^(review|catalog)/
11
+ exclude: \.md$|^(review|catalog|docs/visual-changelog)/
11
12
  - id: check-added-large-files
12
13
  args: [--maxkb=600]
13
- exclude: ^(review|catalog)/ # self-contained HTML pages embed their images
14
+ exclude: ^(review|catalog|docs/visual-changelog)/ # self-contained HTML pages embed images
14
15
  - repo: https://github.com/astral-sh/ruff-pre-commit
15
16
  rev: v0.17.1
16
17
  hooks:
@@ -0,0 +1,122 @@
1
+ # Changelog
2
+
3
+ ForgeGraph follows [semantic versioning](https://semver.org). Before 1.0, a minor version may change how graphs look or how specs are written. From 0.2.0 on, each release's entry links its visual changelog: before and after images of every catalog card and regression graph that changed, made with `scripts/visual_changelog.py`.
4
+
5
+ ## 0.4.0 (2026-10-27)
6
+
7
+ Images that changed: the [visual changelog](docs/visual-changelog/0.4.0.html).
8
+
9
+ ### Changed
10
+
11
+ - **Breaking for existing specs and configs:** one built-in pack, `forgegraph_default`, replaces `forgegraph_base` and `forgegraph_base_2`. Its specs are `light_theme` (in place of `forgegraph_base/base_theme`), `compact_format` (`base_format`), `wide_format` (`base_layout_format`), `layout` (`layout_example`), `schedule` (`base_schedule`) and `graphspec_example`; `forgegraph_base_2` has no replacement. A main config listing `forgegraph_base` or `forgegraph_base_2` is an error: list `forgegraph_default` instead. light_theme draws 0.3's look. It fixes every text's font and gap, the palettes (the colors, line styles, marker shapes and fills that series take in turn), the ticks' direction, sides and algorithms, and the grid, so a GraphSpec that sets `grid.x.show` needs a theme that leaves it variable; a series may still set its own color, line style, marker shape and line width. The default layout draws no line between tiles and leaves 0.25 × the base size at the figure's edges.
12
+ - The specification files, which define each kind, are in `src/forgegraph/specifications/`, and their pages in `docs/specifications/`; no spec can name or extend them. The built-in pack's pages are in `docs/packs/forgegraph_default/`, and the catalog page is `catalog/forgegraph_default.html`.
13
+ - A category's brackets in a specification file say what the code reads about it, from a fixed set: its style, `same as <sibling>` for a category with a sibling's parameters, and `look from <theme category>` for a layer category whose look comes from the theme. Anything else there is an error, and descriptions are never read, so rewording one changes nothing.
14
+ - A style's member that no file tags, itself or through a category inside `parameters`, is fixed or variable as its general parameter is: a fixed `text.font` fixes every text style's font, even where the theme sets the style's own.
15
+ - `forgegraph schema <kind>` no longer says whether a parameter is fixed: it shows the kind's specification, which isn't what graphs are drawn with. `forgegraph schema graphspec` lists what a GraphSpec can set, and `forgegraph explain` shows what's fixed.
16
+ - A reference layer's `fill.color` may be None: two lines with values make a band only when it isn't.
17
+ - **Breaking for existing specs:** a GraphSpec lists its series by name under `series`, each drawn from its own column (by default, the column of its name) with its own settings: `aggregation`, `split`, `order`, `color`, `color_scale`, `line`, `marker`, `bar` and `value_label`, and the theme's variable series parameters it sets for itself. They replace `axis.*.data.aggregation`, `encoding.*` and `mark.*`; the value axis's `data.column` is None. `arrangement.base_axis`, `arrangement.stacking`, `arrangement.offset` and `arrangement.total.show` replace `series.base_axis`, `series.aggregation`, `series.offset` and `series.value_label.total.show`. A series' color, line style, marker shape and fill take `first`, `series`, a value or a column; series take palette colors in the order they're listed.
18
+ - **Breaking for existing specs:** the `reference` layer replaces `reference_line`: `line_1` and `line_2`, each at a value or from a column, with its own `aggregation` and `offset` (aggregation styles), `scope`, line and label (with `label.inside`), and the `fill` of a band between them. The theme's `layer.reference` replaces `layer.reference_line`.
19
+ - An aggregation style (`function`, `multiplier`, `percentile`) for a series, a reference line and error bars; functions include `percentile`, `stddev`, `stderr` and `ci`.
20
+ - `line.interpolate` draws a series' line straight, in steps (`step_after`, `step_before`, `step_center`) or as a smooth curve that never overshoots its points.
21
+ - A note and a reference layer's lines, labels and fill may set the theme's variable look for themselves.
22
+ - A style key (one from `encoding.line.style.column`, `encoding.marker.shape.column` or `encoding.marker.fill.column`) follows `legend.key.title.text`, as the series' key does: `column_name`, the default, gives each key its own column's name, so default graphs are unchanged; `None` removes every key's title; a text titles one key, and with more than one key drawn it's an error. With no `encoding.color.column`, a style key's samples are drawn in the one series color, not the text color. `render --json` reports `style_keys`, the column each style key drawn explains (for a layout, each tile's), beside `labelling`.
23
+ - A range type `date`: a date, or a date and time, as YAML's bare date (`2025-08-25`, `2025-08-25 06:00:00`) or ISO 8601 text (`"2025-08-25T06:00"`); a time with a zone is at its clock time, as the data's are. `axis.x.min`, `axis.x.max`, `axis.y.min` and `axis.y.max`, a reference line's `value` and `benchmark.value` take it: on a datetime axis or column, a date is drawn exactly where its day number is, and numbers keep working as day numbers. A date on an axis that isn't dates is an error naming the axis's type. Text that reads as a date is a reference line's column only if the data has a column of that name. Provenance records write dates as ISO 8601 text.
24
+ - On a date value axis, what would draw nonsense is an error that says what to do: stacking (`series.aggregation` sum or percent), adding up rows (`axis.*.data.aggregation` sum), bars (`mark.bar.show`, which would start at 1970), and value labels without a date format. A reference line at a date column's aggregate is on a date axis only, at its mean, median, min or max, with multiplier 1. A date axis's `tick.label.format` must have a date directive.
25
+
26
+ ### Fixed
27
+
28
+ - In a theme whose text is light, powers of ten on a log axis and superscripts in labels no longer give a `font-fallback` lint issue. They were always drawn in the theme's font and weight; the issue came from the faces matplotlib loads for maths but doesn't draw these with.
29
+ - The `outside-limits` and `log-axis-values` lint checks count only data points. A reference line's ends and an error bar's ends no longer count as points outside a set axis limit, or as values of 0 or below on a log axis.
30
+ - A style key on the benchmark's column matches the drawing: its entries are the groups the series are styled by, so a value after the benchmark no longer gets the next value's style, and the benchmark, drawn in its own style, has no style sample and is named once, by `legend.method`. When `legend.method: key` doesn't fit, the error says why: every position in `legend.key.positions` is taken or covers data, naming the position each style key took.
31
+ - YAML's null (`null`, `~` or nothing) is None everywhere a spec can say None. `extends: null` failed with `KeyError: None`, and a file extending null wasn't required to list every parameter.
32
+ - Computed values are compared with an axis's limits allowing for float noise: a value is past a limit only if it's past by more than 1e-9 of the axis's span, measured in powers of ten on a log axis. A stack that totals `axis.y.max` but for its last digits isn't reported by `outside-limits`; a reference line at a computed value that equals a set limit isn't an error; bars whose values are 0 but for float noise still stand on the axis; and a tick a hair past the end of the view, which matplotlib draws, is measured for layout and lint and counts when log labels choose between plain numbers and powers of ten.
33
+ - Dates and times draw the same on y as on x: every value placed on an axis (the data, its aggregates, stacks, reference lines, error bars and limits) becomes a number the same way, so a date y axis has date ticks, a reference line at a date column's aggregate lands on it, and error bars from a date column's spread are in days. With value labels off, a date `tick.label.format` such as `"%H:%M"` on y is no longer refused as a number format; value labels and a reference line's value on a date axis are written in a date format.
34
+
35
+ ## 0.3.0 (2026-10-25)
36
+
37
+ Images that changed: the [visual changelog](docs/visual-changelog/0.3.0.html).
38
+
39
+ ### Added
40
+
41
+ - `fg.blank` takes `registry=`, as `fg.render` does, and a blank canvas's `save` path is optional, as a graph's is: with none, it saves `canvas.png` and the format's other file types.
42
+
43
+ ### Changed
44
+
45
+ - **Breaking for existing specs:** parameters follow one naming system. `_` joins words that name one thing (`error_bar`, `plot_area`), `.` goes from a thing to its parts and properties (`line.width`), an on/off switch is the thing's `.show`, and nothing is abbreviated. A spec still using an old name is an error that suggests the new one; an old name that's now a category, such as `encoding.color`, suggests that category's parameters. The Python API's keyword arguments (`fg.xy`'s `color=`, `line_style=`, `marker_shape=`, `marker_fill=`, `detail=`) are unchanged and set the new paths. Graphs draw the same as before. The renames, old → new:
46
+ 1. `grid.line_style` → `grid.line.style`; `grid.line_width` → `grid.line.width`
47
+ 2. `plot_area.line_color` → `plot_area.line.color`; `plot_area.line_width` → `plot_area.line.width`
48
+ 3. `layer.error_bar.line_width` → `layer.error_bar.line.width`; `layer.error_bar.cap_size` → `layer.error_bar.cap.width`
49
+ 4. `layer.reference_line.line_style` → `layer.reference_line.line.style`; `layer.reference_line.line_width` → `layer.reference_line.line.width`
50
+ 5. `series.marker.edge_color`, `series.marker.edge_width` → `series.marker.edge.color`, `series.marker.edge.width`, and the same in `series.bar`, `series.benchmark.marker` and `series.benchmark.bar`
51
+ 6. `legend.key.frame_width` → `legend.key.frame.width`
52
+ 7. `legend.key.sample.marker_size` → `legend.key.sample.marker.size`
53
+ 8. `legend.key.frame` → `legend.key.frame.show`
54
+ 9. `series.value_label.total` → `series.value_label.total.show`
55
+ 10. `axis.tick.minor.num` → `axis.tick.minor.count`
56
+ 11. `encoding.color` → `encoding.color.column`; `encoding.color_type` → `encoding.color.type`; `encoding.line_style` → `encoding.line.style.column`; `encoding.marker_shape` → `encoding.marker.shape.column`; `encoding.marker_fill` → `encoding.marker.fill.column`; `encoding.detail` → `encoding.detail.column` (`encoding.order` is unchanged)
57
+ 12. Layouts: `separators.line.border` → `separators.border.show`
58
+ 13. Schedules: `freshness.stamp` → `freshness.stamp.show`; `cadence.interval` → `cadence.interval.count`; `cadence.interval_unit` → `cadence.interval.unit`
59
+ - **Breaking for packs' catalog files:** a catalog's cards are chosen by a rule, not by hand. Every parameter gets one card, its value taken from its range and the baseline's data, drawn on the first baseline where it changes the drawing; the page shows the variable parameters' cards. A catalog file lists only its baselines, and a layer's settings: `variations`, `no_card` and the `{value, from, with}` forms are gone. A pack's catalog page draws with the pack's own theme and format values.
60
+ - Drawing and saving are about 3.7 times faster. Graphs and their files are the same as before.
61
+ - A pack's fonts are registered when a file drawn uses one of its specs, not whenever a config lists the pack.
62
+ - `forgegraph --help` gives each command a one-sentence summary, and `forgegraph catalog --help` names every kind it lists.
63
+ - The internal package `forgegraph.catalog` is `forgegraph.catalog_build`. The API is unchanged.
64
+ - One name is one pack. A config can't give a built-in pack's name, or a name the main config already gives, to another folder. Before, a folder config's copy of a pack replaced the one the main config lists, and what it drew wasn't marked non-standard.
65
+ - ForgeGraph needs matplotlib 3.11.2 and typer 0.15.4 or later; earlier versions installed but didn't work.
66
+ - The package's description and classifiers say what it is now: released, in alpha.
67
+
68
+ ### Fixed
69
+
70
+ - Error bars on a date axis stand on their points, and error bars of aggregated rows on a date axis draw.
71
+ - Times with a time zone are drawn at the times their clocks show. Before, they raised an error.
72
+ - A reference line at a column's sum or standard deviation counts each row once when several y columns are drawn.
73
+ - Value labels written with format auto use the value axis's tick label format when it's set, as reference lines do.
74
+ - The catalog's record of what it was built from covers every module it draws with, so a change to the drawing code marks the catalog out of date.
75
+ - The package's metadata lists the bundled fonts' licences.
76
+ - A GraphSpec naming a list as its theme, format or graph type gets the error "must be a single value", not a crash.
77
+ - A config naming a pack that can't be found, or another pack problem, stops `catalog`, `pack-notes`, `schema` and `explain` with its problems listed (`error:` lines, exit 1), not a traceback; with `--json`, one problem each, not one joined line.
78
+
79
+ ## 0.2.0 (2026-10-24)
80
+
81
+ Images that changed: the [visual changelog](docs/visual-changelog/0.2.0.html).
82
+
83
+ ### Changed
84
+
85
+ - Error bars are black by default in both built-in themes, and their color (`layer.error_bar.color`) is a variable parameter: a GraphSpec may set `series` or any hex color.
86
+ - Three internal modules are renamed so none shares a name with the API: `forgegraph.render` is `forgegraph.drawing`, `forgegraph.layout` is `forgegraph.layouts` and `forgegraph.blank` is `forgegraph.canvas`. `import forgegraph.layouts as m` now gives the module, not `fg.layout`. The API is unchanged.
87
+
88
+ ### Fixed
89
+
90
+ - `forgegraph --version` and `--help` no longer load matplotlib and pandas, so they answer at once, even on a new install. The API loads on first use.
91
+ - The README and the skill's reference say when the main config is written: the first time a command reads the configs, such as `catalog` or `render`.
92
+ - Error bars on side-by-side bars (`series.offset: side_by_side`) are drawn on their own bars. Before, every series but the middle one had its error bars drawn where they were first placed, before layout, usually off the axes.
93
+
94
+ ## 0.1.0 (2026-10-24)
95
+
96
+ The first public release.
97
+
98
+ ### Added
99
+
100
+ - **GraphSpecs:** a graph described in YAML or as a Python dict, drawn with `forgegraph render` or `fg.render`; `fg.xy` draws straight from a DataFrame.
101
+ - **The `xy` graph type:**
102
+ - lines, markers and bars: grouped, stacked, 100 % stacked and horizontal;
103
+ - dates and log axes, value labels, a benchmark series;
104
+ - series named beside their lines or in a key.
105
+ - **Layers:** reference lines, notes and error bars, from the data or given.
106
+ - **Themes and formats:** a theme fixes what must stay the same and gives defaults for the rest; a format sets size, base font size, file types and resolution.
107
+ - **Packs and configs:**
108
+ - every named spec comes from a pack, named `pack/name`; ForgeGraph's own is `forgegraph_base`, and `forgegraph_base_2` is a second look in this repository;
109
+ - the main config (written on first use, or named by `FORGEGRAPH_CONFIG`) and folder configs (`forgegraph.toml`) say which packs may be used;
110
+ - a pack only a folder config lists is non-standard: it works, and what's drawn with it is watermarked.
111
+ - **Lint on every render:** overlapping or clipped text, a key covering data, fonts too small for the format, missing fonts, dropped rows and more.
112
+ - **Provenance:** every saved file (PNG, JPEG, TIFF, SVG, PDF and HTML) records its GraphSpec and the specs it was drawn with, at the format's provenance level; `forgegraph load` reads it back.
113
+ - **Layouts:** several GraphSpecs in one figure, with spanning tiles, blank cells and set widths; tabs, and HTML dashboards.
114
+ - **Scheduled renders:** schedule files, `forgegraph job run`, a status file, `on_failure` and `on_success` hooks, a "data as of" footnote and a stale banner.
115
+ - **The themed canvas:** `forgegraph.blank(theme, format)` for what no graph type can draw, always watermarked as non-standard.
116
+ - **The agent skill** for Claude Code, installed with `forgegraph skill install`, with reference notes for themes, formats and configs, and for filing requests.
117
+ - **Commands:** `render`, `explain`, `catalog`, `schema`, `pack-notes`, `load`, `job run` and `skill install`, each with `--json`.
118
+ - **Catalogs:** a page for each pack in this repository, with a card for every parameter.
119
+
120
+ ## 0.0.1 (2026-10-17)
121
+
122
+ The name, reserved on PyPI. No functionality.
@@ -0,0 +1,44 @@
1
+ # Contributing
2
+
3
+ Contributions are welcome. For a bug or a feature request, open an [issue](https://github.com/sskaye/forgegraph/issues). For a change, open a pull request with tests, after running the checks below.
4
+
5
+ ## Development setup
6
+
7
+ ```bash
8
+ uv sync
9
+ uv run pre-commit install
10
+ ```
11
+
12
+ While you work, `uv run pytest` runs the development suite: every test not marked slow, in parallel. The full suite adds the slow ones (every catalog card drawn, the image baselines, the catalog pages, and any test over a second). CI runs it on every pull request, and it's the one to run before a release:
13
+
14
+ ```bash
15
+ uv run pytest --full && uv run ruff check . && uv run ruff format --check && uv run pyright
16
+ ```
17
+
18
+ Mark a new test `@pytest.mark.slow` if it takes over a second (`uv run pytest --durations=20` lists the slowest).
19
+
20
+ ## After changing a definition or how graphs are drawn
21
+
22
+ Every parameter gets one catalog card, its value and baseline chosen by a rule (`src/forgegraph/catalog_build/cards.py`), so a new parameter needs no card of its own; the page shows the variable parameters' cards, and the perturbation test draws them all. It needs a baseline that shows it only if none does: the build (for a variable parameter) or the perturbation test (for any) names a parameter that changes no baseline's drawing, and the fix is a generic scenario added to the baselines in the matching catalog file under `src/forgegraph/specifications/catalogs/` (or the pack's `catalogs/`).
23
+
24
+ Rebuild the catalog (it keeps its review comments; Node 18+ is needed once it has some), the mirrors, and the image baselines if graphs look different on purpose:
25
+
26
+ ```bash
27
+ uv run forgegraph catalog build
28
+ uv run python scripts/mirror_specs.py
29
+ uv run python scripts/build_recreations.py --baselines
30
+ ```
31
+
32
+ `uv run python scripts/visual_changelog.py main` then shows every image that changed.
33
+
34
+ ## Requesting a graph type
35
+
36
+ Open a GitHub issue describing the graph you need, ideally with an example image or sketch and a little sample data. No code is needed.
37
+
38
+ ## Releasing
39
+
40
+ 1. Set the new version in pyproject.toml and in the built-in pack's pack.yaml, and for a new minor version, its `requires` (`">=0.4, <0.5"` for 0.4).
41
+ 2. Rebuild the catalog and mirrors (above).
42
+ 3. Write the visual changelog, `uv run python scripts/visual_changelog.py v<last version>`, and the CHANGELOG entry, linking it.
43
+ 4. Merge with CI green, and tag the merge commit `v<version>`.
44
+ 5. Run the Publish workflow.
@@ -1,6 +1,36 @@
1
+ Metadata-Version: 2.5
2
+ Name: forgegraph
3
+ Version: 0.4.0
4
+ Summary: Fast, consistent, publication-quality graphs from pandas DataFrames, usable by people and AI agents.
5
+ Project-URL: Repository, https://github.com/sskaye/forgegraph
6
+ Project-URL: Issues, https://github.com/sskaye/forgegraph/issues
7
+ Project-URL: Changelog, https://github.com/sskaye/forgegraph/blob/main/CHANGELOG.md
8
+ Author: Steven Kaye
9
+ License-Expression: MIT AND OFL-1.1
10
+ License-File: LICENSE
11
+ License-File: src/forgegraph/fonts/OFL-IBMPlexSerif.txt
12
+ License-File: src/forgegraph/fonts/OFL-Roboto.txt
13
+ License-File: src/forgegraph/fonts/OFL-SourceSans3.md
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Science/Research
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Programming Language :: Python :: 3.14
20
+ Classifier: Topic :: Scientific/Engineering :: Visualization
21
+ Requires-Python: >=3.12
22
+ Requires-Dist: matplotlib>=3.11.2
23
+ Requires-Dist: packaging>=23
24
+ Requires-Dist: pandas>=2.2
25
+ Requires-Dist: pyarrow>=17
26
+ Requires-Dist: pydantic>=2.7
27
+ Requires-Dist: ruamel-yaml>=0.18
28
+ Requires-Dist: typer>=0.15.4
29
+ Description-Content-Type: text/markdown
30
+
1
31
  # ForgeGraph
2
32
 
3
- Fast, consistent, publication-quality graphs from pandas DataFrames, useable by people and AI agents.
33
+ Fast, consistent, publication-quality graphs from pandas DataFrames, usable by people and AI agents.
4
34
 
5
35
  You describe a graph in a **GraphSpec**. ForgeGraph draws it in a house style set by a **theme** and a **format**. It checks what it drew, and records how the graph was made inside the saved file. An agent skill lets agents make and revise graphs the same way.
6
36
 
@@ -18,7 +48,7 @@ You describe a graph in a **GraphSpec**. ForgeGraph draws it in a house style se
18
48
  - **Configs:** control which packs may be used, per user or folder. Used to enforce use of style pack(s) and watermark non-standard graphs.
19
49
  - **Lint:** Graphs are linted on rendering, with warnings for issues including overlapping or clipped text, a key covering data, or fonts too small.
20
50
 
21
- **Status:** 0.x. `xy` graph type (lines, markers, & bars), reference lines, error bars, and notes layers, initial style packs. More graph types coming soon. If there’s specific ones you want, [open an issue](https://github.com/sskaye/forgegraph/issues).
51
+ **Status:** 0.x. `xy` graph type (lines, markers, & bars), reference lines, error bars, and notes layers, initial style packs. More graph types are planned. If there’s specific ones you want, [open an issue](https://github.com/sskaye/forgegraph/issues).
22
52
 
23
53
  ## Install
24
54
 
@@ -59,6 +89,16 @@ g = fg.xy(runs, x="hours", y="voltage", color="cell", title="Cell voltage")
59
89
  g.save("voltage") # voltage.png, with its GraphSpec inside
60
90
  ```
61
91
 
92
+ The Python API (each function has a docstring):
93
+
94
+ - `fg.xy(df, x, y, ...)`: draw y against x from a DataFrame.
95
+ - `fg.render(spec, data=None)`: draw a GraphSpec, given as a file or a document.
96
+ - `fg.graphspec(name, graph_type, ...)`: write a GraphSpec document.
97
+ - `fg.layout(spec, data=None)`: draw a layout.
98
+ - `fg.load(path)`: a saved graph's record; its GraphSpec is under `"graphspec"`.
99
+ - `fg.blank(theme, format)`: a themed canvas for drawing with matplotlib what no graph type can; what's drawn on it is watermarked.
100
+ - A `Graph` has `.save(path)`, `.figure` and `.axes` (matplotlib's), `.issues` (the lint) and `.check()`.
101
+
62
102
  From the command line, with the DataFrame saved as runs.parquet and a GraphSpec, voltage.yaml:
63
103
 
64
104
  ```yaml
@@ -66,12 +106,11 @@ name: voltage
66
106
  version: 0
67
107
  description: Cell voltage over a test, one line per cell.
68
108
  extends: None
69
- fixed_parameters: None
70
- variable_parameters:
109
+ parameters: !var
71
110
  specifications:
72
111
  graph_type: xy
73
- theme: forgegraph_base/base_theme
74
- format: forgegraph_base/base_format
112
+ theme: forgegraph_default/light_theme
113
+ format: forgegraph_default/compact_format
75
114
  text:
76
115
  title: Cell voltage
77
116
  data:
@@ -81,11 +120,9 @@ variable_parameters:
81
120
  x:
82
121
  data:
83
122
  column: hours
84
- y:
85
- data:
86
- column: voltage
87
- encoding:
88
- color: cell
123
+ series:
124
+ voltage:
125
+ color: cell
89
126
  ```
90
127
 
91
128
  ```bash
@@ -94,7 +131,7 @@ forgegraph render voltage.yaml
94
131
 
95
132
  ## Packs and configs
96
133
 
97
- Every named theme, format, GraphSpec, layout and schedule comes from a **pack**, a folder or pip package of specs, and is named `pack/name`. The initial built-in packs are `forgegraph_base` and `forgegraph_base_2`, stored in src/forgegraph/packs.
134
+ Every named theme, format, GraphSpec, layout and schedule comes from a **pack**, a folder or pip package of specs, and is named `pack/name`. ForgeGraph's built-in pack, `forgegraph_default`, is stored in src/forgegraph/packs: its theme, `light_theme`, its formats, `compact_format` for single graphs and `wide_format` for layouts, and a layout and a schedule to extend.
98
135
 
99
136
  A **config** lists the packs that may be used:
100
137
 
@@ -102,11 +139,15 @@ A **config** lists the packs that may be used:
102
139
  - A folder config, `forgegraph.toml`, applies to the files in its folder and every folder below it. A file may use only the packs it lists.
103
140
  - A pack that a folder config lists but the main config doesn't still works, but it's non-standard: graphs drawn with it are watermarked, and ForgeGraph's commands say so. That way you can make and try a pack without changing an organization's main config.
104
141
 
142
+ To write a pack, start from the example pack in [examples/packs/acme](https://github.com/sskaye/forgegraph/blob/main/examples/packs/acme); `forgegraph schema theme`, `format`, `pack` and `config` list every parameter.
143
+
144
+ On macOS, a scheduled render that writes into a cloud-synced folder needs Full Disk Access.
145
+
105
146
  ## Commands
106
147
 
107
148
  - `forgegraph render <graphspec or layout>`: draw and save, and report lint.
108
149
  - `forgegraph explain <graphspec or layout>`: every value it's drawn with, and which file set it.
109
- - `forgegraph catalog`: the packs, graph types, layer types, themes, formats and reference notes available here.
150
+ - `forgegraph catalog`: the packs, graph types, layer types, themes, formats, GraphSpecs, layouts, schedules and reference notes available here.
110
151
  - `forgegraph schema graphspec --graph-type <type> --theme <theme> --format <format>`: every parameter a GraphSpec can set.
111
152
  - `forgegraph schema <kind>`: every parameter of a theme, format, layer, layout, schedule, pack or config.
112
153
  - `forgegraph pack-notes`: the reference notes of the packs available here.
@@ -118,48 +159,42 @@ Every command takes `--help`, and `--json` for agents.
118
159
 
119
160
  ## Catalogs
120
161
 
121
- Each pack in this repository has a catalog: a page with a card for each parameter, showing what changing it does.
162
+ The built-in pack has a catalog: a page with a card for each parameter, showing what changing it does. Download it and open it in a browser.
122
163
 
123
- - forgegraph_base: ForgeGraph's own pack, with its graph types and layer types.
124
- - forgegraph_base_2: its own theme and format, and the same graph types and layer types drawn in them.
164
+ - [forgegraph_default](https://github.com/sskaye/forgegraph/blob/main/catalog/forgegraph_default.html): its theme and formats, and ForgeGraph's graph types and layer types drawn in them.
125
165
 
126
166
  ## Your graphs are yours
127
167
 
128
- ForgeGraph is [MIT-licensed](LICENSE). Graphs and other output you make with it are yours: no attribution or licence terms apply to them. See TRADEMARKS.md for use of the name.
168
+ ForgeGraph is [MIT-licensed](https://github.com/sskaye/forgegraph/blob/main/LICENSE). Graphs and other output you make with it are yours: no attribution or licence terms apply to them. See [TRADEMARKS.md](https://github.com/sskaye/forgegraph/blob/main/TRADEMARKS.md) for use of the name.
129
169
 
130
170
  ## Documentation
131
171
 
132
- - Architecture: how ForgeGraph is designed, and why.
133
- - Decisions: decisions that refine the architecture.
134
- - Specifications: every spec, a folder per kind.
135
- - [Changelog](CHANGELOG.md).
136
- - Build plan: how ForgeGraph is being built, phase by phase.
172
+ - [Specifications](https://github.com/sskaye/forgegraph/blob/main/docs/specifications): the file that defines each kind of spec, every parameter with its default, range and description.
173
+ - [Built-in pack](https://github.com/sskaye/forgegraph/blob/main/docs/packs/forgegraph_default): forgegraph_default's specs.
174
+ - [Changelog](https://github.com/sskaye/forgegraph/blob/main/CHANGELOG.md).
175
+ - [Contributing](https://github.com/sskaye/forgegraph/blob/main/CONTRIBUTING.md): working on ForgeGraph itself.
176
+ - Design record, in [docs/design](https://github.com/sskaye/forgegraph/blob/main/docs/design):
177
+ - [Architecture](https://github.com/sskaye/forgegraph/blob/main/docs/design/architecture.md): how ForgeGraph is designed, and why.
178
+ - [To do](https://github.com/sskaye/forgegraph/blob/main/docs/design/todo.md): what's still planned.
137
179
 
138
180
  ## Contributing
139
181
 
140
- Feature requests and bug reports go to [GitHub issues](https://github.com/sskaye/forgegraph/issues); the skill can file them for you. CONTRIBUTING.md covers working on ForgeGraph itself. In short:
141
-
142
- ```bash
143
- uv sync && uv run pre-commit install
144
- ```
145
-
146
- ```bash
147
- uv run pytest --full && uv run ruff check . && uv run pyright
148
- ```
182
+ Feature requests and bug reports go to [GitHub issues](https://github.com/sskaye/forgegraph/issues); the skill can file them for you. [CONTRIBUTING.md](https://github.com/sskaye/forgegraph/blob/main/CONTRIBUTING.md) covers working on ForgeGraph itself: setup, the checks to run, and regenerating the catalogs.
149
183
 
150
184
  ## Repository map
151
185
 
152
186
  - **src/forgegraph/**: the package.
153
- - `graph.py`: the Python API (`fg.xy`, `fg.render`, `fg.graphspec`, `fg.load`) and the `Graph` object; `canvas.py`: the themed canvas.
187
+ - `graph.py`: the Python API (`fg.xy`, `fg.render`, `fg.graphspec`, `fg.load`) and the `Graph` object; `canvas.py`: `fg.blank`, the themed canvas; `drawn.py`: what they and layouts share once drawn; `data.py`: reading a GraphSpec's data.
154
188
  - **cli/**: the `forgegraph` command.
155
189
  - **spec/**: reading, checking and resolving specs, and the provenance record.
156
- - **drawing/**: drawing, layout and lint. **layouts/**: layouts. **jobs/**: scheduled renders.
157
- - **packs/**: packs and configs, and the built-in packs `forgegraph_base` and `forgegraph_base_2`. **fonts/**: bundled fonts and their licences.
158
- - **graph_types/**, **layers/**: the graph type and layer type definitions. **catalog/**, **catalogs/**: the catalog builder, and each definition's catalog file.
159
- - **skill/forgegraph/**: the agent skill.
190
+ - **drawing/**: drawing, layout and lint. **layouts/**: `fg.layout` and layouts. **jobs/**: scheduled renders.
191
+ - **specifications/**: the specification files, which define each kind of spec, and the graph types' and layer types' catalog files.
192
+ - **packs/**: packs and configs, and the built-in pack `forgegraph_default`. **fonts/**: bundled fonts and their licences.
193
+ - **catalog_build/**: the catalog builder.
194
+ - **skill/forgegraph/**: the agent skill. `forgemark.py`: Forgemark's review-comment format, and its pinned tool.
160
195
  - **catalog/**: the generated catalog pages.
161
- - **examples/**: sample data, and `packs/acme`, an example pack in a deliberately different style.
196
+ - **examples/**: sample data; `packs/acme`, an example pack in a deliberately different style; and `layouts/`, a paper figure and a dashboard.
162
197
  - **evals/skill/**: the skill's eval cases, run by `scripts/run_skill_evals.py`.
163
198
  - **tests/**, **scripts/**: tests, and build and maintenance scripts.
164
- - **docs/**: the documents above. **review/**: each build phase's review pages.
199
+ - **docs/**: the specifications' and packs' pages, the design record and the visual changelogs. **review/**: each build phase's review pages.
165
200
 
@@ -1,31 +1,6 @@
1
- Metadata-Version: 2.5
2
- Name: forgegraph
3
- Version: 0.2.0
4
- Summary: Consistent, high-quality graphs from pandas DataFrames, for people and AI agents. Early development.
5
- Project-URL: Repository, https://github.com/sskaye/forgegraph
6
- Author: Steven Kaye
7
- License-Expression: MIT
8
- License-File: LICENSE
9
- Classifier: Development Status :: 1 - Planning
10
- Classifier: Intended Audience :: Science/Research
11
- Classifier: Programming Language :: Python :: 3
12
- Classifier: Programming Language :: Python :: 3.12
13
- Classifier: Programming Language :: Python :: 3.13
14
- Classifier: Programming Language :: Python :: 3.14
15
- Classifier: Topic :: Scientific/Engineering :: Visualization
16
- Requires-Python: >=3.12
17
- Requires-Dist: matplotlib>=3.9
18
- Requires-Dist: packaging>=23
19
- Requires-Dist: pandas>=2.2
20
- Requires-Dist: pyarrow>=17
21
- Requires-Dist: pydantic>=2.7
22
- Requires-Dist: ruamel-yaml>=0.18
23
- Requires-Dist: typer>=0.12
24
- Description-Content-Type: text/markdown
25
-
26
1
  # ForgeGraph
27
2
 
28
- Fast, consistent, publication-quality graphs from pandas DataFrames, useable by people and AI agents.
3
+ Fast, consistent, publication-quality graphs from pandas DataFrames, usable by people and AI agents.
29
4
 
30
5
  You describe a graph in a **GraphSpec**. ForgeGraph draws it in a house style set by a **theme** and a **format**. It checks what it drew, and records how the graph was made inside the saved file. An agent skill lets agents make and revise graphs the same way.
31
6
 
@@ -43,7 +18,7 @@ You describe a graph in a **GraphSpec**. ForgeGraph draws it in a house style se
43
18
  - **Configs:** control which packs may be used, per user or folder. Used to enforce use of style pack(s) and watermark non-standard graphs.
44
19
  - **Lint:** Graphs are linted on rendering, with warnings for issues including overlapping or clipped text, a key covering data, or fonts too small.
45
20
 
46
- **Status:** 0.x. `xy` graph type (lines, markers, & bars), reference lines, error bars, and notes layers, initial style packs. More graph types coming soon. If there’s specific ones you want, [open an issue](https://github.com/sskaye/forgegraph/issues).
21
+ **Status:** 0.x. `xy` graph type (lines, markers, & bars), reference lines, error bars, and notes layers, initial style packs. More graph types are planned. If there’s specific ones you want, [open an issue](https://github.com/sskaye/forgegraph/issues).
47
22
 
48
23
  ## Install
49
24
 
@@ -84,6 +59,16 @@ g = fg.xy(runs, x="hours", y="voltage", color="cell", title="Cell voltage")
84
59
  g.save("voltage") # voltage.png, with its GraphSpec inside
85
60
  ```
86
61
 
62
+ The Python API (each function has a docstring):
63
+
64
+ - `fg.xy(df, x, y, ...)`: draw y against x from a DataFrame.
65
+ - `fg.render(spec, data=None)`: draw a GraphSpec, given as a file or a document.
66
+ - `fg.graphspec(name, graph_type, ...)`: write a GraphSpec document.
67
+ - `fg.layout(spec, data=None)`: draw a layout.
68
+ - `fg.load(path)`: a saved graph's record; its GraphSpec is under `"graphspec"`.
69
+ - `fg.blank(theme, format)`: a themed canvas for drawing with matplotlib what no graph type can; what's drawn on it is watermarked.
70
+ - A `Graph` has `.save(path)`, `.figure` and `.axes` (matplotlib's), `.issues` (the lint) and `.check()`.
71
+
87
72
  From the command line, with the DataFrame saved as runs.parquet and a GraphSpec, voltage.yaml:
88
73
 
89
74
  ```yaml
@@ -91,12 +76,11 @@ name: voltage
91
76
  version: 0
92
77
  description: Cell voltage over a test, one line per cell.
93
78
  extends: None
94
- fixed_parameters: None
95
- variable_parameters:
79
+ parameters: !var
96
80
  specifications:
97
81
  graph_type: xy
98
- theme: forgegraph_base/base_theme
99
- format: forgegraph_base/base_format
82
+ theme: forgegraph_default/light_theme
83
+ format: forgegraph_default/compact_format
100
84
  text:
101
85
  title: Cell voltage
102
86
  data:
@@ -106,11 +90,9 @@ variable_parameters:
106
90
  x:
107
91
  data:
108
92
  column: hours
109
- y:
110
- data:
111
- column: voltage
112
- encoding:
113
- color: cell
93
+ series:
94
+ voltage:
95
+ color: cell
114
96
  ```
115
97
 
116
98
  ```bash
@@ -119,7 +101,7 @@ forgegraph render voltage.yaml
119
101
 
120
102
  ## Packs and configs
121
103
 
122
- Every named theme, format, GraphSpec, layout and schedule comes from a **pack**, a folder or pip package of specs, and is named `pack/name`. The initial built-in packs are `forgegraph_base` and `forgegraph_base_2`, stored in src/forgegraph/packs.
104
+ Every named theme, format, GraphSpec, layout and schedule comes from a **pack**, a folder or pip package of specs, and is named `pack/name`. ForgeGraph's built-in pack, `forgegraph_default`, is stored in src/forgegraph/packs: its theme, `light_theme`, its formats, `compact_format` for single graphs and `wide_format` for layouts, and a layout and a schedule to extend.
123
105
 
124
106
  A **config** lists the packs that may be used:
125
107
 
@@ -127,11 +109,15 @@ A **config** lists the packs that may be used:
127
109
  - A folder config, `forgegraph.toml`, applies to the files in its folder and every folder below it. A file may use only the packs it lists.
128
110
  - A pack that a folder config lists but the main config doesn't still works, but it's non-standard: graphs drawn with it are watermarked, and ForgeGraph's commands say so. That way you can make and try a pack without changing an organization's main config.
129
111
 
112
+ To write a pack, start from the example pack in [examples/packs/acme](https://github.com/sskaye/forgegraph/blob/main/examples/packs/acme); `forgegraph schema theme`, `format`, `pack` and `config` list every parameter.
113
+
114
+ On macOS, a scheduled render that writes into a cloud-synced folder needs Full Disk Access.
115
+
130
116
  ## Commands
131
117
 
132
118
  - `forgegraph render <graphspec or layout>`: draw and save, and report lint.
133
119
  - `forgegraph explain <graphspec or layout>`: every value it's drawn with, and which file set it.
134
- - `forgegraph catalog`: the packs, graph types, layer types, themes, formats and reference notes available here.
120
+ - `forgegraph catalog`: the packs, graph types, layer types, themes, formats, GraphSpecs, layouts, schedules and reference notes available here.
135
121
  - `forgegraph schema graphspec --graph-type <type> --theme <theme> --format <format>`: every parameter a GraphSpec can set.
136
122
  - `forgegraph schema <kind>`: every parameter of a theme, format, layer, layout, schedule, pack or config.
137
123
  - `forgegraph pack-notes`: the reference notes of the packs available here.
@@ -143,48 +129,42 @@ Every command takes `--help`, and `--json` for agents.
143
129
 
144
130
  ## Catalogs
145
131
 
146
- Each pack in this repository has a catalog: a page with a card for each parameter, showing what changing it does.
132
+ The built-in pack has a catalog: a page with a card for each parameter, showing what changing it does. Download it and open it in a browser.
147
133
 
148
- - forgegraph_base: ForgeGraph's own pack, with its graph types and layer types.
149
- - forgegraph_base_2: its own theme and format, and the same graph types and layer types drawn in them.
134
+ - [forgegraph_default](https://github.com/sskaye/forgegraph/blob/main/catalog/forgegraph_default.html): its theme and formats, and ForgeGraph's graph types and layer types drawn in them.
150
135
 
151
136
  ## Your graphs are yours
152
137
 
153
- ForgeGraph is [MIT-licensed](LICENSE). Graphs and other output you make with it are yours: no attribution or licence terms apply to them. See TRADEMARKS.md for use of the name.
138
+ ForgeGraph is [MIT-licensed](https://github.com/sskaye/forgegraph/blob/main/LICENSE). Graphs and other output you make with it are yours: no attribution or licence terms apply to them. See [TRADEMARKS.md](https://github.com/sskaye/forgegraph/blob/main/TRADEMARKS.md) for use of the name.
154
139
 
155
140
  ## Documentation
156
141
 
157
- - Architecture: how ForgeGraph is designed, and why.
158
- - Decisions: decisions that refine the architecture.
159
- - Specifications: every spec, a folder per kind.
160
- - [Changelog](CHANGELOG.md).
161
- - Build plan: how ForgeGraph is being built, phase by phase.
142
+ - [Specifications](https://github.com/sskaye/forgegraph/blob/main/docs/specifications): the file that defines each kind of spec, every parameter with its default, range and description.
143
+ - [Built-in pack](https://github.com/sskaye/forgegraph/blob/main/docs/packs/forgegraph_default): forgegraph_default's specs.
144
+ - [Changelog](https://github.com/sskaye/forgegraph/blob/main/CHANGELOG.md).
145
+ - [Contributing](https://github.com/sskaye/forgegraph/blob/main/CONTRIBUTING.md): working on ForgeGraph itself.
146
+ - Design record, in [docs/design](https://github.com/sskaye/forgegraph/blob/main/docs/design):
147
+ - [Architecture](https://github.com/sskaye/forgegraph/blob/main/docs/design/architecture.md): how ForgeGraph is designed, and why.
148
+ - [To do](https://github.com/sskaye/forgegraph/blob/main/docs/design/todo.md): what's still planned.
162
149
 
163
150
  ## Contributing
164
151
 
165
- Feature requests and bug reports go to [GitHub issues](https://github.com/sskaye/forgegraph/issues); the skill can file them for you. CONTRIBUTING.md covers working on ForgeGraph itself. In short:
166
-
167
- ```bash
168
- uv sync && uv run pre-commit install
169
- ```
170
-
171
- ```bash
172
- uv run pytest --full && uv run ruff check . && uv run pyright
173
- ```
152
+ Feature requests and bug reports go to [GitHub issues](https://github.com/sskaye/forgegraph/issues); the skill can file them for you. [CONTRIBUTING.md](https://github.com/sskaye/forgegraph/blob/main/CONTRIBUTING.md) covers working on ForgeGraph itself: setup, the checks to run, and regenerating the catalogs.
174
153
 
175
154
  ## Repository map
176
155
 
177
156
  - **src/forgegraph/**: the package.
178
- - `graph.py`: the Python API (`fg.xy`, `fg.render`, `fg.graphspec`, `fg.load`) and the `Graph` object; `canvas.py`: the themed canvas.
157
+ - `graph.py`: the Python API (`fg.xy`, `fg.render`, `fg.graphspec`, `fg.load`) and the `Graph` object; `canvas.py`: `fg.blank`, the themed canvas; `drawn.py`: what they and layouts share once drawn; `data.py`: reading a GraphSpec's data.
179
158
  - **cli/**: the `forgegraph` command.
180
159
  - **spec/**: reading, checking and resolving specs, and the provenance record.
181
- - **drawing/**: drawing, layout and lint. **layouts/**: layouts. **jobs/**: scheduled renders.
182
- - **packs/**: packs and configs, and the built-in packs `forgegraph_base` and `forgegraph_base_2`. **fonts/**: bundled fonts and their licences.
183
- - **graph_types/**, **layers/**: the graph type and layer type definitions. **catalog/**, **catalogs/**: the catalog builder, and each definition's catalog file.
184
- - **skill/forgegraph/**: the agent skill.
160
+ - **drawing/**: drawing, layout and lint. **layouts/**: `fg.layout` and layouts. **jobs/**: scheduled renders.
161
+ - **specifications/**: the specification files, which define each kind of spec, and the graph types' and layer types' catalog files.
162
+ - **packs/**: packs and configs, and the built-in pack `forgegraph_default`. **fonts/**: bundled fonts and their licences.
163
+ - **catalog_build/**: the catalog builder.
164
+ - **skill/forgegraph/**: the agent skill. `forgemark.py`: Forgemark's review-comment format, and its pinned tool.
185
165
  - **catalog/**: the generated catalog pages.
186
- - **examples/**: sample data, and `packs/acme`, an example pack in a deliberately different style.
166
+ - **examples/**: sample data; `packs/acme`, an example pack in a deliberately different style; and `layouts/`, a paper figure and a dashboard.
187
167
  - **evals/skill/**: the skill's eval cases, run by `scripts/run_skill_evals.py`.
188
168
  - **tests/**, **scripts/**: tests, and build and maintenance scripts.
189
- - **docs/**: the documents above. **review/**: each build phase's review pages.
169
+ - **docs/**: the specifications' and packs' pages, the design record and the visual changelogs. **review/**: each build phase's review pages.
190
170