plotstyle 1.0.0__tar.gz → 1.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. {plotstyle-1.0.0 → plotstyle-1.1.0}/.gitignore +3 -0
  2. {plotstyle-1.0.0 → plotstyle-1.1.0}/CHANGELOG.md +25 -1
  3. plotstyle-1.1.0/PKG-INFO +367 -0
  4. plotstyle-1.1.0/README.md +306 -0
  5. plotstyle-1.1.0/src/plotstyle/__init__.py +53 -0
  6. plotstyle-1.1.0/src/plotstyle/_utils/io.py +49 -0
  7. plotstyle-1.1.0/src/plotstyle/_utils/warnings.py +13 -0
  8. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/_version.py +2 -2
  9. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/cli/main.py +42 -223
  10. plotstyle-1.1.0/src/plotstyle/color/__init__.py +11 -0
  11. plotstyle-1.1.0/src/plotstyle/color/_rendering.py +39 -0
  12. plotstyle-1.1.0/src/plotstyle/color/accessibility.py +198 -0
  13. plotstyle-1.1.0/src/plotstyle/color/grayscale.py +158 -0
  14. plotstyle-1.1.0/src/plotstyle/color/palettes.py +168 -0
  15. plotstyle-1.1.0/src/plotstyle/core/export.py +362 -0
  16. plotstyle-1.1.0/src/plotstyle/core/figure.py +394 -0
  17. plotstyle-1.1.0/src/plotstyle/core/migrate.py +408 -0
  18. plotstyle-1.1.0/src/plotstyle/core/style.py +580 -0
  19. plotstyle-1.1.0/src/plotstyle/engine/fonts.py +166 -0
  20. plotstyle-1.1.0/src/plotstyle/engine/latex.py +154 -0
  21. plotstyle-1.1.0/src/plotstyle/engine/rcparams.py +180 -0
  22. plotstyle-1.1.0/src/plotstyle/integrations/seaborn.py +115 -0
  23. plotstyle-1.1.0/src/plotstyle/preview/__init__.py +11 -0
  24. plotstyle-1.1.0/src/plotstyle/preview/gallery.py +173 -0
  25. plotstyle-1.1.0/src/plotstyle/preview/print_size.py +135 -0
  26. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/__init__.py +62 -79
  27. plotstyle-1.1.0/src/plotstyle/specs/schema.py +906 -0
  28. plotstyle-1.1.0/src/plotstyle/specs/units.py +445 -0
  29. plotstyle-1.1.0/src/plotstyle/validation/__init__.py +48 -0
  30. plotstyle-1.1.0/src/plotstyle/validation/checks/__init__.py +48 -0
  31. plotstyle-1.1.0/src/plotstyle/validation/checks/_base.py +50 -0
  32. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/validation/checks/colors.py +48 -150
  33. plotstyle-1.1.0/src/plotstyle/validation/checks/dimensions.py +107 -0
  34. plotstyle-1.1.0/src/plotstyle/validation/checks/export.py +145 -0
  35. plotstyle-1.1.0/src/plotstyle/validation/checks/lines.py +88 -0
  36. plotstyle-1.1.0/src/plotstyle/validation/checks/typography.py +125 -0
  37. plotstyle-1.1.0/src/plotstyle/validation/report.py +162 -0
  38. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_color/test_palettes.py +18 -17
  39. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_core/test_migrate.py +0 -12
  40. plotstyle-1.0.0/PKG-INFO +0 -395
  41. plotstyle-1.0.0/README.md +0 -334
  42. plotstyle-1.0.0/src/plotstyle/__init__.py +0 -120
  43. plotstyle-1.0.0/src/plotstyle/_utils/io.py +0 -113
  44. plotstyle-1.0.0/src/plotstyle/_utils/warnings.py +0 -86
  45. plotstyle-1.0.0/src/plotstyle/color/__init__.py +0 -42
  46. plotstyle-1.0.0/src/plotstyle/color/_rendering.py +0 -86
  47. plotstyle-1.0.0/src/plotstyle/color/accessibility.py +0 -288
  48. plotstyle-1.0.0/src/plotstyle/color/grayscale.py +0 -285
  49. plotstyle-1.0.0/src/plotstyle/color/palettes.py +0 -259
  50. plotstyle-1.0.0/src/plotstyle/core/export.py +0 -416
  51. plotstyle-1.0.0/src/plotstyle/core/figure.py +0 -402
  52. plotstyle-1.0.0/src/plotstyle/core/migrate.py +0 -586
  53. plotstyle-1.0.0/src/plotstyle/core/style.py +0 -393
  54. plotstyle-1.0.0/src/plotstyle/engine/fonts.py +0 -309
  55. plotstyle-1.0.0/src/plotstyle/engine/latex.py +0 -287
  56. plotstyle-1.0.0/src/plotstyle/engine/rcparams.py +0 -352
  57. plotstyle-1.0.0/src/plotstyle/integrations/seaborn.py +0 -305
  58. plotstyle-1.0.0/src/plotstyle/preview/__init__.py +0 -50
  59. plotstyle-1.0.0/src/plotstyle/preview/gallery.py +0 -337
  60. plotstyle-1.0.0/src/plotstyle/preview/print_size.py +0 -304
  61. plotstyle-1.0.0/src/plotstyle/specs/schema.py +0 -1098
  62. plotstyle-1.0.0/src/plotstyle/specs/units.py +0 -761
  63. plotstyle-1.0.0/src/plotstyle/validation/__init__.py +0 -96
  64. plotstyle-1.0.0/src/plotstyle/validation/checks/__init__.py +0 -95
  65. plotstyle-1.0.0/src/plotstyle/validation/checks/_base.py +0 -149
  66. plotstyle-1.0.0/src/plotstyle/validation/checks/dimensions.py +0 -166
  67. plotstyle-1.0.0/src/plotstyle/validation/checks/export.py +0 -222
  68. plotstyle-1.0.0/src/plotstyle/validation/checks/lines.py +0 -147
  69. plotstyle-1.0.0/src/plotstyle/validation/checks/typography.py +0 -200
  70. plotstyle-1.0.0/src/plotstyle/validation/report.py +0 -300
  71. {plotstyle-1.0.0 → plotstyle-1.1.0}/LICENSE +0 -0
  72. {plotstyle-1.0.0 → plotstyle-1.1.0}/pyproject.toml +0 -0
  73. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/_utils/__init__.py +0 -0
  74. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/cli/__init__.py +0 -0
  75. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/color/data/okabe_ito.json +0 -0
  76. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/color/data/safe_grayscale.json +0 -0
  77. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/color/data/tol_bright.json +0 -0
  78. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/color/data/tol_muted.json +0 -0
  79. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/color/data/tol_vibrant.json +0 -0
  80. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/core/__init__.py +0 -0
  81. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/engine/__init__.py +0 -0
  82. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/integrations/__init__.py +0 -0
  83. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/py.typed +0 -0
  84. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/_templates.toml +0 -0
  85. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/acs.toml +0 -0
  86. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/cell.toml +0 -0
  87. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/elsevier.toml +0 -0
  88. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/ieee.toml +0 -0
  89. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/nature.toml +0 -0
  90. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/plos.toml +0 -0
  91. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/prl.toml +0 -0
  92. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/science.toml +0 -0
  93. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/springer.toml +0 -0
  94. {plotstyle-1.0.0 → plotstyle-1.1.0}/src/plotstyle/specs/wiley.toml +0 -0
  95. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/conftest.py +0 -0
  96. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_cli/test_main.py +0 -0
  97. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_color/test_accessibility.py +0 -0
  98. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_color/test_grayscale.py +0 -0
  99. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_color/test_rendering.py +0 -0
  100. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_core/test_export.py +0 -0
  101. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_core/test_figure.py +0 -0
  102. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_core/test_style.py +0 -0
  103. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_engine/test_fonts.py +0 -0
  104. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_engine/test_latex.py +0 -0
  105. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_engine/test_rcparams.py +0 -0
  106. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_integrations/test_seaborn.py +0 -0
  107. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_preview/test_gallery.py +0 -0
  108. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_preview/test_print_size.py +0 -0
  109. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_specs/test_registry.py +0 -0
  110. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_specs/test_schema.py +0 -0
  111. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_specs/test_units.py +0 -0
  112. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_utils/test_io.py +0 -0
  113. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_utils/test_warnings.py +0 -0
  114. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_validation/test_checks.py +0 -0
  115. {plotstyle-1.0.0 → plotstyle-1.1.0}/tests/test_validation/test_report.py +0 -0
