plotstyle 1.2.2__tar.gz → 1.2.3__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.
- {plotstyle-1.2.2 → plotstyle-1.2.3}/.gitignore +2 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/CHANGELOG.md +26 -1
- {plotstyle-1.2.2 → plotstyle-1.2.3}/PKG-INFO +58 -15
- {plotstyle-1.2.2 → plotstyle-1.2.3}/README.md +57 -14
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/_version.py +2 -2
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/cli/main.py +2 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/core/style.py +8 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/engine/rcparams.py +22 -3
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/preview/gallery.py +2 -2
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/nature.toml +1 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/schema.py +26 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_core/test_style.py +107 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_engine/test_rcparams.py +177 -3
- {plotstyle-1.2.2 → plotstyle-1.2.3}/LICENSE +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/pyproject.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/_compat/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/_compat/mpl_style.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/_utils/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/_utils/io.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/_utils/warnings.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/cli/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/_rendering.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/accessibility.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/okabe_ito.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/safe_grayscale.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/tol_bright.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/tol_high_contrast.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/tol_light.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/tol_muted.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/tol_rainbow_10.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/tol_rainbow_12.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/tol_rainbow_4.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/tol_rainbow_6.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/tol_rainbow_8.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/data/tol_vibrant.json +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/grayscale.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/color/palettes.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/core/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/core/export.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/core/figure.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/core/migrate.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/engine/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/engine/fonts.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/engine/latex.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/integrations/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/integrations/seaborn.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/bar.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/cjk-japanese.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/cjk-korean.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/cjk-simplified.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/cjk-traditional.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/grid.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/high-vis.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/latex-sans.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/minimal.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/no-latex.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/notebook.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/okabe-ito.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/pgf.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/presentation.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/russian.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/safe-grayscale.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/scatter.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/schema.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/tol-bright.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/tol-high-contrast.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/tol-light.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/tol-muted.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/tol-rainbow-10.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/tol-rainbow-12.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/tol-rainbow-4.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/tol-rainbow-6.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/tol-rainbow-8.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/tol-vibrant.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/overlays/turkish.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/preview/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/preview/print_size.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/py.typed +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/_templates.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/acs.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/cell.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/elsevier.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/ieee.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/plos.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/prl.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/science.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/springer.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/units.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/specs/wiley.toml +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/validation/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/validation/checks/__init__.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/validation/checks/_base.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/validation/checks/colors.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/validation/checks/dimensions.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/validation/checks/export.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/validation/checks/lines.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/validation/checks/typography.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/src/plotstyle/validation/report.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/conftest.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_cli/test_main.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_color/test_accessibility.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_color/test_grayscale.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_color/test_palettes.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_color/test_rendering.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_core/test_export.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_core/test_figure.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_core/test_migrate.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_engine/test_fonts.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_engine/test_latex.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_integrations/test_seaborn.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_preview/test_gallery.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_preview/test_print_size.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_specs/test_registry.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_specs/test_schema.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_specs/test_units.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_utils/test_io.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_utils/test_warnings.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_validation/test_checks.py +0 -0
- {plotstyle-1.2.2 → plotstyle-1.2.3}/tests/test_validation/test_report.py +0 -0
|
@@ -13,6 +13,30 @@ _Nothing yet._
|
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
+
## [1.2.3] - 2026-04-30
|
|
17
|
+
|
|
18
|
+
Minor release: automatic journal color cycle, `target_font_pt` typography field, Nature-specific rcParams, CLI improvements, a full documentation and example audit, and a new doc image generation script.
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **Automatic journal palette as default color cycle** (`plotstyle.use()`): calling `use("nature")` (or any journal key) now sets the journal's recommended palette as `axes.prop_cycle` automatically. Every `ax.plot()`, `ax.bar()`, and `ax.scatter()` call draws from it without any `color=` argument. A color overlay applied in the same `use()` call overrides this default.
|
|
23
|
+
- **`target_font_pt` field on `TypographySpec`**: optional `float | None` field that records a journal's explicitly stated target font size (as opposed to only a min/max range). When set, `build_rcparams()` uses it as `font.size` instead of the midpoint of the range. `nature.toml` sets `target_font_pt = 7.0` (Nature's guidelines explicitly state 7 pt as the standard text size).
|
|
24
|
+
- **`plotstyle info` CLI shows `Target size:`**: when `target_font_pt` is set for a journal, the `plotstyle info <journal>` command now prints a `Target size:` line under Typography.
|
|
25
|
+
- **Nature-specific tick and legend rcParams** (`build_rcparams()`): the Nature preset now applies inward-facing ticks (`xtick.direction: in`, `ytick.direction: in`), minor ticks visible on all axes, mirrored tick marks (`xtick.top: True`, `ytick.right: True`), and `legend.frameon: False` - matching Nature's published figure style guidelines.
|
|
26
|
+
- **`scripts/generate_docs_images.py`**: new script that regenerates all 9 static PNG images used in the documentation (`docs/images/`) from the current codebase in one headless run.
|
|
27
|
+
- **Docs images regenerated**: all 9 images in `docs/images/` rebuilt using the updated codebase - `quickstart_nature.png`, `multi_panel_science.png`, `palette_comparison.png`, `accessibility_colorblind.png`, `accessibility_grayscale.png`, `gallery_nature.png`, `gallery_ieee.png`, `seaborn_scatter_nature.png`, `overlay_bar.png`.
|
|
28
|
+
- **New test coverage**: `TestUseColorCycle` (automatic palette cycle), `TestUseFontSizeTarget` (target_font_pt font size selection), `TestBuildRcparamsLegend` (Nature legend.frameon), and `TestBuildRcparamsTicks` (Nature inward/mirrored tick rcParams).
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- **`examples/03_color_palettes.py`**: added Section 1 demonstrating the automatic default color cycle; renumbered remaining sections 2-6.
|
|
33
|
+
- **`examples/05_validation.py`**: added `is_failure` / `is_warning` convenience property usage.
|
|
34
|
+
- **`examples/09_registry_and_spec.py`**: expanded to cover `target_font_pt`, `is_official`, `assumed_fields`, and `registry.preload()`.
|
|
35
|
+
- **`examples/12_overlays.py`**: added color overlay, grid rendering overlay, scatter + IEEE warning, overlay inspection, and `list_overlays()` with category filter. Imports reorganized to comply with E402 (module-level imports at top); unused loop variable renamed to `_ls` to comply with B007.
|
|
36
|
+
- **Docs**: all docs updated to reflect the automatic palette cycle and `target_font_pt` changes; `colour` spelling standardized to `color` throughout.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
16
40
|
## [1.2.2] - 2026-04-27
|
|
17
41
|
|
|
18
42
|
Patch release: docs improvements, README example quality, and CI action bump.
|
|
@@ -172,7 +196,8 @@ First public alpha release.
|
|
|
172
196
|
- **Dynamic versioning**: version derived from git tags via `hatch-vcs` and `importlib.metadata`.
|
|
173
197
|
- **CI/CD pipeline**: GitHub Actions workflows for lint, type-check, test matrix, and automated PyPI release via OIDC Trusted Publishing.
|
|
174
198
|
|
|
175
|
-
[Unreleased]: https://github.com/rahulkaushal04/plotstyle/compare/v1.2.
|
|
199
|
+
[Unreleased]: https://github.com/rahulkaushal04/plotstyle/compare/v1.2.3...HEAD
|
|
200
|
+
[1.2.3]: https://github.com/rahulkaushal04/plotstyle/compare/v1.2.2...v1.2.3
|
|
176
201
|
[1.2.2]: https://github.com/rahulkaushal04/plotstyle/compare/v1.2.1...v1.2.2
|
|
177
202
|
[1.2.1]: https://github.com/rahulkaushal04/plotstyle/compare/v1.2.0...v1.2.1
|
|
178
203
|
[1.2.0]: https://github.com/rahulkaushal04/plotstyle/compare/v1.1.0...v1.2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: plotstyle
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: Matplotlib/seaborn style presets matching scientific journal requirements, with validation, export safety, and preview capabilities.
|
|
5
5
|
Project-URL: Homepage, https://github.com/rahulkaushal04/plotstyle
|
|
6
6
|
Project-URL: Documentation, https://plotstyle.readthedocs.io
|
|
@@ -99,6 +99,14 @@ Description-Content-Type: text/markdown
|
|
|
99
99
|
|
|
100
100
|
**PlotStyle** makes it easy to produce Matplotlib figures that meet the exact typographic, dimensional, and export requirements of major academic journals. It also integrates with Seaborn, with more integrations planned. Pick a journal, create your figure, save it. PlotStyle handles the rest.
|
|
101
101
|
|
|
102
|
+
<p align="center">
|
|
103
|
+
<img src="https://raw.githubusercontent.com/rahulkaushal04/plotstyle/main/examples/output/before_after.png" width="90%" alt="Left: default Matplotlib output. Right: the same figure styled with plotstyle.use('nature').">
|
|
104
|
+
</p>
|
|
105
|
+
|
|
106
|
+
<p align="center">
|
|
107
|
+
<em>Left: default Matplotlib. Right: <code>plotstyle.use("nature")</code>. Same data, same code.</em>
|
|
108
|
+
</p>
|
|
109
|
+
|
|
102
110
|
---
|
|
103
111
|
|
|
104
112
|
## Table of Contents
|
|
@@ -115,6 +123,8 @@ Description-Content-Type: text/markdown
|
|
|
115
123
|
- [CLI](#cli)
|
|
116
124
|
- [Documentation](#documentation)
|
|
117
125
|
- [Contributing](#contributing)
|
|
126
|
+
- [Code of Conduct](#code-of-conduct)
|
|
127
|
+
- [Security](#security)
|
|
118
128
|
- [Citation](#citation)
|
|
119
129
|
- [License](#license)
|
|
120
130
|
|
|
@@ -415,7 +425,7 @@ import plotstyle
|
|
|
415
425
|
|
|
416
426
|
x = np.linspace(0, 2 * np.pi, 100)
|
|
417
427
|
|
|
418
|
-
# Outside plotstyle.use()
|
|
428
|
+
# Outside plotstyle.use(): some checks will fail
|
|
419
429
|
fig, ax = plt.subplots()
|
|
420
430
|
ax.plot(x, np.sin(x), label="sin(x)")
|
|
421
431
|
ax.set_xlabel("Phase (rad)")
|
|
@@ -424,14 +434,14 @@ ax.legend()
|
|
|
424
434
|
|
|
425
435
|
report = plotstyle.validate(fig, journal="nature")
|
|
426
436
|
print(report) # formatted compliance table
|
|
427
|
-
print(report.passed) # False
|
|
437
|
+
print(report.passed) # False, rcParams not configured
|
|
428
438
|
|
|
429
439
|
for failure in report.failures:
|
|
430
440
|
print(failure.message) # what failed
|
|
431
441
|
print(failure.fix_suggestion) # how to fix it
|
|
432
442
|
plt.close(fig)
|
|
433
443
|
|
|
434
|
-
# Inside plotstyle.use()
|
|
444
|
+
# Inside plotstyle.use(): all checks pass
|
|
435
445
|
with plotstyle.use("nature") as style:
|
|
436
446
|
fig, ax = style.figure(columns=1)
|
|
437
447
|
ax.plot(x, np.sin(x), label="sin(x)")
|
|
@@ -660,7 +670,34 @@ Full documentation at **[plotstyle.readthedocs.io](https://plotstyle.readthedocs
|
|
|
660
670
|
- [CLI reference](https://plotstyle.readthedocs.io/en/stable/cli.html)
|
|
661
671
|
- [FAQ](https://plotstyle.readthedocs.io/en/stable/faq.html)
|
|
662
672
|
|
|
663
|
-
Working examples are in the [`examples/`](examples/) directory
|
|
673
|
+
Working examples are in the [`examples/`](https://github.com/rahulkaushal04/plotstyle/tree/main/examples/) directory:
|
|
674
|
+
|
|
675
|
+
| Example | What it covers |
|
|
676
|
+
|---------|----------------|
|
|
677
|
+
| [`01_quickstart.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/01_quickstart.py) | Apply a journal preset, create a figure, and save |
|
|
678
|
+
| [`02_multi_panel_figure.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/02_multi_panel_figure.py) | Multi-panel layouts with automatic panel labels |
|
|
679
|
+
| [`03_color_palettes.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/03_color_palettes.py) | Journal palettes, grayscale-safe markers, `apply_palette` |
|
|
680
|
+
| [`04_accessibility_checks.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/04_accessibility_checks.py) | Colorblind simulation and grayscale print-safety |
|
|
681
|
+
| [`05_validation.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/05_validation.py) | Validate a figure against journal requirements |
|
|
682
|
+
| [`06_export_submission.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/06_export_submission.py) | Export in all required formats for submission |
|
|
683
|
+
| [`07_spec_diff_and_migrate.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/07_spec_diff_and_migrate.py) | Compare journals and migrate a figure between them |
|
|
684
|
+
| [`08_gallery_preview.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/08_gallery_preview.py) | Discover journals and preview their styles |
|
|
685
|
+
| [`09_registry_and_spec.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/09_registry_and_spec.py) | Inspect journal specs from the registry |
|
|
686
|
+
| [`10_context_manager_patterns.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/10_context_manager_patterns.py) | Patterns for managing rcParam lifetime |
|
|
687
|
+
| [`11_seaborn_integration.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/11_seaborn_integration.py) | Keep PlotStyle settings intact with Seaborn |
|
|
688
|
+
| [`12_overlays.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/12_overlays.py) | Overlays: context, color, and plot-type |
|
|
689
|
+
| [`14_print_size_preview.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/14_print_size_preview.py) | Preview a figure at its true physical print size |
|
|
690
|
+
| [`15_matplotlib_native_styles.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/15_matplotlib_native_styles.py) | Use PlotStyle presets with `plt.style` |
|
|
691
|
+
| [`16_latex_and_fonts.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/16_latex_and_fonts.py) | LaTeX modes and font availability checks |
|
|
692
|
+
|
|
693
|
+
Interactive Jupyter notebooks are in [`examples/notebooks/`](https://github.com/rahulkaushal04/plotstyle/tree/main/examples/notebooks/):
|
|
694
|
+
|
|
695
|
+
| Notebook | What it covers |
|
|
696
|
+
|----------|----------------|
|
|
697
|
+
| [`01_quickstart.ipynb`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/notebooks/01_quickstart.ipynb) | Full quickstart: style, figure, palette, validate, save, overlays |
|
|
698
|
+
| [`02_accessibility_and_validation.ipynb`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/notebooks/02_accessibility_and_validation.ipynb) | Colorblind and grayscale previews, validation reports |
|
|
699
|
+
| [`03_journal_comparison_and_migration.ipynb`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/notebooks/03_journal_comparison_and_migration.ipynb) | Diff journals and migrate figures between them |
|
|
700
|
+
| [`04_overlays.ipynb`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/notebooks/04_overlays.ipynb) | Overlays in depth: context, color, plot-type, combining |
|
|
664
701
|
|
|
665
702
|
---
|
|
666
703
|
|
|
@@ -668,21 +705,27 @@ Working examples are in the [`examples/`](examples/) directory.
|
|
|
668
705
|
|
|
669
706
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, adding journal specs, and pull request guidelines.
|
|
670
707
|
|
|
708
|
+
All contributors are expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
709
|
+
|
|
710
|
+
---
|
|
711
|
+
|
|
712
|
+
## Code of Conduct
|
|
713
|
+
|
|
714
|
+
This project follows the [Contributor Covenant](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this standard.
|
|
715
|
+
|
|
716
|
+
---
|
|
717
|
+
|
|
718
|
+
## Security
|
|
719
|
+
|
|
720
|
+
To report a security vulnerability, use [GitHub's private vulnerability reporting](https://github.com/rahulkaushal04/plotstyle/security/advisories/new) rather than opening a public issue. See [SECURITY.md](SECURITY.md) for scope, timeline, and disclosure guidelines.
|
|
721
|
+
|
|
671
722
|
---
|
|
672
723
|
|
|
673
724
|
## Citation
|
|
674
725
|
|
|
675
|
-
If PlotStyle helps your research, a citation or star is appreciated
|
|
726
|
+
If PlotStyle helps your research, a citation or star is appreciated.
|
|
676
727
|
|
|
677
|
-
|
|
678
|
-
@misc{plotstyle,
|
|
679
|
-
author = {Kaushal, Rahul},
|
|
680
|
-
title = {PlotStyle: Publication-ready scientific figure presets for Matplotlib},
|
|
681
|
-
year = {2026},
|
|
682
|
-
url = {https://github.com/rahulkaushal04/plotstyle},
|
|
683
|
-
note = {Version 1.2.2},
|
|
684
|
-
}
|
|
685
|
-
```
|
|
728
|
+
Use the **"Cite this repository"** button on the GitHub sidebar to get a ready-to-use APA or BibTeX entry. It reads from [`CITATION.cff`](CITATION.cff) and is always up to date.
|
|
686
729
|
|
|
687
730
|
---
|
|
688
731
|
|
|
@@ -18,6 +18,14 @@
|
|
|
18
18
|
|
|
19
19
|
**PlotStyle** makes it easy to produce Matplotlib figures that meet the exact typographic, dimensional, and export requirements of major academic journals. It also integrates with Seaborn, with more integrations planned. Pick a journal, create your figure, save it. PlotStyle handles the rest.
|
|
20
20
|
|
|
21
|
+
<p align="center">
|
|
22
|
+
<img src="https://raw.githubusercontent.com/rahulkaushal04/plotstyle/main/examples/output/before_after.png" width="90%" alt="Left: default Matplotlib output. Right: the same figure styled with plotstyle.use('nature').">
|
|
23
|
+
</p>
|
|
24
|
+
|
|
25
|
+
<p align="center">
|
|
26
|
+
<em>Left: default Matplotlib. Right: <code>plotstyle.use("nature")</code>. Same data, same code.</em>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
21
29
|
---
|
|
22
30
|
|
|
23
31
|
## Table of Contents
|
|
@@ -34,6 +42,8 @@
|
|
|
34
42
|
- [CLI](#cli)
|
|
35
43
|
- [Documentation](#documentation)
|
|
36
44
|
- [Contributing](#contributing)
|
|
45
|
+
- [Code of Conduct](#code-of-conduct)
|
|
46
|
+
- [Security](#security)
|
|
37
47
|
- [Citation](#citation)
|
|
38
48
|
- [License](#license)
|
|
39
49
|
|
|
@@ -334,7 +344,7 @@ import plotstyle
|
|
|
334
344
|
|
|
335
345
|
x = np.linspace(0, 2 * np.pi, 100)
|
|
336
346
|
|
|
337
|
-
# Outside plotstyle.use()
|
|
347
|
+
# Outside plotstyle.use(): some checks will fail
|
|
338
348
|
fig, ax = plt.subplots()
|
|
339
349
|
ax.plot(x, np.sin(x), label="sin(x)")
|
|
340
350
|
ax.set_xlabel("Phase (rad)")
|
|
@@ -343,14 +353,14 @@ ax.legend()
|
|
|
343
353
|
|
|
344
354
|
report = plotstyle.validate(fig, journal="nature")
|
|
345
355
|
print(report) # formatted compliance table
|
|
346
|
-
print(report.passed) # False
|
|
356
|
+
print(report.passed) # False, rcParams not configured
|
|
347
357
|
|
|
348
358
|
for failure in report.failures:
|
|
349
359
|
print(failure.message) # what failed
|
|
350
360
|
print(failure.fix_suggestion) # how to fix it
|
|
351
361
|
plt.close(fig)
|
|
352
362
|
|
|
353
|
-
# Inside plotstyle.use()
|
|
363
|
+
# Inside plotstyle.use(): all checks pass
|
|
354
364
|
with plotstyle.use("nature") as style:
|
|
355
365
|
fig, ax = style.figure(columns=1)
|
|
356
366
|
ax.plot(x, np.sin(x), label="sin(x)")
|
|
@@ -579,7 +589,34 @@ Full documentation at **[plotstyle.readthedocs.io](https://plotstyle.readthedocs
|
|
|
579
589
|
- [CLI reference](https://plotstyle.readthedocs.io/en/stable/cli.html)
|
|
580
590
|
- [FAQ](https://plotstyle.readthedocs.io/en/stable/faq.html)
|
|
581
591
|
|
|
582
|
-
Working examples are in the [`examples/`](examples/) directory
|
|
592
|
+
Working examples are in the [`examples/`](https://github.com/rahulkaushal04/plotstyle/tree/main/examples/) directory:
|
|
593
|
+
|
|
594
|
+
| Example | What it covers |
|
|
595
|
+
|---------|----------------|
|
|
596
|
+
| [`01_quickstart.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/01_quickstart.py) | Apply a journal preset, create a figure, and save |
|
|
597
|
+
| [`02_multi_panel_figure.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/02_multi_panel_figure.py) | Multi-panel layouts with automatic panel labels |
|
|
598
|
+
| [`03_color_palettes.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/03_color_palettes.py) | Journal palettes, grayscale-safe markers, `apply_palette` |
|
|
599
|
+
| [`04_accessibility_checks.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/04_accessibility_checks.py) | Colorblind simulation and grayscale print-safety |
|
|
600
|
+
| [`05_validation.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/05_validation.py) | Validate a figure against journal requirements |
|
|
601
|
+
| [`06_export_submission.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/06_export_submission.py) | Export in all required formats for submission |
|
|
602
|
+
| [`07_spec_diff_and_migrate.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/07_spec_diff_and_migrate.py) | Compare journals and migrate a figure between them |
|
|
603
|
+
| [`08_gallery_preview.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/08_gallery_preview.py) | Discover journals and preview their styles |
|
|
604
|
+
| [`09_registry_and_spec.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/09_registry_and_spec.py) | Inspect journal specs from the registry |
|
|
605
|
+
| [`10_context_manager_patterns.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/10_context_manager_patterns.py) | Patterns for managing rcParam lifetime |
|
|
606
|
+
| [`11_seaborn_integration.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/11_seaborn_integration.py) | Keep PlotStyle settings intact with Seaborn |
|
|
607
|
+
| [`12_overlays.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/12_overlays.py) | Overlays: context, color, and plot-type |
|
|
608
|
+
| [`14_print_size_preview.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/14_print_size_preview.py) | Preview a figure at its true physical print size |
|
|
609
|
+
| [`15_matplotlib_native_styles.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/15_matplotlib_native_styles.py) | Use PlotStyle presets with `plt.style` |
|
|
610
|
+
| [`16_latex_and_fonts.py`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/16_latex_and_fonts.py) | LaTeX modes and font availability checks |
|
|
611
|
+
|
|
612
|
+
Interactive Jupyter notebooks are in [`examples/notebooks/`](https://github.com/rahulkaushal04/plotstyle/tree/main/examples/notebooks/):
|
|
613
|
+
|
|
614
|
+
| Notebook | What it covers |
|
|
615
|
+
|----------|----------------|
|
|
616
|
+
| [`01_quickstart.ipynb`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/notebooks/01_quickstart.ipynb) | Full quickstart: style, figure, palette, validate, save, overlays |
|
|
617
|
+
| [`02_accessibility_and_validation.ipynb`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/notebooks/02_accessibility_and_validation.ipynb) | Colorblind and grayscale previews, validation reports |
|
|
618
|
+
| [`03_journal_comparison_and_migration.ipynb`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/notebooks/03_journal_comparison_and_migration.ipynb) | Diff journals and migrate figures between them |
|
|
619
|
+
| [`04_overlays.ipynb`](https://github.com/rahulkaushal04/plotstyle/blob/main/examples/notebooks/04_overlays.ipynb) | Overlays in depth: context, color, plot-type, combining |
|
|
583
620
|
|
|
584
621
|
---
|
|
585
622
|
|
|
@@ -587,21 +624,27 @@ Working examples are in the [`examples/`](examples/) directory.
|
|
|
587
624
|
|
|
588
625
|
See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, adding journal specs, and pull request guidelines.
|
|
589
626
|
|
|
627
|
+
All contributors are expected to follow the [Code of Conduct](CODE_OF_CONDUCT.md).
|
|
628
|
+
|
|
629
|
+
---
|
|
630
|
+
|
|
631
|
+
## Code of Conduct
|
|
632
|
+
|
|
633
|
+
This project follows the [Contributor Covenant](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this standard.
|
|
634
|
+
|
|
635
|
+
---
|
|
636
|
+
|
|
637
|
+
## Security
|
|
638
|
+
|
|
639
|
+
To report a security vulnerability, use [GitHub's private vulnerability reporting](https://github.com/rahulkaushal04/plotstyle/security/advisories/new) rather than opening a public issue. See [SECURITY.md](SECURITY.md) for scope, timeline, and disclosure guidelines.
|
|
640
|
+
|
|
590
641
|
---
|
|
591
642
|
|
|
592
643
|
## Citation
|
|
593
644
|
|
|
594
|
-
If PlotStyle helps your research, a citation or star is appreciated
|
|
645
|
+
If PlotStyle helps your research, a citation or star is appreciated.
|
|
595
646
|
|
|
596
|
-
|
|
597
|
-
@misc{plotstyle,
|
|
598
|
-
author = {Kaushal, Rahul},
|
|
599
|
-
title = {PlotStyle: Publication-ready scientific figure presets for Matplotlib},
|
|
600
|
-
year = {2026},
|
|
601
|
-
url = {https://github.com/rahulkaushal04/plotstyle},
|
|
602
|
-
note = {Version 1.2.2},
|
|
603
|
-
}
|
|
604
|
-
```
|
|
647
|
+
Use the **"Cite this repository"** button on the GitHub sidebar to get a ready-to-use APA or BibTeX entry. It reads from [`CITATION.cff`](CITATION.cff) and is always up to date.
|
|
605
648
|
|
|
606
649
|
---
|
|
607
650
|
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '1.2.
|
|
22
|
-
__version_tuple__ = version_tuple = (1, 2,
|
|
21
|
+
__version__ = version = '1.2.3'
|
|
22
|
+
__version_tuple__ = version_tuple = (1, 2, 3)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|
|
@@ -82,6 +82,8 @@ def _cmd_info(journal: str) -> int:
|
|
|
82
82
|
print("Typography:")
|
|
83
83
|
print(f" Font: {fonts} (fallback: {typo.font_fallback})")
|
|
84
84
|
print(f" Size range: {typo.min_font_pt}-{typo.max_font_pt}pt")
|
|
85
|
+
if typo.target_font_pt is not None:
|
|
86
|
+
print(f" Target size: {typo.target_font_pt}pt")
|
|
85
87
|
print(
|
|
86
88
|
f" Panel labels: {typo.panel_label_pt}pt "
|
|
87
89
|
f"{typo.panel_label_weight} {typo.panel_label_case} "
|
|
@@ -771,6 +771,14 @@ def use(
|
|
|
771
771
|
if journal_key is not None:
|
|
772
772
|
spec = registry.get(journal_key)
|
|
773
773
|
params = build_rcparams(spec, latex=effective_latex)
|
|
774
|
+
|
|
775
|
+
from cycler import cycler as _cycler
|
|
776
|
+
|
|
777
|
+
from plotstyle.color.palettes import JOURNAL_PALETTE_MAP, load_palette
|
|
778
|
+
|
|
779
|
+
_palette_name = JOURNAL_PALETTE_MAP.get(journal_key)
|
|
780
|
+
if _palette_name:
|
|
781
|
+
params["axes.prop_cycle"] = _cycler("color", load_palette(_palette_name))
|
|
774
782
|
else:
|
|
775
783
|
spec = None
|
|
776
784
|
use_latex = _resolve_latex_mode(effective_latex)
|
|
@@ -174,7 +174,13 @@ def build_rcparams(
|
|
|
174
174
|
font_name = spec.typography.font_fallback
|
|
175
175
|
|
|
176
176
|
figsize = _compute_figure_size(spec)
|
|
177
|
-
|
|
177
|
+
# Use the journal's explicit target when available; fall back to the
|
|
178
|
+
# midpoint heuristic for specs that only publish a compliance range.
|
|
179
|
+
font_size = (
|
|
180
|
+
spec.typography.target_font_pt
|
|
181
|
+
if spec.typography.target_font_pt is not None
|
|
182
|
+
else _compute_base_font_size(spec)
|
|
183
|
+
)
|
|
178
184
|
|
|
179
185
|
params: dict[str, Any] = {
|
|
180
186
|
"pdf.fonttype": _FONTTYPE_TRUETYPE,
|
|
@@ -194,12 +200,25 @@ def build_rcparams(
|
|
|
194
200
|
"xtick.labelsize": font_size,
|
|
195
201
|
"ytick.labelsize": font_size,
|
|
196
202
|
"legend.fontsize": font_size,
|
|
197
|
-
# Clamped to physically reproducible minimums; thinner lines vanish in print.
|
|
198
203
|
"lines.linewidth": max(spec.line.min_weight_pt, 1.0),
|
|
199
204
|
"axes.linewidth": max(spec.line.min_weight_pt, 0.5),
|
|
200
|
-
# "none" keeps text editable in SVG; "path" converts to outlines (more portable).
|
|
201
205
|
"svg.fonttype": "none" if spec.export.editable_text else "path",
|
|
202
206
|
"axes.grid": False,
|
|
207
|
+
"legend.frameon": False,
|
|
208
|
+
"xtick.direction": "in",
|
|
209
|
+
"xtick.major.size": 3.0,
|
|
210
|
+
"xtick.major.width": 0.5,
|
|
211
|
+
"xtick.minor.size": 1.5,
|
|
212
|
+
"xtick.minor.width": 0.5,
|
|
213
|
+
"xtick.minor.visible": True,
|
|
214
|
+
"xtick.top": True,
|
|
215
|
+
"ytick.direction": "in",
|
|
216
|
+
"ytick.major.size": 3.0,
|
|
217
|
+
"ytick.major.width": 0.5,
|
|
218
|
+
"ytick.minor.size": 1.5,
|
|
219
|
+
"ytick.minor.width": 0.5,
|
|
220
|
+
"ytick.minor.visible": True,
|
|
221
|
+
"ytick.right": True,
|
|
203
222
|
}
|
|
204
223
|
)
|
|
205
224
|
|
|
@@ -69,7 +69,7 @@ def _draw_line_panel(ax: Axes) -> None:
|
|
|
69
69
|
ax.plot(x, y, label=f"Series {i + 1}")
|
|
70
70
|
ax.set_xlabel("x")
|
|
71
71
|
ax.set_ylabel("y")
|
|
72
|
-
ax.legend(fontsize="small")
|
|
72
|
+
ax.legend(fontsize="small", loc="upper right")
|
|
73
73
|
ax.set_title("Line Plot", fontsize="small")
|
|
74
74
|
|
|
75
75
|
|
|
@@ -81,7 +81,7 @@ def _draw_scatter_panel(ax: Axes) -> None:
|
|
|
81
81
|
ax.scatter(x[mask], y[mask], label=str(group_label), s=15, alpha=0.8)
|
|
82
82
|
ax.set_xlabel("x")
|
|
83
83
|
ax.set_ylabel("y")
|
|
84
|
-
ax.legend(fontsize="small")
|
|
84
|
+
ax.legend(fontsize="small", loc="lower right")
|
|
85
85
|
ax.set_title("Scatter Plot", fontsize="small")
|
|
86
86
|
|
|
87
87
|
|
|
@@ -538,6 +538,12 @@ class TypographySpec:
|
|
|
538
538
|
Font weight for panel labels (e.g. ``"bold"``).
|
|
539
539
|
panel_label_case : str
|
|
540
540
|
Case transformation for panel labels (e.g. ``"lower"``, ``"upper"``).
|
|
541
|
+
target_font_pt : float | None
|
|
542
|
+
Recommended rendering font size in points, when the journal's
|
|
543
|
+
guidelines state a preferred target distinct from the midpoint of
|
|
544
|
+
``[min_font_pt, max_font_pt]``. ``None`` when absent from the TOML,
|
|
545
|
+
in which case ``build_rcparams`` falls back to the midpoint heuristic.
|
|
546
|
+
Must be within ``[min_font_pt, max_font_pt]`` when set.
|
|
541
547
|
"""
|
|
542
548
|
|
|
543
549
|
font_family: list[str]
|
|
@@ -547,6 +553,7 @@ class TypographySpec:
|
|
|
547
553
|
panel_label_pt: float
|
|
548
554
|
panel_label_weight: str
|
|
549
555
|
panel_label_case: str
|
|
556
|
+
target_font_pt: float | None = None
|
|
550
557
|
|
|
551
558
|
|
|
552
559
|
@dataclass(frozen=True, slots=True)
|
|
@@ -872,6 +879,24 @@ class JournalSpec:
|
|
|
872
879
|
f"must be ≥ min_font_pt ({min_pt}), got {max_pt}",
|
|
873
880
|
)
|
|
874
881
|
|
|
882
|
+
# target_font_pt is optional. When present it must be a non-negative
|
|
883
|
+
# float within the journal's compliance range [min_pt, max_pt].
|
|
884
|
+
target_pt: float | None = None
|
|
885
|
+
if "target_font_pt" in raw:
|
|
886
|
+
raw_target = raw["target_font_pt"]
|
|
887
|
+
try:
|
|
888
|
+
target_pt = float(raw_target)
|
|
889
|
+
except (TypeError, ValueError):
|
|
890
|
+
raise FieldTypeError(t, "target_font_pt", "float", raw_target) from None
|
|
891
|
+
if target_pt < 0.0:
|
|
892
|
+
raise FieldValueError(t, "target_font_pt", f"must be ≥ 0, got {target_pt}")
|
|
893
|
+
if not (min_pt <= target_pt <= max_pt):
|
|
894
|
+
raise FieldValueError(
|
|
895
|
+
t,
|
|
896
|
+
"target_font_pt",
|
|
897
|
+
f"must be within [min_font_pt={min_pt}, max_font_pt={max_pt}], got {target_pt}",
|
|
898
|
+
)
|
|
899
|
+
|
|
875
900
|
return TypographySpec(
|
|
876
901
|
font_family=_cast_str_list(
|
|
877
902
|
raw,
|
|
@@ -890,6 +915,7 @@ class JournalSpec:
|
|
|
890
915
|
panel_label_case=_cast_str(
|
|
891
916
|
raw, t, "panel_label_case", default="lower", allowed=_KNOWN_LABEL_CASES
|
|
892
917
|
),
|
|
918
|
+
target_font_pt=target_pt,
|
|
893
919
|
)
|
|
894
920
|
|
|
895
921
|
@staticmethod
|
|
@@ -740,6 +740,113 @@ class TestJournalStyleRestore:
|
|
|
740
740
|
# ---------------------------------------------------------------------------
|
|
741
741
|
|
|
742
742
|
|
|
743
|
+
# ===========================================================================
|
|
744
|
+
# use(): journal color cycle
|
|
745
|
+
# ===========================================================================
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
class TestUseColorCycle:
|
|
749
|
+
"""Verify that use() applies the journal-recommended default color cycle."""
|
|
750
|
+
|
|
751
|
+
@pytest.mark.filterwarnings("ignore::plotstyle._utils.warnings.SpecAssumptionWarning")
|
|
752
|
+
@pytest.mark.filterwarnings("ignore::plotstyle._utils.warnings.FontFallbackWarning")
|
|
753
|
+
def test_nature_gets_okabe_ito_palette(self) -> None:
|
|
754
|
+
"""
|
|
755
|
+
Description: use('nature') must apply okabe_ito as the default color
|
|
756
|
+
cycle. The JOURNAL_PALETTE_MAP maps 'nature' to okabe_ito.
|
|
757
|
+
Scenario: Call use('nature') and inspect axes.prop_cycle.
|
|
758
|
+
Expectation: The cycle colors match the okabe_ito palette.
|
|
759
|
+
"""
|
|
760
|
+
from plotstyle.color.palettes import JOURNAL_PALETTE_MAP, load_palette
|
|
761
|
+
|
|
762
|
+
expected = load_palette(JOURNAL_PALETTE_MAP["nature"])
|
|
763
|
+
style = use("nature")
|
|
764
|
+
try:
|
|
765
|
+
actual = [item["color"] for item in mpl.rcParams["axes.prop_cycle"]]
|
|
766
|
+
assert actual == expected
|
|
767
|
+
finally:
|
|
768
|
+
style.restore()
|
|
769
|
+
|
|
770
|
+
@pytest.mark.filterwarnings("ignore::plotstyle._utils.warnings.SpecAssumptionWarning")
|
|
771
|
+
@pytest.mark.filterwarnings("ignore::plotstyle._utils.warnings.FontFallbackWarning")
|
|
772
|
+
def test_ieee_gets_safe_grayscale_palette(self) -> None:
|
|
773
|
+
"""
|
|
774
|
+
Description: use('ieee') must apply safe_grayscale by default. IEEE
|
|
775
|
+
requires colorblind-safe and grayscale-compatible figures;
|
|
776
|
+
the matplotlib default blue-orange-green cycle would fail.
|
|
777
|
+
Scenario: Call use('ieee') and inspect axes.prop_cycle.
|
|
778
|
+
Expectation: The cycle colors match the safe_grayscale palette.
|
|
779
|
+
"""
|
|
780
|
+
from plotstyle.color.palettes import JOURNAL_PALETTE_MAP, load_palette
|
|
781
|
+
|
|
782
|
+
expected = load_palette(JOURNAL_PALETTE_MAP["ieee"])
|
|
783
|
+
style = use("ieee")
|
|
784
|
+
try:
|
|
785
|
+
actual = [item["color"] for item in mpl.rcParams["axes.prop_cycle"]]
|
|
786
|
+
assert actual == expected
|
|
787
|
+
finally:
|
|
788
|
+
style.restore()
|
|
789
|
+
|
|
790
|
+
@pytest.mark.filterwarnings("ignore::plotstyle._utils.warnings.SpecAssumptionWarning")
|
|
791
|
+
@pytest.mark.filterwarnings("ignore::plotstyle._utils.warnings.FontFallbackWarning")
|
|
792
|
+
def test_color_overlay_overrides_default_palette(self) -> None:
|
|
793
|
+
"""
|
|
794
|
+
Description: An explicit color overlay applied after use() must win
|
|
795
|
+
over the journal's default palette. Overlay precedence
|
|
796
|
+
must be preserved.
|
|
797
|
+
Scenario: use(['nature', 'tol-bright']) - tol-bright colors differ
|
|
798
|
+
from nature's default okabe-ito.
|
|
799
|
+
Expectation: The cycle reflects tol-bright, not okabe-ito.
|
|
800
|
+
"""
|
|
801
|
+
from plotstyle.color.palettes import load_palette
|
|
802
|
+
|
|
803
|
+
tol_bright = load_palette("tol_bright")
|
|
804
|
+
with use(["nature", "tol-bright"]) as _style:
|
|
805
|
+
actual = [item["color"] for item in mpl.rcParams["axes.prop_cycle"]]
|
|
806
|
+
assert actual == tol_bright
|
|
807
|
+
|
|
808
|
+
@pytest.mark.filterwarnings("ignore::plotstyle._utils.warnings.FontFallbackWarning")
|
|
809
|
+
def test_overlay_only_mode_does_not_apply_palette(self) -> None:
|
|
810
|
+
"""
|
|
811
|
+
Description: When use() is called with overlays only (no journal key),
|
|
812
|
+
no palette is applied from JOURNAL_PALETTE_MAP.
|
|
813
|
+
Scenario: use(['notebook']) - no journal key.
|
|
814
|
+
Expectation: axes.prop_cycle is unchanged from before the call.
|
|
815
|
+
"""
|
|
816
|
+
before = list(mpl.rcParams["axes.prop_cycle"])
|
|
817
|
+
with use(["notebook"]):
|
|
818
|
+
after = list(mpl.rcParams["axes.prop_cycle"])
|
|
819
|
+
assert after == before
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
# ===========================================================================
|
|
823
|
+
# use(): font size target
|
|
824
|
+
# ===========================================================================
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
class TestUseFontSizeTarget:
|
|
828
|
+
"""Verify that use('nature') applies 7 pt (target) not 6 pt (midpoint)."""
|
|
829
|
+
|
|
830
|
+
@pytest.mark.filterwarnings("ignore::plotstyle._utils.warnings.FontFallbackWarning")
|
|
831
|
+
def test_nature_font_size_is_7pt(self) -> None:
|
|
832
|
+
"""
|
|
833
|
+
Description: Nature's TOML sets target_font_pt=7.0. build_rcparams
|
|
834
|
+
must use 7 pt, not the 6 pt midpoint of the 5-7 pt range.
|
|
835
|
+
Scenario: use('nature') and read font.size.
|
|
836
|
+
Expectation: mpl.rcParams['font.size'] == 7.0.
|
|
837
|
+
"""
|
|
838
|
+
style = use("nature")
|
|
839
|
+
try:
|
|
840
|
+
assert mpl.rcParams["font.size"] == pytest.approx(7.0)
|
|
841
|
+
finally:
|
|
842
|
+
style.restore()
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
# ===========================================================================
|
|
846
|
+
# Public API
|
|
847
|
+
# ===========================================================================
|
|
848
|
+
|
|
849
|
+
|
|
743
850
|
class TestPublicAPI:
|
|
744
851
|
"""Validate the module's public API surface."""
|
|
745
852
|
|