forgegraph 0.1.0__tar.gz → 0.2.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.
- {forgegraph-0.1.0 → forgegraph-0.2.0}/CHANGELOG.md +15 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/CONTRIBUTING.md +4 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/PKG-INFO +5 -5
- {forgegraph-0.1.0 → forgegraph-0.2.0}/README.md +4 -4
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/architecture.md +2 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/decisions.md +4 -4
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/catalog/base_theme.md +1 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/graphspec/polarization.md +3 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/pack/forgegraph_base.md +1 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/theme/base_theme.md +4 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/pyproject.toml +4 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/build_recreations.py +1 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/run_skill_evals.py +1 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/visual_changelog.py +23 -6
- forgegraph-0.2.0/src/forgegraph/__init__.py +58 -0
- forgegraph-0.1.0/src/forgegraph/blank.py → forgegraph-0.2.0/src/forgegraph/canvas.py +4 -4
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/catalog/examples.py +2 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/cli/__init__.py +2 -2
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/axes.py +4 -4
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/colorbar.py +4 -4
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/export.py +3 -3
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/figure.py +5 -5
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/key.py +4 -4
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/labels.py +4 -4
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/layers.py +4 -4
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/lint.py +3 -3
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/marks.py +8 -2
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/spacing.py +4 -4
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/xy.py +10 -10
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/graph.py +5 -5
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/jobs/run.py +6 -6
- {forgegraph-0.1.0/src/forgegraph/layout → forgegraph-0.2.0/src/forgegraph/layouts}/__init__.py +19 -19
- {forgegraph-0.1.0/src/forgegraph/layout → forgegraph-0.2.0/src/forgegraph/layouts}/arrange.py +3 -3
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/catalogs/themes/base_theme.yaml +1 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/graphspecs/polarization.yaml +3 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/pack.yaml +1 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/themes/base_theme.yaml +3 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base_2/pack.yaml +1 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/skill/forgegraph/references/themes_formats_configs.md +1 -1
- forgegraph-0.2.0/tests/conftest.py +30 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/recreations.py +1 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/render_helpers.py +2 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_axes.py +1 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_blank.py +1 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_catalog.py +3 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_cli.py +35 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_jobs.py +6 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_key_position.py +2 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_layers.py +50 -3
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_layout.py +17 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_lint.py +2 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_marks.py +3 -3
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_markup.py +1 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_packs.py +3 -2
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_perturbation.py +2 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_regression.py +3 -1
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_render.py +14 -8
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_text.py +5 -5
- {forgegraph-0.1.0 → forgegraph-0.2.0}/uv.lock +25 -1
- forgegraph-0.1.0/src/forgegraph/__init__.py +0 -27
- forgegraph-0.1.0/tests/conftest.py +0 -14
- {forgegraph-0.1.0 → forgegraph-0.2.0}/.gitignore +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/.pre-commit-config.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/LICENSE +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/TRADEMARKS.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/build-plan.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/forgemark-repro-reattach.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/forgemark-request.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/initial specification.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/catalog/base_format.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/catalog/graph_type_xy.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/catalog/layer_error_bar.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/catalog/layer_note.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/catalog/layer_reference_line.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/config/config.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/format/base_format.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/format/base_layout_format.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/graph_type/xy.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/layer/error_bar.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/layer/note.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/layer/reference_line.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/layout/base_layout.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/pack/acme/formats/slide.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/pack/acme/graphspecs/polarization-curve.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/pack/acme/layouts/dashboard.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/pack/acme/pack.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/pack/acme/schedules/workday.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/pack/acme/themes/acme.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/provenance/provenance.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/docs/specs/schedule/base_schedule.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/packs/acme/formats/slide.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/packs/acme/graphspecs/polarization-curve.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/packs/acme/layouts/dashboard.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/packs/acme/pack.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/packs/acme/references/house.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/packs/acme/schedules/workday.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/packs/acme/themes/acme.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/README.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/air_passengers.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/air_passengers_by_month.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/anscombe.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/assay_summary.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/cell_durability.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/cell_polarization.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/co2_monthly.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/diamonds.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/dose_response.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/economics.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/enzyme_kinetics.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/fmri.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/gapminder.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/geyser.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/growth.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/iris.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/lab_export.xlsx +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/lab_runs.xlsx +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/penguins.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/seaice.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/sensor_log_eu.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/stocks.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/tips.csv +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/examples/sample-data/weather.xlsx +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/build_api_notebook.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/build_bundled_skill.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/build_example_data.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/build_sample_data.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/check_denylist.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/forgemark.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/mirror_specs.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/report_skill_evals.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/scripts/smoke_installed.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/__main__.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/catalog/__init__.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/catalog/build.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/catalog/files.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/catalog/forgemark.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/catalog/page.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/catalogs/graph_types/xy.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/catalogs/layers/error_bar.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/catalogs/layers/note.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/catalogs/layers/reference_line.yaml +0 -0
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/__init__.py +0 -0
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/markup.py +0 -0
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/page.py +0 -0
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/style.py +0 -0
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/text.py +0 -0
- {forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/ticks.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/IBMPlexSerif-Bold.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/IBMPlexSerif-Light.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/IBMPlexSerif-Medium.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/IBMPlexSerif-Regular.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/IBMPlexSerif-SemiBold.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/OFL-IBMPlexSerif.txt +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/OFL-Roboto.txt +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/OFL-SourceSans3.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/Roboto-Bold.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/Roboto-Italic.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/Roboto-Light.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/Roboto-Medium.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/Roboto-Regular.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/Roboto-SemiBold.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/SourceSans3-Bold.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/SourceSans3-It.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/SourceSans3-Light.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/SourceSans3-Medium.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/SourceSans3-Regular.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/SourceSans3-Semibold.ttf +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/fonts/__init__.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/graph_types/__init__.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/graph_types/xy.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/jobs/__init__.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/jobs/status.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/layers/error_bar.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/layers/note.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/layers/reference_line.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/__init__.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/config.toml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/catalogs/formats/base_format.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/catalogs/formats/base_layout_format.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/formats/base_format.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/formats/base_layout_format.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/graphspecs/dated.parquet +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/graphspecs/fanned.parquet +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/graphspecs/polarization.parquet +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/graphspecs/reinforced.parquet +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/layouts/base_layout.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base/schedules/base_schedule.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base_2/catalogs/formats/compact_format.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base_2/catalogs/themes/base_theme.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base_2/formats/compact_format.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base_2/graphspecs/dated.parquet +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base_2/graphspecs/example.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base_2/graphspecs/fanned.parquet +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base_2/graphspecs/polarization.parquet +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base_2/graphspecs/reinforced.parquet +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/packs/forgegraph_base_2/themes/base_theme.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/skill/__init__.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/skill/forgegraph/SKILL.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/skill/forgegraph/examples/bars.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/skill/forgegraph/examples/figure.layout.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/skill/forgegraph/examples/figure.schedule.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/skill/forgegraph/examples/layers.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/skill/forgegraph/examples/xy.parquet +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/skill/forgegraph/examples/xy.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/skill/forgegraph/references/requests.md +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/spec/__init__.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/spec/common.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/spec/documents.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/spec/layout.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/spec/parameters.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/spec/provenance.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/spec/provenance.yaml +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/src/forgegraph/spec/schedule.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/crowded_runs.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/flow_sweep_wide.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/fuel_by_size.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/layout_anode_layers.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/layout_screening_and_rate.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/polarization.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/polarization_narrow.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/precipitation_loglog.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/replicates.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/screening_scatter.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/baselines/separator_colorbar.png +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/fixtures/catalog_comments.html +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/pack_helpers.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/spec_mirror.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_denylist.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_schedule.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_smoke.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_spec_mirrors.py +0 -0
- {forgegraph-0.1.0 → forgegraph-0.2.0}/tests/test_specs.py +0 -0
|
@@ -2,6 +2,21 @@
|
|
|
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. From 0.1.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
4
|
|
|
5
|
+
## 0.2.0 (2026-10-24)
|
|
6
|
+
|
|
7
|
+
Images that changed: the [visual changelog](review/visual-changelog/0.2.0.html).
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- 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.
|
|
12
|
+
- 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.
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- `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.
|
|
17
|
+
- 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`.
|
|
18
|
+
- 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.
|
|
19
|
+
|
|
5
20
|
## 0.1.0 (2026-10-24)
|
|
6
21
|
|
|
7
22
|
The first public release.
|
|
@@ -9,12 +9,14 @@ uv sync
|
|
|
9
9
|
uv run pre-commit install
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
The
|
|
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
13
|
|
|
14
14
|
```bash
|
|
15
|
-
uv run pytest && uv run ruff check . && uv run pyright
|
|
15
|
+
uv run pytest --full && uv run ruff check . && uv run pyright
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
+
Mark a new test `@pytest.mark.slow` if it takes over a second (`uv run pytest --durations=20` lists the slowest).
|
|
19
|
+
|
|
18
20
|
## After changing a definition or how graphs are drawn
|
|
19
21
|
|
|
20
22
|
A new or changed parameter needs its card in the matching catalog file under `src/forgegraph/catalogs/`; the build refuses a catalog that misses one.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: forgegraph
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: Consistent, high-quality graphs from pandas DataFrames, for people and AI agents. Early development.
|
|
5
5
|
Project-URL: Repository, https://github.com/sskaye/forgegraph
|
|
6
6
|
Author: Steven Kaye
|
|
@@ -123,7 +123,7 @@ Every named theme, format, GraphSpec, layout and schedule comes from a **pack**,
|
|
|
123
123
|
|
|
124
124
|
A **config** lists the packs that may be used:
|
|
125
125
|
|
|
126
|
-
- The main config, `~/.config/forgegraph/config.toml` (or the file `FORGEGRAPH_CONFIG` names), applies to all work. ForgeGraph writes it the first time
|
|
126
|
+
- The main config, `~/.config/forgegraph/config.toml` (or the file `FORGEGRAPH_CONFIG` names), applies to all work. ForgeGraph writes it, listing the built-in packs, the first time a command reads the configs, such as `catalog` or `render`.
|
|
127
127
|
- 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
128
|
- 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
129
|
|
|
@@ -169,16 +169,16 @@ uv sync && uv run pre-commit install
|
|
|
169
169
|
```
|
|
170
170
|
|
|
171
171
|
```bash
|
|
172
|
-
uv run pytest && uv run ruff check . && uv run pyright
|
|
172
|
+
uv run pytest --full && uv run ruff check . && uv run pyright
|
|
173
173
|
```
|
|
174
174
|
|
|
175
175
|
## Repository map
|
|
176
176
|
|
|
177
177
|
- **src/forgegraph/**: the package.
|
|
178
|
-
- `graph.py`: the Python API (`fg.xy`, `fg.render`, `fg.graphspec`, `fg.load`) and the `Graph` object; `
|
|
178
|
+
- `graph.py`: the Python API (`fg.xy`, `fg.render`, `fg.graphspec`, `fg.load`) and the `Graph` object; `canvas.py`: the themed canvas.
|
|
179
179
|
- **cli/**: the `forgegraph` command.
|
|
180
180
|
- **spec/**: reading, checking and resolving specs, and the provenance record.
|
|
181
|
-
- **
|
|
181
|
+
- **drawing/**: drawing, layout and lint. **layouts/**: layouts. **jobs/**: scheduled renders.
|
|
182
182
|
- **packs/**: packs and configs, and the built-in packs `forgegraph_base` and `forgegraph_base_2`. **fonts/**: bundled fonts and their licences.
|
|
183
183
|
- **graph_types/**, **layers/**: the graph type and layer type definitions. **catalog/**, **catalogs/**: the catalog builder, and each definition's catalog file.
|
|
184
184
|
- **skill/forgegraph/**: the agent skill.
|
|
@@ -98,7 +98,7 @@ Every named theme, format, GraphSpec, layout and schedule comes from a **pack**,
|
|
|
98
98
|
|
|
99
99
|
A **config** lists the packs that may be used:
|
|
100
100
|
|
|
101
|
-
- The main config, `~/.config/forgegraph/config.toml` (or the file `FORGEGRAPH_CONFIG` names), applies to all work. ForgeGraph writes it the first time
|
|
101
|
+
- The main config, `~/.config/forgegraph/config.toml` (or the file `FORGEGRAPH_CONFIG` names), applies to all work. ForgeGraph writes it, listing the built-in packs, the first time a command reads the configs, such as `catalog` or `render`.
|
|
102
102
|
- 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
103
|
- 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
104
|
|
|
@@ -144,16 +144,16 @@ uv sync && uv run pre-commit install
|
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
|
-
uv run pytest && uv run ruff check . && uv run pyright
|
|
147
|
+
uv run pytest --full && uv run ruff check . && uv run pyright
|
|
148
148
|
```
|
|
149
149
|
|
|
150
150
|
## Repository map
|
|
151
151
|
|
|
152
152
|
- **src/forgegraph/**: the package.
|
|
153
|
-
- `graph.py`: the Python API (`fg.xy`, `fg.render`, `fg.graphspec`, `fg.load`) and the `Graph` object; `
|
|
153
|
+
- `graph.py`: the Python API (`fg.xy`, `fg.render`, `fg.graphspec`, `fg.load`) and the `Graph` object; `canvas.py`: the themed canvas.
|
|
154
154
|
- **cli/**: the `forgegraph` command.
|
|
155
155
|
- **spec/**: reading, checking and resolving specs, and the provenance record.
|
|
156
|
-
- **
|
|
156
|
+
- **drawing/**: drawing, layout and lint. **layouts/**: layouts. **jobs/**: scheduled renders.
|
|
157
157
|
- **packs/**: packs and configs, and the built-in packs `forgegraph_base` and `forgegraph_base_2`. **fonts/**: bundled fonts and their licences.
|
|
158
158
|
- **graph_types/**, **layers/**: the graph type and layer type definitions. **catalog/**, **catalogs/**: the catalog builder, and each definition's catalog file.
|
|
159
159
|
- **skill/forgegraph/**: the agent skill.
|
|
@@ -502,8 +502,8 @@ forgegraph/
|
|
|
502
502
|
│ ├── graph_types/ # xy/, bar/ — graph_type.yaml + render.py + samples/
|
|
503
503
|
│ ├── layers/ # reference_line/, note/, … — layer.yaml + render.py
|
|
504
504
|
│ ├── fonts/ # bundled fonts
|
|
505
|
-
│ ├──
|
|
506
|
-
│ ├──
|
|
505
|
+
│ ├── drawing/ # matplotlib engine, text markup, lint, export, provenance
|
|
506
|
+
│ ├── layouts/ # multi-panel figures and dashboards
|
|
507
507
|
│ ├── jobs/ # running a schedule, status files
|
|
508
508
|
│ ├── packs/ # finding packs and configs; the built-in packs forgegraph_base/ and forgegraph_base_2/
|
|
509
509
|
│ ├── catalog/ # HTML catalog, Forgemark carry-over
|
|
@@ -73,11 +73,11 @@ Decisions made while building that refine or depart from [architecture.md](archi
|
|
|
73
73
|
|
|
74
74
|
**Default look, round 1 (Steven).** The default format's height is auto (the plot box keeps plot\_box.aspect) and its base font 18 pt. Tick labels: a y label's digits are centred on its tick, and the new theme parameter tick.label\_gap\_mult sets the gap from a tick to its label's digits on both axes (matplotlib measured both from a text box that reaches well above the digits). A colour bar is exactly the plot box's height, so an auto figure size can't stretch it. Tests draw at their own fixed size (150 × 140 mm, 12 pt), so tuning the defaults doesn't change what they check.
|
|
75
75
|
|
|
76
|
-
**Text is measured to its letters (Steven, phase 3).** Matplotlib spaces text by a box sized for the font's tallest letters and deepest descenders, so its gaps aren't the gaps you see. Following the CSS `text-box: trim-both cap alphabetic` convention, Figma's vertical trim and D3's axis offsets, a text's edges run from the font's capital height to its baseline and grow only where its letters reach further (superscripts, descenders). Rows of text share one set of edges; collision checks use the letters themselves. forgegraph/
|
|
76
|
+
**Text is measured to its letters (Steven, phase 3).** Matplotlib spaces text by a box sized for the font's tallest letters and deepest descenders, so its gaps aren't the gaps you see. Following the CSS `text-box: trim-both cap alphabetic` convention, Figma's vertical trim and D3's axis offsets, a text's edges run from the font's capital height to its baseline and grow only where its letters reach further (superscripts, descenders). Rows of text share one set of edges; collision checks use the letters themselves. forgegraph/drawing/text.py measures; drawing/spacing.py sets the tick-label, axis-title and title gaps from it; drawing/figure.py lays the figure out itself (no matplotlib layout engine), placing the plot box so what's drawn sits a fixed margin from each edge; drawing/key.py draws legends and style keys. New theme parameters: title.gap\_mult, axis\_title.gap\_mult; legend title\_align, frame\_width\_mult, padding\_mult (one value for every side), title\_gap\_mult, row\_gap\_mult, handle\_length\_mult, handle\_gap\_mult, inset\_mult; color\_bar width\_mult and gap\_mult (its ticks and title use the axes' settings); watermark weight, angle and span (it is centred on, and fitted to, the plot box); tick.minor\_num, minor\_length\_mult and minor\_width\_mult.
|
|
77
77
|
|
|
78
78
|
**Default look, round 2 (Steven).** Legend rows and the title-to-first-entry gap are about half what they were, the sample-to-name gap 20% less, and the legend title is left-aligned. series.marker\_edge\_width\_mult is 0.06. interior\_label.max\_axis\_extension is a limit: the x-axis grows by the least that fits the labels. The example GraphSpec titles its color bar by column.
|
|
79
79
|
|
|
80
|
-
**Default look, round 3 (Steven).** Roboto (SIL Open Font License) is the default font, chosen from a comparison of 13 open fonts. Major ticks on linear axes come from a published algorithm chosen by tick.algorithm (
|
|
80
|
+
**Default look, round 3 (Steven).** Roboto (SIL Open Font License) is the default font, chosen from a comparison of 13 open fonts. Major ticks on linear axes come from a published algorithm chosen by tick.algorithm (drawing/ticks.py): extended\_wilkinson (Talbot, Lin & Hanrahan 2010, the default), wilkinson, heckbert, nelder (AS 96), r\_pretty or matplotlib; each gets a target label count from the axis length. Text is drawn without font hinting, so it has the same width at every resolution and what's laid out is what's saved; the box lines' half-widths count in the layout's visible extent, so the figure's margins are exact.
|
|
81
81
|
|
|
82
82
|
**Parameter names and the catalog page, round 4 (Steven).** Parameters nest in categories and sub-categories to any depth (a mapping inside a category is a sub-category); no path is a prefix of another, across kinds. No parameter name says \_mult: every size, width, length and gap is × figure.base\_size. The scheme: theme font, background, title, axis (title, tick, tick.label, tick.minor), plot\_area, grid, series (line, marker, benchmark), legend (label, direct, key, color\_bar), error\_bar, watermark; format figure, output, provenance; graph type axis (x, y), encoding (color, line\_style, marker\_shape, marker\_fill, detail, order), benchmark, mark (line, marker), legend (method, key.title.text, color\_bar.title.text). Where a standard term exists it follows Vega-Lite (encoding, mark, detail), keeping ForgeGraph's nesting, snake\_case and units; Vega-Lite's names weren't adopted wholesale, since a third of the parameters have no equivalent there. "Legend" is the umbrella for every way of naming what colors and styles mean (Vega-Lite's usage); the legend methods are direct, key and none, chosen by legend.method within the theme's legend.methods. series.colors is a named palette (color\_blind, Tableau's Color Blind palette; tableau\_10; okabe\_ito; tol\_bright; tol\_muted) or a list of hex colors. legend.color\_bar.layout places a color bar's title: title\_above (the default), title\_along (reading downward, its baseline facing the bar) or below (a horizontal bar under the x-axis title). The catalog page writes allowed values tersely (float > 0, int ≥ 0, float, 0-1, hex color code, alternatives separated by |, None last, lists in []), has no baseline-value column, groups each table by category, and shows cards only for variable parameters; the perturbation test still draws every card in the catalog files. The default format saves at 600 dpi, and its output.file\_types is variable (default [png]).
|
|
83
83
|
|
|
@@ -111,13 +111,13 @@ Decisions made while building that refine or depart from [architecture.md](archi
|
|
|
111
111
|
|
|
112
112
|
**The layout always fits its tick labels.** The layout lays out, measures the room needed around the plot box, and repeats until a pass changes the figure's size by under 0.001 in and moves the box by under 0.0001 of the figure. Tick labels can keep it from settling: a taller box gets more, wider labels, which make it shorter again. After 6 unsettled passes it lays out once more with, on each side, the most room either of the last two passes needed: an alternation has both its states there, so whichever labels the final draw has fit. Earlier passes, made while the figure was far from its size, don't count; including them left too little room on a graph that was settling slowly. Ticks are cleaned of float noise by rounding to decimal places that suit their step, not to whole multiples of it, which merged ticks that start off a multiple (1950, 1970… became 1960, 1960…).
|
|
113
113
|
|
|
114
|
-
**Log-axis ticks come from published algorithms (Steven, phase 4).** The theme's axis.tick.log\_algorithm picks one: breaks\_log (the default), a port of R's scales::breaks\_log (ggplot2's default for log axes; MIT licence, notice in
|
|
114
|
+
**Log-axis ticks come from published algorithms (Steven, phase 4).** The theme's axis.tick.log\_algorithm picks one: breaks\_log (the default), a port of R's scales::breaks\_log (ggplot2's default for log axes; MIT licence, notice in drawing/ticks.py), or matplotlib, matplotlib's LogLocator (powers of ten only). breaks\_log's target number of breaks is how many ticks the theme's linear algorithm places across the axis's log10 range; where it gives up (an axis within one power of ten), the linear algorithm places the ticks. On either, the labels must fit: while the drawn labels would overlap or come within the tick-label gap of each other, the algorithm is asked for one tick fewer. This replaced a rule of ForgeGraph's own (1-2-5 steps within three decades), whose labels ran together on short axes in the skill evals.
|
|
115
115
|
|
|
116
116
|
## After phase 4
|
|
117
117
|
|
|
118
118
|
**The watermark belongs to the theme's author (Steven).** A GraphSpec can't change the watermark, since its parameters are fixed in the theme; a theme's author can restyle it however they like, even out of sight. An organisation that wants it required keeps those parameters fixed in its own theme. Its text must have at least one visible character, since it's drawn from its letters' outlines; a theme whose text has none is an error.
|
|
119
119
|
|
|
120
|
-
**The figure checks itself.** A ForgeGraph figure is a GraphFigure on a GraphCanvas (
|
|
120
|
+
**The figure checks itself.** A ForgeGraph figure is a GraphFigure on a GraphCanvas (drawing/figure.py). Whatever draws or saves it, ForgeGraph or matplotlib directly (`figure.savefig`, a notebook showing the figure), first checks whether it's still as rendering left it: the same artists, drawing the same pixels (a hash of the figure drawn at its own size and resolution). A graph found changed stays non-standard, and every drawing of it carries the watermark, which sizes itself to the plot box each time it's drawn. Every save embeds the provenance record, through one function per file type's carrier (drawing/export.py), unless the caller sets the carrier's own key, as the catalog does to keep its images free of metadata.
|
|
121
121
|
|
|
122
122
|
**provenance: off keeps the non-standard flag.** With off, a standard graph's files carry no record; a non-standard graph's carry `level: off`, the ForgeGraph version and `nonstandard: true`, so they can still be told apart. `forgegraph load` reports such a record and can't recover a GraphSpec from it.
|
|
123
123
|
|
|
@@ -196,7 +196,7 @@ variations: *# Every parameter of the theme, by category: its
|
|
|
196
196
|
layer:\
|
|
197
197
|
error_bar:\
|
|
198
198
|
cap_size: {value: 0.8, from: error_bars} *# \[positive float\]; Cap width, × base size.*\
|
|
199
|
-
color: {value:
|
|
199
|
+
color: {value: series, from: error_bars} *# \[series, hex color\]; Error bar color. series: the series' color.*\
|
|
200
200
|
line_width: {value: 0.25, from: error_bars} *# \[positive float\]; Line width, × base size.*\
|
|
201
201
|
reference_line:\
|
|
202
202
|
line_style: {value: dotted, from: target} *# \[solid, dashed, dotted, dashdot\]; Line style.*\
|
|
@@ -127,6 +127,9 @@ variable_parameters: *# List of variable parameters for the G
|
|
|
127
127
|
file_types: \[png\] *# \[png, jpg, tiff, svg, pdf, html\]; File types saved.*\
|
|
128
128
|
provenance:\
|
|
129
129
|
level: full *# \[full, minimal, off\]; Which entries of the provenance record (docs/specs/provenance) each saved file carries. off: none.*\
|
|
130
|
+
layer:\
|
|
131
|
+
error_bar:\
|
|
132
|
+
color: "#000000" *# \[series, hex color\]; Error bar color. series: the series' color.*\
|
|
130
133
|
layers: *# Layers drawn on the graph, each under a name of the GraphSpec's choosing, drawn in this order.*\
|
|
131
134
|
target:\
|
|
132
135
|
type: reference_line *# \[layer type\]; The layer's type: one of the graph type's layer.types.*\
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
This page mirrors src/forgegraph/packs/forgegraph_base/pack.yaml, which is the specification. A test fails if they ever differ.
|
|
4
4
|
|
|
5
5
|
name: forgegraph_base *# \[text\]; The pack's name, either a folder where the pack is stored or a pip pack's entry point.*\
|
|
6
|
-
version: 0.
|
|
6
|
+
version: 0.2.0 *# \[text\]; The pack's release version.*\
|
|
7
7
|
description: ForgeGraph's base specs, complete, for other specs to extend or to use as they are. *# \[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
9
|
requires: None *# \[None, version specifier\]; The ForgeGraph versions the pack works with, as pip writes them, e.g. ">=0.6, <1". None: any.*
|
|
@@ -99,7 +99,6 @@ fixed_parameters: *# List of fixed parameters for the theme.*
|
|
|
99
99
|
error_bar:\
|
|
100
100
|
cap_size: 0.25 *# \[positive float\]; Cap width, × base size.*\
|
|
101
101
|
line_width: 0.08 *# \[positive float\]; Line width, × base size.*\
|
|
102
|
-
color: series *# \[series, hex color\]; Error bar color. series: the series' color.*\
|
|
103
102
|
reference_line:\
|
|
104
103
|
color: "#808080" *# \[hex color\]; Line and label color, unless drawn per series.*\
|
|
105
104
|
line_style: dashed *# \[solid, dashed, dotted, dashdot\]; Line style.*\
|
|
@@ -156,4 +155,7 @@ variable_parameters: *# List of variable parameters for the t
|
|
|
156
155
|
max_relative_distance: 0.8 *# \[0-1\]; Most a label's distance to its series may be, ÷ its distance to the next nearest.*\
|
|
157
156
|
max_axis_extension: 0.15 *# \[0-1\]; Most the x-axis may grow to fit labels, × its range.*\
|
|
158
157
|
color_bar:\
|
|
159
|
-
colors: viridis *# \[viridis, cividis, plasma, inferno, magma, greys, blues, red_blue, hex color, two hex colors\]; Colors for a numeric encoding.color: a named scale, one hex color (light to it) or two (first to second)
|
|
158
|
+
colors: viridis *# \[viridis, cividis, plasma, inferno, magma, greys, blues, red_blue, hex color, two hex colors\]; Colors for a numeric encoding.color: a named scale, one hex color (light to it) or two (first to second).*\
|
|
159
|
+
layer:\
|
|
160
|
+
error_bar:\
|
|
161
|
+
color: "#000000" *# \[series, hex color\]; Error bar color. series: the series' color.*
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "forgegraph"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.2.0"
|
|
4
4
|
description = "Consistent, high-quality graphs from pandas DataFrames, for people and AI agents. Early development."
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -36,6 +36,7 @@ forgegraph = "forgegraph.cli:app"
|
|
|
36
36
|
dev = [
|
|
37
37
|
"pytest>=8",
|
|
38
38
|
"pytest-cov>=5",
|
|
39
|
+
"pytest-xdist>=3.6", # tests run in parallel
|
|
39
40
|
"ruff>=0.6",
|
|
40
41
|
"pyright>=1.1.380",
|
|
41
42
|
"pre-commit>=3.8",
|
|
@@ -74,7 +75,8 @@ typeCheckingMode = "standard"
|
|
|
74
75
|
|
|
75
76
|
[tool.pytest.ini_options]
|
|
76
77
|
testpaths = ["tests"]
|
|
77
|
-
addopts = "--strict-markers"
|
|
78
|
+
addopts = "--strict-markers -n auto" # -n 0 runs them one at a time
|
|
79
|
+
markers = ["slow: over a second, or drawing every catalog card; run only with --full"]
|
|
78
80
|
|
|
79
81
|
[tool.coverage.run]
|
|
80
82
|
source = ["forgegraph"]
|
|
@@ -24,7 +24,7 @@ import tempfile # noqa: E402
|
|
|
24
24
|
from recreations import LAYOUT_RECREATIONS, RECREATIONS # noqa: E402
|
|
25
25
|
|
|
26
26
|
from forgegraph.catalog.build import write # noqa: E402
|
|
27
|
-
from forgegraph.
|
|
27
|
+
from forgegraph.drawing.style import isolated # noqa: E402
|
|
28
28
|
|
|
29
29
|
BASELINE_DPI = 72
|
|
30
30
|
CSS_DPI = 96 # a CSS inch, so images show at the figure's real size
|
|
@@ -292,7 +292,7 @@ def _layout_checks(want: dict[str, Any], ws: Path, allowed: list[str]) -> list[C
|
|
|
292
292
|
"""The final layout: it draws, its tabs and tiles, a spanning tile, a blank cell, its
|
|
293
293
|
column widths, and its lint."""
|
|
294
294
|
import forgegraph as fg
|
|
295
|
-
from forgegraph.
|
|
295
|
+
from forgegraph.layouts import _load
|
|
296
296
|
from forgegraph.spec.layout import BLANK, tabs
|
|
297
297
|
|
|
298
298
|
layouts = _named(ws, ".layout.yaml")
|
|
@@ -4,8 +4,8 @@ uv run python scripts/visual_changelog.py main # main against the wor
|
|
|
4
4
|
uv run python scripts/visual_changelog.py v0.1.0 v0.2.0 # between two commits
|
|
5
5
|
[--out review/visual-changelog.html]
|
|
6
6
|
|
|
7
|
-
Compares the regression baselines (tests/baselines/*.png) and
|
|
8
|
-
and writes one page showing each changed, added or removed image.
|
|
7
|
+
Compares the regression baselines (tests/baselines/*.png) and each catalog page's figures (by
|
|
8
|
+
id), and writes one page showing each changed, added or removed image.
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
11
|
from __future__ import annotations
|
|
@@ -20,7 +20,7 @@ from pathlib import Path
|
|
|
20
20
|
ROOT = Path(__file__).parents[1]
|
|
21
21
|
BASELINES = "tests/baselines"
|
|
22
22
|
CATALOG = "catalog/forgegraph_base.html"
|
|
23
|
-
EARLIER_CATALOG = "catalog/catalog.html" #
|
|
23
|
+
EARLIER_CATALOG = "catalog/catalog.html" # forgegraph_base's page before phase 6
|
|
24
24
|
FIGURE = re.compile(r'<figure id="([^"]+)"><img [^>]*src="data:image/png;base64,([^"]+)"')
|
|
25
25
|
|
|
26
26
|
|
|
@@ -37,9 +37,18 @@ def _baselines(ref: str | None) -> dict[str, bytes]:
|
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
|
|
40
|
-
def
|
|
40
|
+
def _pages(ref: str | None) -> set[str]:
|
|
41
|
+
"""The catalog pages at a commit, or in the working tree, by path."""
|
|
42
|
+
if ref is None:
|
|
43
|
+
return {f"catalog/{p.name}" for p in (ROOT / "catalog").glob("*.html")}
|
|
44
|
+
names = _git("ls-tree", "--name-only", f"{ref}:catalog").decode().split()
|
|
45
|
+
pages = {f"catalog/{n}" for n in names if n.endswith(".html")}
|
|
46
|
+
return {CATALOG if p == EARLIER_CATALOG else p for p in pages}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _catalog(ref: str | None, page: str) -> dict[str, bytes]:
|
|
41
50
|
text = None
|
|
42
|
-
for name in (
|
|
51
|
+
for name in (page, EARLIER_CATALOG) if page == CATALOG else (page,):
|
|
43
52
|
try:
|
|
44
53
|
text = (
|
|
45
54
|
(ROOT / name).read_text(encoding="utf-8")
|
|
@@ -94,7 +103,15 @@ def page(before: str, after: str | None) -> str:
|
|
|
94
103
|
body = "\n".join(
|
|
95
104
|
[
|
|
96
105
|
_section("Regression baselines", "baselines", _baselines(before), _baselines(after)),
|
|
97
|
-
|
|
106
|
+
*(
|
|
107
|
+
_section(
|
|
108
|
+
f"Catalog: {Path(p).stem}",
|
|
109
|
+
Path(p).stem,
|
|
110
|
+
_catalog(before, p),
|
|
111
|
+
_catalog(after, p),
|
|
112
|
+
)
|
|
113
|
+
for p in sorted(_pages(before) | _pages(after))
|
|
114
|
+
),
|
|
98
115
|
]
|
|
99
116
|
)
|
|
100
117
|
return (
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""ForgeGraph: consistent, high-quality graphs from a declarative GraphSpec.
|
|
2
|
+
|
|
3
|
+
The API loads on first use, so `forgegraph --version` and `--help` don't load matplotlib and
|
|
4
|
+
pandas.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from importlib import import_module
|
|
10
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
11
|
+
from typing import TYPE_CHECKING, Any
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
__version__ = version("forgegraph")
|
|
15
|
+
except PackageNotFoundError: # running from a source tree without installation
|
|
16
|
+
__version__ = "0.0.0"
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from forgegraph.canvas import Blank, blank
|
|
20
|
+
from forgegraph.graph import Graph, SpecError, graphspec, load, render, xy
|
|
21
|
+
from forgegraph.layouts import Layout
|
|
22
|
+
from forgegraph.layouts import render_layout as layout
|
|
23
|
+
|
|
24
|
+
_API = { # name: (module, attribute)
|
|
25
|
+
"Blank": ("forgegraph.canvas", "Blank"),
|
|
26
|
+
"blank": ("forgegraph.canvas", "blank"),
|
|
27
|
+
"Graph": ("forgegraph.graph", "Graph"),
|
|
28
|
+
"SpecError": ("forgegraph.graph", "SpecError"),
|
|
29
|
+
"graphspec": ("forgegraph.graph", "graphspec"),
|
|
30
|
+
"load": ("forgegraph.graph", "load"),
|
|
31
|
+
"render": ("forgegraph.graph", "render"),
|
|
32
|
+
"xy": ("forgegraph.graph", "xy"),
|
|
33
|
+
"Layout": ("forgegraph.layouts", "Layout"),
|
|
34
|
+
"layout": ("forgegraph.layouts", "render_layout"),
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def __getattr__(name: str) -> Any:
|
|
39
|
+
if name not in _API:
|
|
40
|
+
raise AttributeError(f"module 'forgegraph' has no attribute {name!r}")
|
|
41
|
+
module, attribute = _API[name]
|
|
42
|
+
value = globals()[name] = getattr(import_module(module), attribute)
|
|
43
|
+
return value
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
__all__ = [
|
|
47
|
+
"Blank",
|
|
48
|
+
"Graph",
|
|
49
|
+
"Layout",
|
|
50
|
+
"SpecError",
|
|
51
|
+
"__version__",
|
|
52
|
+
"blank",
|
|
53
|
+
"graphspec",
|
|
54
|
+
"layout",
|
|
55
|
+
"load",
|
|
56
|
+
"render",
|
|
57
|
+
"xy",
|
|
58
|
+
]
|
|
@@ -19,9 +19,8 @@ from typing import Any
|
|
|
19
19
|
from matplotlib.axes import Axes
|
|
20
20
|
|
|
21
21
|
from forgegraph import __version__
|
|
22
|
-
from forgegraph.
|
|
23
|
-
from forgegraph.
|
|
24
|
-
from forgegraph.render.figure import (
|
|
22
|
+
from forgegraph.drawing import export
|
|
23
|
+
from forgegraph.drawing.figure import (
|
|
25
24
|
GraphFigure,
|
|
26
25
|
LayoutError,
|
|
27
26
|
Watermark,
|
|
@@ -29,7 +28,8 @@ from forgegraph.render.figure import (
|
|
|
29
28
|
layout,
|
|
30
29
|
new_figure,
|
|
31
30
|
)
|
|
32
|
-
from forgegraph.
|
|
31
|
+
from forgegraph.drawing.style import PALETTES, Style, isolated
|
|
32
|
+
from forgegraph.graph import SpecError, _created, _plain, spec_record
|
|
33
33
|
from forgegraph.spec.documents import (
|
|
34
34
|
Registry,
|
|
35
35
|
name_problems,
|
|
@@ -11,9 +11,9 @@ from dataclasses import dataclass
|
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
from typing import Any
|
|
13
13
|
|
|
14
|
+
from forgegraph.drawing import export
|
|
15
|
+
from forgegraph.drawing.style import isolated
|
|
14
16
|
from forgegraph.graph import Graph, data_path, render
|
|
15
|
-
from forgegraph.render import export
|
|
16
|
-
from forgegraph.render.style import isolated
|
|
17
17
|
from forgegraph.spec.documents import Registry, builtin, resolve, resolve_layers
|
|
18
18
|
from forgegraph.spec.parameters import NONE, Parameter, definitions, tree_has, tree_set
|
|
19
19
|
|
|
@@ -88,7 +88,7 @@ def render(
|
|
|
88
88
|
several tabs saves a file per tab (name-<tab>.png), a PDF with a page per tab, and an
|
|
89
89
|
HTML page with every tab."""
|
|
90
90
|
import forgegraph as fg
|
|
91
|
-
from forgegraph.
|
|
91
|
+
from forgegraph.layouts import is_layout, stem
|
|
92
92
|
from forgegraph.spec.documents import nonstandard_note
|
|
93
93
|
|
|
94
94
|
drawn: Any
|
|
@@ -138,7 +138,7 @@ def explain(
|
|
|
138
138
|
"""Show every value a graph is drawn with, whether it's fixed, and which file set it. For
|
|
139
139
|
a layout: its own values, then each tile's, under tabs.<tab>.tiles.<tile>."""
|
|
140
140
|
import forgegraph as fg
|
|
141
|
-
from forgegraph.
|
|
141
|
+
from forgegraph.layouts import explain_layout, is_layout, nonstandard_packs_of
|
|
142
142
|
from forgegraph.spec.documents import explain as explain_values
|
|
143
143
|
from forgegraph.spec.documents import load as load_yaml
|
|
144
144
|
from forgegraph.spec.documents import nonstandard_note, packs_used, registry_for, validate
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
- **Type** (data.type): decimal, integer, datetime or categorical. auto takes it from the
|
|
4
4
|
column: dates and times, then numbers (integer for an integer column), otherwise
|
|
5
|
-
categorical. An integer axis's automatic ticks are whole numbers (forgegraph.
|
|
5
|
+
categorical. An integer axis's automatic ticks are whole numbers (forgegraph.drawing.ticks).
|
|
6
6
|
- **Categories** sit at positions 0, 1, 2 … in data.order: as in the data (a pandas
|
|
7
7
|
Categorical's own order), alphanumeric (natural: Run 2 before Run 10), or by the other
|
|
8
8
|
axis's value (the total at each category), ascending or descending. Every value present is
|
|
@@ -43,9 +43,9 @@ from matplotlib.dates import date2num, num2date
|
|
|
43
43
|
from matplotlib.text import Text
|
|
44
44
|
from matplotlib.ticker import FixedLocator, Formatter, Locator, MultipleLocator
|
|
45
45
|
|
|
46
|
-
from forgegraph.
|
|
47
|
-
from forgegraph.
|
|
48
|
-
from forgegraph.
|
|
46
|
+
from forgegraph.drawing.markup import literal
|
|
47
|
+
from forgegraph.drawing.style import Style
|
|
48
|
+
from forgegraph.drawing.ticks import LogTicks, NiceTicks, target
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
class DrawError(ValueError):
|
{forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/colorbar.py
RENAMED
|
@@ -21,10 +21,10 @@ from matplotlib.cm import ScalarMappable
|
|
|
21
21
|
from matplotlib.colors import Colormap, Normalize
|
|
22
22
|
from matplotlib.transforms import Affine2D, Bbox, ScaledTranslation
|
|
23
23
|
|
|
24
|
-
from forgegraph.
|
|
25
|
-
from forgegraph.
|
|
26
|
-
from forgegraph.
|
|
27
|
-
from forgegraph.
|
|
24
|
+
from forgegraph.drawing import spacing, text
|
|
25
|
+
from forgegraph.drawing.figure import WATERMARK, texts_of, tick_marks
|
|
26
|
+
from forgegraph.drawing.style import Style
|
|
27
|
+
from forgegraph.drawing.ticks import NiceTicks
|
|
28
28
|
|
|
29
29
|
TITLE_ABOVE, TITLE_ALONG, BELOW = "title_above", "title_along", "below"
|
|
30
30
|
|
{forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/export.py
RENAMED
|
@@ -7,7 +7,7 @@ The record is one JSON document, stored invisibly in each file type:
|
|
|
7
7
|
- pdf: the document information dictionary, key /ForgeGraph;
|
|
8
8
|
- jpg: a JPEG comment segment;
|
|
9
9
|
- tiff: the ImageDescription tag;
|
|
10
|
-
- html: a JSON script in the page's head (
|
|
10
|
+
- html: a JSON script in the page's head (drawing/page.py), with each figure's SVG carrying
|
|
11
11
|
its own record too.
|
|
12
12
|
|
|
13
13
|
A layout's PDF has a page per tab, and the document's record covers them all.
|
|
@@ -31,7 +31,7 @@ from matplotlib.backends.backend_pdf import PdfPages
|
|
|
31
31
|
from matplotlib.figure import Figure
|
|
32
32
|
from PIL import Image
|
|
33
33
|
|
|
34
|
-
from forgegraph.
|
|
34
|
+
from forgegraph.drawing import page
|
|
35
35
|
|
|
36
36
|
KEY = "ForgeGraph"
|
|
37
37
|
FILE_TYPES = ("png", "jpg", "tiff", "svg", "pdf", "html")
|
|
@@ -77,7 +77,7 @@ def with_record(kind: str, kwargs: dict[str, Any], record: dict[str, Any] | None
|
|
|
77
77
|
|
|
78
78
|
def save(fig: Figure, path: Path, dpi: int) -> Path:
|
|
79
79
|
"""Save fig to path (its suffix is the file type). A ForgeGraph figure's canvas adds the
|
|
80
|
-
provenance record (forgegraph.
|
|
80
|
+
provenance record (forgegraph.drawing.figure.GraphCanvas)."""
|
|
81
81
|
kind = kind_of(path)
|
|
82
82
|
if kind not in IMAGES:
|
|
83
83
|
raise ValueError(f"can't save as .{kind}; file types are {', '.join(FILE_TYPES)}")
|
{forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/figure.py
RENAMED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Figures sized by the format, laid out by what's visible.
|
|
2
2
|
|
|
3
3
|
Width and height are in mm. ForgeGraph lays the figure out itself rather than with
|
|
4
|
-
matplotlib's layout engines, which space text by its box (see forgegraph.
|
|
4
|
+
matplotlib's layout engines, which space text by its box (see forgegraph.drawing.text): the
|
|
5
5
|
plot box is placed so that everything drawn, measured to its letters and lines, sits MARGIN
|
|
6
6
|
from each edge of the figure. With both sizes given, the plot box takes the space left; with
|
|
7
7
|
one auto, the plot box keeps the theme's plot_area.aspect and the figure is fitted around it.
|
|
@@ -26,10 +26,10 @@ from matplotlib.text import Text
|
|
|
26
26
|
from matplotlib.textpath import TextPath
|
|
27
27
|
from matplotlib.transforms import Affine2D, Bbox, ScaledTranslation
|
|
28
28
|
|
|
29
|
-
from forgegraph.
|
|
30
|
-
from forgegraph.
|
|
31
|
-
from forgegraph.
|
|
32
|
-
from forgegraph.
|
|
29
|
+
from forgegraph.drawing import export, spacing, text
|
|
30
|
+
from forgegraph.drawing.key import keys
|
|
31
|
+
from forgegraph.drawing.markup import literal
|
|
32
|
+
from forgegraph.drawing.style import MM_PER_INCH, Style, isolated
|
|
33
33
|
|
|
34
34
|
MARGIN_IN = 0.04 # space kept between what's drawn and the figure's edges
|
|
35
35
|
WATERMARK = "forgegraph-watermark"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Keys: a legend naming the series, or a style key explaining line styles and markers.
|
|
2
2
|
|
|
3
3
|
ForgeGraph lays a key out itself, with every gap measured to the letters (see
|
|
4
|
-
forgegraph.
|
|
4
|
+
forgegraph.drawing.text): an optional title, then one row per entry, a line sample then the
|
|
5
5
|
entry's name. The theme's legend parameters set the frame, its padding (the same on every
|
|
6
6
|
side), the gaps between title and rows and between rows, the sample's length and its gap to
|
|
7
7
|
the name, and the key's inset from the plot box.
|
|
@@ -24,9 +24,9 @@ from matplotlib.patches import Rectangle
|
|
|
24
24
|
from matplotlib.text import Text
|
|
25
25
|
from matplotlib.transforms import Affine2D, Bbox, ScaledTranslation, Transform
|
|
26
26
|
|
|
27
|
-
from forgegraph.
|
|
28
|
-
from forgegraph.
|
|
29
|
-
from forgegraph.
|
|
27
|
+
from forgegraph.drawing import text
|
|
28
|
+
from forgegraph.drawing.marks import Bars
|
|
29
|
+
from forgegraph.drawing.style import Style
|
|
30
30
|
|
|
31
31
|
# Each position: where it is on the plot box (axes fraction), and which way the key extends
|
|
32
32
|
# from it: right (1), left (-1) or centred (0); down (-1), up (1) or centred (0).
|
{forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/labels.py
RENAMED
|
@@ -29,10 +29,10 @@ from matplotlib.lines import Line2D
|
|
|
29
29
|
from matplotlib.ticker import FixedLocator
|
|
30
30
|
from matplotlib.transforms import Bbox
|
|
31
31
|
|
|
32
|
-
from forgegraph.
|
|
33
|
-
from forgegraph.
|
|
34
|
-
from forgegraph.
|
|
35
|
-
from forgegraph.
|
|
32
|
+
from forgegraph.drawing import text
|
|
33
|
+
from forgegraph.drawing.key import KEY, Entry, Key
|
|
34
|
+
from forgegraph.drawing.marks import Bars
|
|
35
|
+
from forgegraph.drawing.style import Style
|
|
36
36
|
|
|
37
37
|
DIRECTIONS = [(1, 0), (-1, 0), (0, 1), (0, -1), (1, 1), (-1, 1), (1, -1), (-1, -1)]
|
|
38
38
|
SERIES_LABEL = "forgegraph-series-label"
|
{forgegraph-0.1.0/src/forgegraph/render → forgegraph-0.2.0/src/forgegraph/drawing}/layers.py
RENAMED
|
@@ -33,10 +33,10 @@ from matplotlib.axes import Axes
|
|
|
33
33
|
from matplotlib.text import Annotation
|
|
34
34
|
from matplotlib.transforms import Bbox
|
|
35
35
|
|
|
36
|
-
from forgegraph.
|
|
37
|
-
from forgegraph.
|
|
38
|
-
from forgegraph.
|
|
39
|
-
from forgegraph.
|
|
36
|
+
from forgegraph.drawing import marks
|
|
37
|
+
from forgegraph.drawing.axes import DrawError
|
|
38
|
+
from forgegraph.drawing.markup import markup
|
|
39
|
+
from forgegraph.drawing.style import LINE_STYLES, Style, unset
|
|
40
40
|
|
|
41
41
|
NOTE = "forgegraph-note"
|
|
42
42
|
REFERENCE = "forgegraph-reference-line"
|
|
@@ -37,9 +37,9 @@ from matplotlib.lines import Line2D
|
|
|
37
37
|
from matplotlib.text import Text
|
|
38
38
|
from matplotlib.transforms import Bbox
|
|
39
39
|
|
|
40
|
-
from forgegraph.
|
|
41
|
-
from forgegraph.
|
|
42
|
-
from forgegraph.
|
|
40
|
+
from forgegraph.drawing import text
|
|
41
|
+
from forgegraph.drawing.figure import WATERMARK, texts_of
|
|
42
|
+
from forgegraph.drawing.key import KEY, keys
|
|
43
43
|
|
|
44
44
|
MIN_TEXT_PT = 6.0 # the smallest text journals accept in a printed figure
|
|
45
45
|
OVERLAP_PX = 0.5 # letters closer than this count as touching, not overlapping
|