@@ -157,3 +157,6 @@ celerybeat-schedule
157
157
 
158
158
  # secrets (just in case)
159
159
  secrets.json
160
+
161
+ # local files
162
+ local/
@@ -13,6 +13,29 @@ _Nothing yet._
13
13
 
14
14
  ---
15
15
 
16
+ ## [1.1.0] - 2026-04-16
17
+
18
+ Minor feature release : ergonomics improvements, hardened error handling, and spec updates.
19
+
20
+ ### Added
21
+
22
+ - **`quiet` parameter on `JournalStyle.export()`** : suppresses compliance summaries and manifest output for scripting workflows.
23
+ - **Pre-computed Type 3 font checks** : compliance summary now accepts a pre-computed result for Type 3 font detection, improving performance when the check has already been run by the caller.
24
+ - **`JournalSpec` key access** : `JournalSpec` now supports key-style access, and the dimension check message has been updated for clarity.
25
+
26
+ ### Fixed
27
+
28
+ - **`SpecNotFoundError` base classes** : now inherits from both `ValueError` and `KeyError` so existing `except ValueError` and `except KeyError` handlers catch it correctly; a custom `__str__` produces clearer diagnostic messages.
29
+
30
+ ### Changed
31
+
32
+ - **IEEE Transactions spec updated** : column widths, max height, font family, panel-label properties, and preferred output formats revised to match current IEEE author guidelines.
33
+ - **CI documentation build** : Sphinx `docs` job (`sphinx-build -W -n`) added to the CI workflow; rendered HTML is uploaded as an artifact on every push.
34
+ - **Module docstrings** : expanded and standardised across `__init__.py`, `_utils/`, `color/`, `core/`, and `validation/` for consistent Sphinx rendering.
35
+ - **Context-manager examples** : all `plotstyle.use()` call sites in docs and examples updated to the `with plotstyle.use(...) as style:` form to ensure correct `rcParams` restoration.
36
+
37
+ ---
38
+
16
39
  ## [1.0.0] - 2026-04-12
