plotstyle 0.1.0a1__py3-none-any.whl

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 (60) hide show
  1. plotstyle/__init__.py +121 -0
  2. plotstyle/_utils/__init__.py +0 -0
  3. plotstyle/_utils/io.py +113 -0
  4. plotstyle/_utils/warnings.py +86 -0
  5. plotstyle/_version.py +24 -0
  6. plotstyle/cli/__init__.py +0 -0
  7. plotstyle/cli/main.py +553 -0
  8. plotstyle/color/__init__.py +42 -0
  9. plotstyle/color/_rendering.py +86 -0
  10. plotstyle/color/accessibility.py +286 -0
  11. plotstyle/color/data/okabe_ito.json +5 -0
  12. plotstyle/color/data/safe_grayscale.json +7 -0
  13. plotstyle/color/data/tol_bright.json +5 -0
  14. plotstyle/color/data/tol_muted.json +5 -0
  15. plotstyle/color/data/tol_vibrant.json +5 -0
  16. plotstyle/color/grayscale.py +284 -0
  17. plotstyle/color/palettes.py +259 -0
  18. plotstyle/core/__init__.py +0 -0
  19. plotstyle/core/export.py +418 -0
  20. plotstyle/core/figure.py +394 -0
  21. plotstyle/core/migrate.py +579 -0
  22. plotstyle/core/style.py +394 -0
  23. plotstyle/engine/__init__.py +0 -0
  24. plotstyle/engine/fonts.py +309 -0
  25. plotstyle/engine/latex.py +287 -0
  26. plotstyle/engine/rcparams.py +352 -0
  27. plotstyle/integrations/__init__.py +0 -0
  28. plotstyle/integrations/seaborn.py +305 -0
  29. plotstyle/preview/__init__.py +50 -0
  30. plotstyle/preview/gallery.py +337 -0
  31. plotstyle/preview/print_size.py +304 -0
  32. plotstyle/py.typed +0 -0
  33. plotstyle/specs/__init__.py +304 -0
  34. plotstyle/specs/_templates.toml +48 -0
  35. plotstyle/specs/acs.toml +36 -0
  36. plotstyle/specs/cell.toml +35 -0
  37. plotstyle/specs/elsevier.toml +35 -0
  38. plotstyle/specs/ieee.toml +35 -0
  39. plotstyle/specs/nature.toml +35 -0
  40. plotstyle/specs/plos.toml +35 -0
  41. plotstyle/specs/prl.toml +35 -0
  42. plotstyle/specs/schema.py +1095 -0
  43. plotstyle/specs/science.toml +35 -0
  44. plotstyle/specs/springer.toml +35 -0
  45. plotstyle/specs/units.py +761 -0
  46. plotstyle/specs/wiley.toml +35 -0
  47. plotstyle/validation/__init__.py +94 -0
  48. plotstyle/validation/checks/__init__.py +95 -0
  49. plotstyle/validation/checks/_base.py +149 -0
  50. plotstyle/validation/checks/colors.py +394 -0
  51. plotstyle/validation/checks/dimensions.py +166 -0
  52. plotstyle/validation/checks/export.py +205 -0
  53. plotstyle/validation/checks/lines.py +147 -0
  54. plotstyle/validation/checks/typography.py +200 -0
  55. plotstyle/validation/report.py +293 -0
  56. plotstyle-0.1.0a1.dist-info/METADATA +271 -0
  57. plotstyle-0.1.0a1.dist-info/RECORD +60 -0
  58. plotstyle-0.1.0a1.dist-info/WHEEL +4 -0
  59. plotstyle-0.1.0a1.dist-info/entry_points.txt +2 -0
  60. plotstyle-0.1.0a1.dist-info/licenses/LICENSE +21 -0
plotstyle/__init__.py ADDED
@@ -0,0 +1,121 @@
1
+ """PlotStyle — scientific journal figure style presets for Matplotlib.
2
+
3
+ PlotStyle makes it trivial to produce publication-ready figures that conform
4
+ to the typographic and dimensional requirements of major academic journals.
5
+ A single :func:`use` call reconfigures Matplotlib's ``rcParams``; helper
6
+ functions handle figure sizing, colour palettes, accessibility previews,
7
+ validation, and submission-ready export.
8
+
9
+ Quick start
10
+ -----------
11
+ >>> import matplotlib.pyplot as plt
12
+ >>> import plotstyle
13
+ >>>
14
+ >>> plotstyle.use("nature")
15
+ >>>
16
+ >>> fig, ax = plotstyle.subplots(columns=1)
17
+ >>> ax.plot([0, 1, 2], [0.2, 0.8, 0.4], color=plotstyle.palette("nature")[0])
18
+ >>> ax.set_xlabel("Time (s)")
19
+ >>> ax.set_ylabel("Signal (a.u.)")
20
+ >>>
21
+ >>> report = plotstyle.validate(fig, journal="nature")
22
+ >>> print(report)
23
+ >>>
24
+ >>> plotstyle.savefig(fig, "figure1.pdf")
25
+
26
+ Package layout
27
+ --------------
28
+ The public API is re-exported here from the following sub-packages:
29
+
30
+ - :mod:`plotstyle.core.style` — :func:`use`, :class:`JournalStyle`
31
+ - :mod:`plotstyle.core.figure` — :func:`figure`, :func:`subplots`
32
+ - :mod:`plotstyle.core.export` — :func:`savefig`, :func:`export_submission`
33
+ - :mod:`plotstyle.core.migrate` — :func:`diff`, :func:`migrate`, :class:`SpecDiff`
34
+ - :mod:`plotstyle.color.palettes` — :func:`palette`
35
+ - :mod:`plotstyle.color.accessibility` — :func:`preview_colorblind`
36
+ - :mod:`plotstyle.color.grayscale` — :func:`preview_grayscale`
37
+ - :mod:`plotstyle.validation` — :func:`validate`
38
+ - :mod:`plotstyle.specs` — :data:`registry`
39
+ - :mod:`plotstyle.preview.gallery` — :func:`gallery`
40
+ - :mod:`plotstyle.preview.print_size` — :func:`preview_print_size`
41
+
42
+ Version
43
+ -------
44
+ The installed version is accessible as :data:`plotstyle.__version__`.
45
+ """
46
+
47
+ from __future__ import annotations
48
+
49
+ # ---------------------------------------------------------------------------
50
+ # Package metadata
51
+ # ---------------------------------------------------------------------------
52
+ from importlib.metadata import PackageNotFoundError
53
+ from importlib.metadata import version as _pkg_version
54
+
55
+ # ---------------------------------------------------------------------------
56
+ # Colour utilities
57
+ # ---------------------------------------------------------------------------
58
+ from plotstyle.color.accessibility import preview_colorblind
59
+ from plotstyle.color.grayscale import preview_grayscale
60
+ from plotstyle.color.palettes import palette
61
+
62
+ # ---------------------------------------------------------------------------
63
+ # Core — style application, figure construction, export, spec migration
64
+ # ---------------------------------------------------------------------------
65
+ from plotstyle.core.export import export_submission, savefig
66
+ from plotstyle.core.figure import figure, subplots
67
+ from plotstyle.core.migrate import SpecDiff, diff, migrate
68
+ from plotstyle.core.style import JournalStyle, use
69
+
70
+ # ---------------------------------------------------------------------------
71
+ # Seaborn integration
72
+ # ---------------------------------------------------------------------------
73
+ from plotstyle.integrations.seaborn import patch_seaborn, plotstyle_theme, unpatch_seaborn
74
+
75
+ # ---------------------------------------------------------------------------
76
+ # Preview helpers
77
+ # ---------------------------------------------------------------------------
78
+ from plotstyle.preview.gallery import gallery
79
+ from plotstyle.preview.print_size import preview_print_size
80
+
81
+ # ---------------------------------------------------------------------------
82
+ # Journal spec registry
83
+ # ---------------------------------------------------------------------------
84
+ from plotstyle.specs import registry
85
+
86
+ # ---------------------------------------------------------------------------
87
+ # Validation
88
+ # ---------------------------------------------------------------------------
89
+ from plotstyle.validation import validate
90
+
91
+ try:
92
+ __version__: str = _pkg_version("plotstyle")
93
+ except PackageNotFoundError:
94
+ __version__ = "0.0.0+unknown"
95
+
96
+ # ---------------------------------------------------------------------------
97
+ # Public API surface
98
+ # ---------------------------------------------------------------------------
99
+
100
+ __all__: list[str] = [
101
+ "JournalStyle",
102
+ "SpecDiff",
103
+ "__version__",
104
+ "diff",
105
+ "export_submission",
106
+ "figure",
107
+ "gallery",
108
+ "migrate",
109
+ "palette",
110
+ "patch_seaborn",
111
+ "plotstyle_theme",
112
+ "preview_colorblind",
113
+ "preview_grayscale",
114
+ "preview_print_size",
115
+ "registry",
116
+ "savefig",
117
+ "subplots",
118
+ "unpatch_seaborn",
119
+ "use",
120
+ "validate",
121
+ ]
File without changes
plotstyle/_utils/io.py ADDED
@@ -0,0 +1,113 @@
1
+ """File I/O helpers for PlotStyle.
2
+
3
+ This module provides thin wrappers around common file operations used
4
+ throughout PlotStyle:
5
+
6
+ - **TOML loading** — :func:`load_toml` reads journal specification and
7
+ configuration files. On Python 3.11+ the standard library
8
+ :mod:`tomllib` module is used; on older Python versions the third-party
9
+ :mod:`tomli` back-port is required.
10
+
11
+ Python version handling
12
+ -----------------------
13
+ TOML support was added to the Python standard library in 3.11 (PEP 680).
14
+ For Python 3.10 and earlier, PlotStyle requires the ``tomli`` package, which
15
+ is API-compatible with ``tomllib`` and is a zero-dependency pure-Python
16
+ library. The import shim at module level ensures the rest of the codebase
17
+ imports only from this module, insulating it from the stdlib/backport split.
18
+
19
+ Example
20
+ -------
21
+ >>> from pathlib import Path
22
+ >>> from plotstyle._utils.io import load_toml
23
+ >>> config = load_toml(Path("pyproject.toml"))
24
+ >>> config["project"]["name"]
25
+ 'plotstyle'
26
+ """
27
+
28
+ from __future__ import annotations
29
+
30
+ import sys
31
+ from typing import TYPE_CHECKING, Any
32
+
33
+ if TYPE_CHECKING:
34
+ from pathlib import Path
35
+
36
+
37
+ # ---------------------------------------------------------------------------
38
+ # TOML back-compat shim
39
+ # ---------------------------------------------------------------------------
40
+
41
+ # tomllib became part of the standard library in Python 3.11 (PEP 680).
42
+ # For earlier versions we fall back to the 'tomli' third-party package, which
43
+ # is API-identical and is a declared dependency of PlotStyle for Python < 3.11.
44
+ if sys.version_info >= (3, 11):
45
+ import tomllib
46
+ else:
47
+ try:
48
+ import tomli as tomllib # type: ignore[no-redef]
49
+ except ImportError as exc: # pragma: no cover
50
+ raise ImportError(
51
+ "PlotStyle requires the 'tomli' package on Python < 3.11. "
52
+ "Install it with: pip install tomli"
53
+ ) from exc
54
+
55
+
56
+ # ---------------------------------------------------------------------------
57
+ # Public helpers
58
+ # ---------------------------------------------------------------------------
59
+
60
+
61
+ def load_toml(path: Path) -> dict[str, Any]:
62
+ """Load and parse a TOML file into a Python dictionary.
63
+
64
+ Opens *path* in binary mode (as required by both :mod:`tomllib` and
65
+ :mod:`tomli`) and returns the fully parsed document. All standard TOML
66
+ types are mapped to their Python equivalents: strings, integers, floats,
67
+ booleans, datetimes, arrays, and inline tables.
68
+
69
+ Args:
70
+ path: Filesystem path to the ``.toml`` file. Must be an existing,
71
+ readable regular file. :class:`~pathlib.Path` is the canonical
72
+ type, but any object implementing the :meth:`open` protocol with
73
+ binary-read support is accepted.
74
+
75
+ Returns
76
+ -------
77
+ A :class:`dict` containing the top-level keys and values parsed from
78
+ the TOML document. Nested tables become nested dicts; TOML arrays
79
+ become Python lists.
80
+
81
+ Raises
82
+ ------
83
+ FileNotFoundError: If *path* does not exist on the filesystem.
84
+ IsADirectoryError: If *path* points to a directory rather than a file.
85
+ PermissionError: If the process does not have read permission for
86
+ *path*.
87
+ OSError: For other low-level I/O failures (e.g., broken filesystem,
88
+ NFS timeout).
89
+ tomllib.TOMLDecodeError: If the file content is not valid TOML. The
90
+ exception message includes the line and column of the syntax error.
91
+
92
+ Example:
93
+ >>> from pathlib import Path
94
+ >>> from plotstyle._utils.io import load_toml
95
+ >>> data = load_toml(Path("journals/nature.toml"))
96
+ >>> data["journal"]["name"]
97
+ 'Nature'
98
+
99
+ Notes
100
+ -----
101
+ - Both :mod:`tomllib` (stdlib, Python ≥ 3.11) and :mod:`tomli`
102
+ (backport, Python < 3.11) require the file to be opened in *binary*
103
+ mode (``"rb"``). This module handles that detail internally so
104
+ callers can treat :func:`load_toml` as a plain text-file loader.
105
+ - No caching is performed; each call re-reads the file from disk.
106
+ For files that are loaded repeatedly (e.g., palette data), callers
107
+ should cache the result at the call site.
108
+ - The function does not validate the contents of the parsed dictionary
109
+ beyond what the TOML spec requires. Schema validation is the
110
+ responsibility of the caller.
111
+ """
112
+ with path.open("rb") as fh:
113
+ return tomllib.load(fh)
@@ -0,0 +1,86 @@
1
+ """Warning hierarchy for PlotStyle.
2
+
3
+ All warnings emitted by PlotStyle derive from :class:`PlotStyleWarning`, which
4
+ itself subclasses the built-in :class:`UserWarning`. This two-level hierarchy
5
+ lets users selectively filter or silence PlotStyle-specific warnings without
6
+ affecting unrelated user warnings from other packages:
7
+
8
+ .. code-block:: python
9
+
10
+ import warnings
11
+ from plotstyle._utils.warnings import PlotStyleWarning
12
+
13
+ # Silence all PlotStyle warnings at once.
14
+ warnings.filterwarnings("ignore", category=PlotStyleWarning)
15
+
16
+ # Or silence only a specific sub-class.
17
+ from plotstyle._utils.warnings import FontFallbackWarning
18
+
19
+ warnings.filterwarnings("ignore", category=FontFallbackWarning)
20
+
21
+ Warning classes
22
+ ---------------
23
+ .. autosummary::
24
+
25
+ PlotStyleWarning
26
+ FontFallbackWarning
27
+
28
+ Design notes
29
+ ------------
30
+ - All warning classes are intentionally kept as thin stubs. They carry no
31
+ data attributes beyond the message string inherited from :class:`Warning`.
32
+ If structured warning data is ever needed, add it as constructor arguments
33
+ on the specific subclass rather than on the base class.
34
+ - ``pass`` is omitted from class bodies by convention (a docstring is
35
+ sufficient to make the body non-empty), improving readability in IDEs and
36
+ documentation renderers.
37
+ - Inheriting from :class:`UserWarning` (via :class:`PlotStyleWarning`) ensures
38
+ that ``warnings.warn(..., stacklevel=2)`` displays the caller's frame, not
39
+ the internals of PlotStyle, in the warning message.
40
+ """
41
+
42
+ from __future__ import annotations
43
+
44
+
45
+ class PlotStyleWarning(UserWarning):
46
+ """Base class for all PlotStyle warnings.
47
+
48
+ Subclass :class:`UserWarning` so that PlotStyle warnings are visible by
49
+ default (Python does not suppress ``UserWarning`` the way it suppresses
50
+ :class:`DeprecationWarning`), while still being filterable as a group.
51
+
52
+ All other PlotStyle warning classes inherit from this class. To silence
53
+ every warning from PlotStyle in one call, filter on this base class:
54
+
55
+ .. code-block:: python
56
+
57
+ import warnings
58
+
59
+ warnings.filterwarnings("ignore", category=PlotStyleWarning)
60
+
61
+ Example:
62
+ >>> import warnings
63
+ >>> from plotstyle._utils.warnings import PlotStyleWarning
64
+ >>> warnings.warn("example", PlotStyleWarning, stacklevel=2)
65
+ """
66
+
67
+
68
+ class FontFallbackWarning(PlotStyleWarning):
69
+ """Raised when a preferred font is unavailable and a fallback is used.
70
+
71
+ PlotStyle attempts to activate journal-specific fonts (e.g., Helvetica
72
+ Neue for Nature, Times New Roman for IEEE). When the requested font is
73
+ not installed on the system, Matplotlib falls back to its default font
74
+ family. This warning is emitted in that situation so that authors are
75
+ aware the rendered figure may not match the journal's typographic
76
+ requirements.
77
+
78
+ Example:
79
+ >>> import warnings
80
+ >>> from plotstyle._utils.warnings import FontFallbackWarning
81
+ >>> warnings.warn(
82
+ ... "Font 'Helvetica Neue' not found; falling back to 'DejaVu Sans'.",
83
+ ... FontFallbackWarning,
84
+ ... stacklevel=2,
85
+ ... )
86
+ """
plotstyle/_version.py ADDED
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '0.1.0a1'
22
+ __version_tuple__ = version_tuple = (0, 1, 0, 'a1')
23
+
24
+ __commit_id__ = commit_id = None
File without changes