17
40
 
18
41
  First stable release — production-ready for scientific publication workflows.
@@ -72,7 +95,8 @@ First public alpha release.
72
95
  - **Dynamic versioning** — version derived from git tags via `hatch-vcs` and `importlib.metadata`.
73
96
  - **CI/CD pipeline** — GitHub Actions workflows for lint, type-check, test matrix, and automated PyPI release via OIDC Trusted Publishing.
74
97
 
75
- [Unreleased]: https://github.com/rahulkaushal04/plotstyle/compare/v1.0.0...HEAD
98
+ [Unreleased]: https://github.com/rahulkaushal04/plotstyle/compare/v1.1.0...HEAD
99
+ [1.1.0]: https://github.com/rahulkaushal04/plotstyle/compare/v1.0.0...v1.1.0
76
100
  [1.0.0]: https://github.com/rahulkaushal04/plotstyle/compare/v0.1.0a2...v1.0.0
77
101
  [0.1.0a2]: https://github.com/rahulkaushal04/plotstyle/compare/v0.1.0a1...v0.1.0a2
78
102
  [0.1.0a1]: https://github.com/rahulkaushal04/plotstyle/releases/tag/v0.1.0a1
@@ -0,0 +1,367 @@
1
+ Metadata-Version: 2.4
2
+ Name: plotstyle
3
+ Version: 1.1.0
4
+ Summary: Matplotlib/seaborn style presets matching scientific journal requirements, with validation, export safety, and preview capabilities.
5
+ Project-URL: Homepage, https://github.com/rahulkaushal04/plotstyle
6
+ Project-URL: Documentation, https://plotstyle.readthedocs.io
7
+ Project-URL: Repository, https://github.com/rahulkaushal04/plotstyle
8
+ Project-URL: Issues, https://github.com/rahulkaushal04/plotstyle/issues
9
+ Project-URL: Changelog, https://github.com/rahulkaushal04/plotstyle/blob/main/CHANGELOG.md
10
+ Project-URL: Download, https://pypi.org/project/plotstyle/
11
+ Author: Rahul Kaushal
12
+ License: MIT
13
+ License-File: LICENSE
14
+ Keywords: academic,accessibility,colorblind,export,figures,ieee,journal,matplotlib,nature,plotting,publication,rcParams,research,science,scientific,seaborn,style,typesetting,validation,visualization
15
+ Classifier: Development Status :: 5 - Production/Stable
16
+ Classifier: Framework :: Matplotlib
17
+ Classifier: Intended Audience :: Education
18
+ Classifier: Intended Audience :: Science/Research
19
+ Classifier: License :: OSI Approved :: MIT License
20
+ Classifier: Natural Language :: English
21
+ Classifier: Operating System :: OS Independent
22
+ Classifier: Programming Language :: Python :: 3
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Programming Language :: Python :: 3.13
27
+ Classifier: Topic :: Multimedia :: Graphics
28
+ Classifier: Topic :: Scientific/Engineering
29
+ Classifier: Topic :: Scientific/Engineering :: Visualization
30
+ Classifier: Typing :: Typed
31
+ Requires-Python: >=3.10
32
+ Requires-Dist: matplotlib<4,>=3.9
33
+ Requires-Dist: tomli>=2.0; python_version < '3.11'
34
+ Provides-Extra: all
35
+ Requires-Dist: fonttools<5,>=4.55; extra == 'all'
36
+ Requires-Dist: pandas<3,>=2.2; extra == 'all'
37
+ Requires-Dist: pillow<13,>=11.0; extra == 'all'
38
+ Requires-Dist: seaborn<1,>=0.13.2; extra == 'all'
39
+ Provides-Extra: color
40
+ Requires-Dist: pillow<13,>=11.0; extra == 'color'
41
+ Provides-Extra: dev
42
+ Requires-Dist: mypy<2,>=1.15; extra == 'dev'
43
+ Requires-Dist: pillow<13,>=11.0; extra == 'dev'
44
+ Requires-Dist: pre-commit<5,>=4.0; extra == 'dev'
45
+ Requires-Dist: pytest-cov<8,>=6.0; extra == 'dev'
46
+ Requires-Dist: pytest-mpl<1,>=0.18; extra == 'dev'
47
+ Requires-Dist: pytest<10,>=8.3; extra == 'dev'
48
+ Requires-Dist: ruff<1,>=0.15; extra == 'dev'
49
+ Provides-Extra: docs
50
+ Requires-Dist: furo>=2025.12.19; extra == 'docs'
51
+ Requires-Dist: myst-parser<6,>=5.0; extra == 'docs'
52
+ Requires-Dist: sphinx-autodoc-typehints<4,>=3.0; extra == 'docs'
53
+ Requires-Dist: sphinx-copybutton<1,>=0.5; extra == 'docs'
54
+ Requires-Dist: sphinx<10,>=9.0; extra == 'docs'
55
+ Provides-Extra: fonttools
56
+ Requires-Dist: fonttools<5,>=4.55; extra == 'fonttools'
57
+ Provides-Extra: seaborn
58
+ Requires-Dist: pandas<3,>=2.2; extra == 'seaborn'
59
+ Requires-Dist: seaborn<1,>=0.13.2; extra == 'seaborn'
60
+ Description-Content-Type: text/markdown
61
+
62
+ <p align="center">
63
+ <strong>plotstyle</strong>
64
+ </p>
65
+
66
+ <p align="center">
67
+ <em>Matplotlib figures formatted for journal submission, automatically.</em>
68
+ </p>
69
+
70
+ <p align="center">
71
+ <a href="https://pypi.org/project/plotstyle/"><img alt="PyPI version" src="https://img.shields.io/pypi/v/plotstyle?color=blue"></a>
72
+ <a href="https://pypi.org/project/plotstyle/"><img alt="Python versions" src="https://img.shields.io/pypi/pyversions/plotstyle"></a>
73
+ <a href="https://github.com/rahulkaushal04/plotstyle/blob/main/LICENSE"><img alt="License: MIT" src="https://img.shields.io/github/license/rahulkaushal04/plotstyle"></a>
74
+ <a href="https://github.com/rahulkaushal04/plotstyle/actions"><img alt="CI" src="https://img.shields.io/github/actions/workflow/status/rahulkaushal04/plotstyle/ci.yml?label=CI"></a>
75
+ <a href="https://plotstyle.readthedocs.io/en/stable/"><img alt="Docs" src="https://img.shields.io/readthedocs/plotstyle/stable?label=docs"></a>
76
+ </p>
77
+
78
+ ---
79
+
80
+ **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.
81
+
82
+ ---
83
+
84
+ ## Table of Contents
85
+
86
+ - [Installation](#installation)
87
+ - [Quick Start](#quick-start)
88
+ - [Examples](#examples)
89
+ - [Multi-panel figures](#multi-panel-figures)
90
+ - [Color palettes](#color-palettes)
91
+ - [Colorblind and grayscale previews](#colorblind-and-grayscale-previews)
92
+ - [Validation and submission export](#validation-and-submission-export)
93
+ - [Supported Journals](#supported-journals)
94
+ - [CLI](#cli)
95
+ - [Documentation](#documentation)
96
+ - [Contributing](#contributing)
97
+ - [Citation](#citation)
98
+ - [License](#license)
99
+
100
+ ---
101
+
102
+ ## Installation
103
+
104
+ Requires **Python 3.10+** and **Matplotlib >= 3.9**.
105
+
106
+ ```bash
107
+ pip install plotstyle
108
+ ```
109
+
110
+ Optional extras:
111
+
112
+ ```bash
113
+ pip install "plotstyle[color]" # colorblind / grayscale previews
114
+ pip install "plotstyle[seaborn]" # seaborn integration
115
+ pip install "plotstyle[all]" # everything
116
+ ```
117
+
118
+ ---
119
+
120
+ ## Quick Start
121
+
122
+ ```python
123
+ import numpy as np
124
+ import plotstyle
125
+
126
+ with plotstyle.use("nature") as style:
127
+ fig, ax = style.figure(columns=1) # sized to Nature's single-column width (89 mm)
128
+
129
+ x = np.linspace(0, 2 * np.pi, 200)
130
+ ax.plot(x, np.sin(x), label="sin(x)")
131
+ ax.plot(x, np.cos(x), label="cos(x)")
132
+ ax.set_xlabel("Phase (rad)")
133
+ ax.set_ylabel("Amplitude (a.u.)")
134
+ ax.legend()
135
+
136
+ style.savefig(fig, "figure.pdf") # 300 DPI minimum, TrueType fonts embedded
137
+ ```
138
+
139
+ <p align="center">
140
+ <img src="examples/output/quickstart_nature.png" width="55%" alt="Quickstart output: sin and cos figure styled for Nature">
141
+ </p>
142
+
143
+ The `with` block is the recommended pattern. Matplotlib's `rcParams` are restored automatically when it exits, even if an exception occurs.
144
+
145
+ ---
146
+
147
+ ## Examples
148
+
149
+ ### Multi-panel figures
150
+
151
+ `style.subplots()` works like `plt.subplots()` but sizes the figure to the journal spec and adds panel labels automatically, styled to each journal's convention (**A**, **B**, **C** for Science; **a**, **b**, **c** for Nature; **(a)**, **(b)**, **(c)** for IEEE).
152
+
153
+ ```python
154
+ import numpy as np
155
+ import plotstyle
156
+
157
+ rng = np.random.default_rng(42)
158
+
159
+ with plotstyle.use("science") as style:
160
+ fig, axes = style.subplots(nrows=2, ncols=2, columns=2)
161
+
162
+ x = np.linspace(0, 10, 100)
163
+ axes[0, 0].plot(x, np.sin(x), label="sin")
164
+ axes[0, 0].plot(x, np.cos(x), label="cos")
165
+ axes[0, 0].set_xlabel("x")
166
+ axes[0, 0].set_ylabel("f(x)")
167
+ axes[0, 0].legend()
168
+
169
+ xs = rng.normal(0, 1, 60)
170
+ ys = 0.7 * xs + rng.normal(0, 0.3, 60)
171
+ axes[0, 1].scatter(xs, ys, s=12, alpha=0.7)
172
+ axes[0, 1].set_xlabel("Variable X")
173
+ axes[0, 1].set_ylabel("Variable Y")
174
+
175
+ axes[1, 0].bar(["A", "B", "C", "D"], [3.2, 5.8, 4.1, 6.5])
176
+ axes[1, 0].set_xlabel("Category")
177
+ axes[1, 0].set_ylabel("Count")
178
+
179
+ axes[1, 1].hist(rng.normal(0, 1, 500), bins=25, edgecolor="white", linewidth=0.5)
180
+ axes[1, 1].set_xlabel("Value")
181
+ axes[1, 1].set_ylabel("Frequency")
182
+
183
+ style.savefig(fig, "multi_panel.pdf")
184
+ ```
185
+
186
+ <p align="center">
187
+ <img src="examples/output/multi_panel_science.png" width="70%" alt="2x2 multi-panel Science figure with automatic panel labels A B C D">
188
+ </p>
189
+
190
+ > `axes` is always a 2-D NumPy array. Use `axes[0, 0]` to access a single panel or `axes.flat` to iterate. Pass `panels=False` to suppress the automatic labels.
191
+
192
+ ---
193
+
194
+ ### Color palettes
195
+
196
+ Each journal has a recommended colorblind-safe palette. `plotstyle.palette()` returns hex color strings, cycling if you need more than the palette length.
197
+
198
+ ```python
199
+ import matplotlib.pyplot as plt
200
+ import plotstyle
201
+
202
+ journals = ["nature", "science", "ieee", "acs"]
203
+ fig, axes = plt.subplots(len(journals), 1, figsize=(6, 0.6 * len(journals)))
204
+
205
+ for ax, journal in zip(axes, journals):
206
+ pal = plotstyle.palette(journal, n=8)
207
+ for i, color in enumerate(pal):
208
+ ax.barh(0, 1, left=i, color=color, edgecolor="none", height=0.8)
209
+ ax.set_xlim(0, 8)
210
+ ax.set_yticks([])
211
+ ax.set_ylabel(journal, rotation=0, ha="right", va="center")
212
+ ax.set_xticks([])
213
+
214
+ fig.suptitle("Journal Color Palettes")
215
+ fig.tight_layout()
216
+ fig.savefig("palette_comparison.png", dpi=150)
217
+ ```
218
+
219
+ <p align="center">
220
+ <img src="examples/output/palette_comparison.png" width="70%" alt="Color swatch comparison for Nature, Science, IEEE, and ACS palettes">
221
+ </p>
222
+
223
+ Pass `with_markers=True` to get `(color, linestyle, marker)` tuples, useful for journals like IEEE that print in grayscale:
224
+
225
+ ```python
226
+ styled = plotstyle.palette("ieee", n=4, with_markers=True)
227
+ for color, ls, marker in styled:
228
+ ax.plot(x, y, color=color, linestyle=ls, marker=marker)
229
+ ```
230
+
231
+ ---
232
+
233
+ ### Colorblind and grayscale previews
234
+
235
+ Build a figure, then simulate how it looks under color vision deficiency or grayscale printing before you submit.
236
+
237
+ ```python
238
+ import numpy as np
239
+ import plotstyle
240
+
241
+ with plotstyle.use("nature") as style:
242
+ colors = style.palette(n=4)
243
+ fig, ax = style.figure(columns=1)
244
+ x = np.linspace(0, 5, 80)
245
+ for i, c in enumerate(colors):
246
+ ax.plot(x, np.sin(x + i), color=c, linewidth=1.5, label=f"Series {i + 1}")
247
+ ax.set_xlabel("Time (s)")
248
+ ax.set_ylabel("Signal")
249
+ ax.legend()
250
+
251
+ cvd_fig = plotstyle.preview_colorblind(fig)
252
+ cvd_fig.savefig("accessibility_colorblind.png", dpi=150, bbox_inches="tight")
253
+ ```
254
+
255
+ <p align="center">
256
+ <img src="examples/output/accessibility_colorblind.png" width="90%" alt="Colorblind simulation: original, deuteranopia, protanopia, tritanopia">
257
+ </p>
258
+
259
+ ```python
260
+ gray_fig = plotstyle.preview_grayscale(fig)
261
+ gray_fig.savefig("accessibility_grayscale.png", dpi=150, bbox_inches="tight")
262
+ ```
263
+
264
+ <p align="center">
265
+ <img src="examples/output/accessibility_grayscale.png" width="60%" alt="Grayscale simulation: original vs grayscale rendering">
266
+ </p>
267
+
268
+ ---
269
+
270
+ ### Validation and submission export
271
+
272
+ Validate a figure against the journal's requirements, then export in all required formats at once.
273
+
274
+ ```python
275
+ report = plotstyle.validate(fig, journal="nature")
276
+ print(report) # formatted compliance table
277
+ print(report.passed) # True if everything is OK
278
+
279
+ for failure in report.failures:
280
+ print(failure.message) # what failed
281
+ print(failure.fix_suggestion) # how to fix it
282
+ ```
283
+
284
+ ```python
285
+ paths = plotstyle.export_submission(
286
+ fig,
287
+ "figure1",
288
+ journal="ieee",
289
+ author_surname="Smith", # IEEE prepends the surname prefix to filenames
290
+ output_dir="submission/",
291
+ )
292
+ # Produces: submission/smith_figure1.pdf (and any other IEEE-required formats)
293
+ ```
294
+
295
+ ---
296
+
297
+ ## Supported Journals
298
+
299
+ | Key | Journal | Publisher |
300
+ |-----|---------|-----------|
301
+ | `acs` | ACS (JACS) | American Chemical Society |
302
+ | `cell` | Cell | Cell Press |
303
+ | `elsevier` | Elsevier | Elsevier |
304
+ | `ieee` | IEEE Transactions | IEEE |
305
+ | `nature` | Nature | Springer Nature |
306
+ | `plos` | PLOS ONE | Public Library of Science |
307
+ | `prl` | Physical Review Letters | American Physical Society |
308
+ | `science` | Science | AAAS |
309
+ | `springer` | Springer | Springer |
310
+ | `wiley` | Wiley | Wiley |
311
+
312
+ > Need another journal? See [CONTRIBUTING.md](CONTRIBUTING.md).
313
+
314
+ ---
315
+
316
+ ## CLI
317
+
318
+ ```
319
+ plotstyle list # list all journal presets
320
+ plotstyle info <journal> # show spec details
321
+ plotstyle diff <journal_a> <journal_b> # compare two journals
322
+ plotstyle fonts --journal <journal> # check font availability
323
+ plotstyle validate <file> --journal <journal> # validate a saved figure
324
+ plotstyle export <file> --journal <journal> # print snippet for re-exporting
325
+ ```
326
+
327
+ ---
328
+
329
+ ## Documentation
330
+
331
+ Full documentation at **[plotstyle.readthedocs.io](https://plotstyle.readthedocs.io)**:
332
+
333
+ - [Installation guide](https://plotstyle.readthedocs.io/en/stable/installation.html)
334
+ - [Quick start tutorial](https://plotstyle.readthedocs.io/en/stable/quickstart.html)
335
+ - [API reference](https://plotstyle.readthedocs.io/en/stable/api/index.html)
336
+ - [CLI reference](https://plotstyle.readthedocs.io/en/stable/cli.html)
337
+ - [FAQ](https://plotstyle.readthedocs.io/en/stable/faq.html)
338
+
339
+ Working examples are in the [`examples/`](examples/) directory.
340
+
341
+ ---
342
+
343
+ ## Contributing
344
+
345
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for development setup, adding journal specs, and pull request guidelines.
346
+
347
+ ---
348
+
349
+ ## Citation
350
+
351
+ If PlotStyle helps your research, a citation or star is appreciated:
352
+
353
+ ```bibtex
354
+ @misc{plotstyle,
355
+ author = {Kaushal, Rahul},
356
+ title = {PlotStyle: Publication-ready scientific figure presets for Matplotlib},
357
+ year = {2026},
358
+ url = {https://github.com/rahulkaushal04/plotstyle},
359
+ note = {Version 1.1.0},
360
+ }
361
+ ```
362
+
363
+ ---
364
+
365
+ ## License
366
+
367
+ [MIT](LICENSE) © 2026 Rahul Kaushal