scienceplots-toolkit 0.1.1__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.
- scienceplots_toolkit/__init__.py +54 -0
- scienceplots_toolkit/analysis.py +70 -0
- scienceplots_toolkit/style.py +139 -0
- scienceplots_toolkit/utils.py +98 -0
- scienceplots_toolkit-0.1.1.dist-info/METADATA +260 -0
- scienceplots_toolkit-0.1.1.dist-info/RECORD +8 -0
- scienceplots_toolkit-0.1.1.dist-info/WHEEL +4 -0
- scienceplots_toolkit-0.1.1.dist-info/licenses/LICENSE +31 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"""SciencePlots Toolkit - Publication-quality Matplotlib plotting utilities.
|
|
2
|
+
|
|
3
|
+
A toolkit for creating consistent, publication-quality scientific plots
|
|
4
|
+
using Matplotlib with SciencePlots styles and LaTeX typesetting.
|
|
5
|
+
|
|
6
|
+
Example usage:
|
|
7
|
+
>>> from scienceplots_toolkit import configure_matplotlib_style, save_plot
|
|
8
|
+
>>> from scienceplots_toolkit.utils import configure_24h_axis
|
|
9
|
+
>>>
|
|
10
|
+
>>> configure_matplotlib_style(use_latex=True)
|
|
11
|
+
>>> fig, ax = plt.subplots()
|
|
12
|
+
>>> ax.plot([1, 2, 3], [4, 5, 6])
|
|
13
|
+
>>> configure_24h_axis(ax)
|
|
14
|
+
>>> save_plot(fig, "my_plot")
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
from scienceplots_toolkit.analysis import (
|
|
18
|
+
generate_profile_grid,
|
|
19
|
+
plot_profile_with_quantiles,
|
|
20
|
+
)
|
|
21
|
+
from scienceplots_toolkit.style import (
|
|
22
|
+
DEFAULT_QUAL_CMAP_NAME,
|
|
23
|
+
configure_matplotlib_style,
|
|
24
|
+
qual_cmap,
|
|
25
|
+
)
|
|
26
|
+
from scienceplots_toolkit.utils import (
|
|
27
|
+
OUTPUT_DIR,
|
|
28
|
+
add_stats_box,
|
|
29
|
+
configure_24h_axis,
|
|
30
|
+
save_plot,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
__version__ = "0.1.0"
|
|
34
|
+
__author__ = "Jakob Buchmeier"
|
|
35
|
+
__email__ = "jakob.buchmeier@tuwien.ac.at"
|
|
36
|
+
|
|
37
|
+
__all__ = [
|
|
38
|
+
# Version info
|
|
39
|
+
"__version__",
|
|
40
|
+
"__author__",
|
|
41
|
+
"__email__",
|
|
42
|
+
# Style configuration
|
|
43
|
+
"configure_matplotlib_style",
|
|
44
|
+
"qual_cmap",
|
|
45
|
+
"DEFAULT_QUAL_CMAP_NAME",
|
|
46
|
+
# Utilities
|
|
47
|
+
"save_plot",
|
|
48
|
+
"configure_24h_axis",
|
|
49
|
+
"add_stats_box",
|
|
50
|
+
"OUTPUT_DIR",
|
|
51
|
+
# Analysis
|
|
52
|
+
"plot_profile_with_quantiles",
|
|
53
|
+
"generate_profile_grid",
|
|
54
|
+
]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Specialized functions for time-series visualization and analysis."""
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
import numpy as np
|
|
7
|
+
from matplotlib.axes import Axes
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def plot_profile_with_quantiles(
|
|
11
|
+
ax: Axes,
|
|
12
|
+
x: np.ndarray,
|
|
13
|
+
mean: np.ndarray,
|
|
14
|
+
q10: np.ndarray,
|
|
15
|
+
q90: np.ndarray,
|
|
16
|
+
label: str,
|
|
17
|
+
color: str | None = None,
|
|
18
|
+
) -> None:
|
|
19
|
+
"""Plot mean with 10%–90% quantile shading.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
ax: Axes to plot on.
|
|
23
|
+
x: X-axis values (usually 0-24).
|
|
24
|
+
mean: Mean profile data.
|
|
25
|
+
q10: 10th percentile profile data.
|
|
26
|
+
q90: 90th percentile profile data.
|
|
27
|
+
label: Legend label for the mean line.
|
|
28
|
+
color: Optional fixed color for line and shading.
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
line = ax.plot(x, mean, label=label, color=color, linewidth=2.5)
|
|
32
|
+
c = line[0].get_color()
|
|
33
|
+
ax.fill_between(
|
|
34
|
+
x, q10, q90, alpha=0.2, color=c, edgecolor="none", label=r"10%--90% Quantile"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def generate_profile_grid(
|
|
39
|
+
n_rows: int,
|
|
40
|
+
n_cols: int,
|
|
41
|
+
figsize: tuple[float, float] = (16, 10),
|
|
42
|
+
sharey: Literal["row", "col", "all"] | bool = "row",
|
|
43
|
+
) -> tuple[plt.Figure, list[Axes]]:
|
|
44
|
+
"""Generate multi-panel grids of 24h profiles with standard axis sharing.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
n_rows: Number of rows in the grid.
|
|
48
|
+
n_cols: Number of columns in the grid.
|
|
49
|
+
figsize: Size of the complete figure.
|
|
50
|
+
sharey: Axis sharing mode (default 'row').
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
A tuple containing (figure, list of axes).
|
|
54
|
+
|
|
55
|
+
"""
|
|
56
|
+
fig, axes = plt.subplots(
|
|
57
|
+
n_rows,
|
|
58
|
+
n_cols,
|
|
59
|
+
figsize=figsize,
|
|
60
|
+
sharex=True,
|
|
61
|
+
sharey=sharey,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# Flatten axes if needed
|
|
65
|
+
if n_rows * n_cols > 1:
|
|
66
|
+
axes_list = axes.flatten()
|
|
67
|
+
else:
|
|
68
|
+
axes_list = [axes]
|
|
69
|
+
|
|
70
|
+
return fig, axes_list
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""Centralised Matplotlib styling and configuration for consistent plotting."""
|
|
2
|
+
|
|
3
|
+
from typing import Literal
|
|
4
|
+
|
|
5
|
+
import matplotlib.pyplot as plt
|
|
6
|
+
import scienceplots # noqa: F401 - Required for matplotlib 'science' and 'ieee' styles
|
|
7
|
+
from cmap import Colormap
|
|
8
|
+
from cycler import cycler
|
|
9
|
+
|
|
10
|
+
# Default qualitative colormap used across plots
|
|
11
|
+
DEFAULT_QUAL_CMAP_NAME = "seaborn:tab10_new"
|
|
12
|
+
|
|
13
|
+
# https://cmap-docs.readthedocs.io/en/latest/catalog/qualitative/seaborn%3Atab10_new/
|
|
14
|
+
# tab10_new colour codes:
|
|
15
|
+
# blue #4E79A7
|
|
16
|
+
# orange #F28E2B
|
|
17
|
+
# red #E15759
|
|
18
|
+
# light blue #76B7B2
|
|
19
|
+
# green #59A14E
|
|
20
|
+
# yellow #EDC949
|
|
21
|
+
# lila #AF7AA1
|
|
22
|
+
# rosa #FF9DA7
|
|
23
|
+
# brown #9C755F
|
|
24
|
+
# grey #BAB0AB
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def qual_cmap(cmap_name: str = DEFAULT_QUAL_CMAP_NAME) -> Colormap:
|
|
28
|
+
"""Return the qualitative cmap of the given name (cmap.Colormap instance).
|
|
29
|
+
|
|
30
|
+
Default is 'seaborn:tab10_new'.
|
|
31
|
+
See: https://cmap-docs.readthedocs.io/en/latest/catalog/qualitative/seaborn%3Atab10_new/
|
|
32
|
+
"""
|
|
33
|
+
return Colormap(cmap_name)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def configure_matplotlib_style(
|
|
37
|
+
styles: list[str] | str = ["science", "ieee", "grid"],
|
|
38
|
+
grid_linewidth: float = 3,
|
|
39
|
+
lines_linewidth: float = 4,
|
|
40
|
+
fontsize: float = 26,
|
|
41
|
+
figsize: tuple[float, float] = (16, 10),
|
|
42
|
+
font: Literal["serif", "sans-serif"] | str = "serif",
|
|
43
|
+
sans_serif_math: bool = False,
|
|
44
|
+
cmap_name: str = DEFAULT_QUAL_CMAP_NAME,
|
|
45
|
+
use_latex: bool = False,
|
|
46
|
+
grid: bool = True,
|
|
47
|
+
legend_framealpha: float = 1.0,
|
|
48
|
+
legend_shadow: bool = True,
|
|
49
|
+
) -> None:
|
|
50
|
+
"""Configure matplotlib style and register the default qualitative colormap.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
styles: list or single style name passed to plt.style.use, default
|
|
54
|
+
["science", "ieee"], enable grid with "grid" in the list.
|
|
55
|
+
grid_linewidth: Width to use for grid lines.
|
|
56
|
+
lines_linewidth: Width for plot lines.
|
|
57
|
+
fontsize: Base font size.
|
|
58
|
+
figsize: Figure size as (width, height) in inches.
|
|
59
|
+
font: Font family to use (e.g., 'serif', 'sans-serif' or specific font
|
|
60
|
+
e.g., 'Times', 'Helvetica').
|
|
61
|
+
See: https://matplotlib.org/stable/users/explain/text/usetex.html
|
|
62
|
+
sans_serif_math: If True, use sans-serif font for math text (default
|
|
63
|
+
serif math in LaTeX).
|
|
64
|
+
cmap_name: Name of the qualitative colormap to use for default colours.
|
|
65
|
+
See: https://cmap-docs.readthedocs.io/en/latest/catalog/qualitative/seaborn%3Atab10_new/
|
|
66
|
+
use_latex: If True, use LaTeX for text rendering. If False (default), use
|
|
67
|
+
'no-latex' style and disable usetex.
|
|
68
|
+
grid: Whether to enable axis gridlines by default (`axes.grid` rcParam).
|
|
69
|
+
Disable for stuff like Heatmaps.
|
|
70
|
+
legend_framealpha: Alpha (transparency) of the legend background, 0.0
|
|
71
|
+
(transparent) to 1.0 (opaque). Default 1 because of legend_shadow.
|
|
72
|
+
legend_shadow: If True (default), draw a shadow behind the legend frame.
|
|
73
|
+
|
|
74
|
+
"""
|
|
75
|
+
# Reset to default matplotlib style before applying new styles
|
|
76
|
+
plt.rcdefaults()
|
|
77
|
+
|
|
78
|
+
# Get colors from the qualitative colormap
|
|
79
|
+
cm = qual_cmap(cmap_name)
|
|
80
|
+
default_colors = [
|
|
81
|
+
cm(i / (9)) for i in range(10)
|
|
82
|
+
] # 10 colors from the qualitative colormap
|
|
83
|
+
|
|
84
|
+
# Handle no-latex logic
|
|
85
|
+
if not use_latex:
|
|
86
|
+
if isinstance(styles, list):
|
|
87
|
+
styles = [s if s != "ieee" else "no-latex" for s in styles]
|
|
88
|
+
elif styles == "ieee":
|
|
89
|
+
styles = "no-latex"
|
|
90
|
+
|
|
91
|
+
# Apply scienceplots style
|
|
92
|
+
plt.style.use(styles)
|
|
93
|
+
|
|
94
|
+
# Build LaTeX preamble
|
|
95
|
+
preamble = (
|
|
96
|
+
r"\usepackage{amsmath,amssymb,amsfonts}"
|
|
97
|
+
r"\usepackage{textcomp}"
|
|
98
|
+
r"\usepackage{gensymb}"
|
|
99
|
+
r"\usepackage{siunitx}"
|
|
100
|
+
r"\usepackage{graphicx}"
|
|
101
|
+
)
|
|
102
|
+
if sans_serif_math:
|
|
103
|
+
# Switch both text and math to sans-serif in LaTeX
|
|
104
|
+
preamble += (
|
|
105
|
+
r"\usepackage{sansmath}\sansmath\renewcommand{\familydefault}{\sfdefault}"
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# reference: https://matplotlib.org/stable/users/explain/customizing.html
|
|
109
|
+
rc: dict = {
|
|
110
|
+
"font.size": fontsize, # The font.size property is the default font size for text, given in points.
|
|
111
|
+
"text.usetex": use_latex, # use latex for all text handling.
|
|
112
|
+
"text.latex.preamble": preamble, # text.latex.preamble is a single line of LaTeX code that will be passed on to the LaTeX system.
|
|
113
|
+
"font.family": font, # The font.family property can take either a single or multiple entries of any combination of concrete font names
|
|
114
|
+
"axes.titlesize": fontsize + 4, # font size of the axes title
|
|
115
|
+
"axes.labelsize": fontsize + 2, # font size of the x and y labels
|
|
116
|
+
"axes.axisbelow": False, # draw axis gridlines and ticks: below patches (True), above patches but below lines ('line'), above all (False)
|
|
117
|
+
# Do not set "axes.grid" here when grid is True; leave it to the applied style.
|
|
118
|
+
"axes.prop_cycle": cycler(
|
|
119
|
+
"color", default_colors
|
|
120
|
+
), # colour cycle for plot lines as list of string colour specs: single letter, long name, or web-style hex
|
|
121
|
+
"grid.linewidth": grid_linewidth, # in points
|
|
122
|
+
"lines.linewidth": lines_linewidth, # line width in points
|
|
123
|
+
"legend.handlelength": 1.5, # the length of the legend lines
|
|
124
|
+
"legend.shadow": legend_shadow, # if True, give background a shadow effect
|
|
125
|
+
"legend.framealpha": legend_framealpha, # legend patch transparency
|
|
126
|
+
"figure.titlesize": fontsize
|
|
127
|
+
+ 4, # size of the figure title (``Figure.suptitle()``)
|
|
128
|
+
"figure.labelsize": fontsize
|
|
129
|
+
+ 2, # size of the figure label (``Figure.sup[x|y]label()``)
|
|
130
|
+
"figure.figsize": figsize, # figure size in inches
|
|
131
|
+
"figure.constrained_layout.use": True, # When True, automatically make plot elements fit on the figure, is the new and improved tight_layout
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
# Only explicitly disable the axes grid if the user requested grid=False.
|
|
135
|
+
# If grid is True, we don't modify 'axes.grid' here so the style rules remain in effect.
|
|
136
|
+
if grid is False:
|
|
137
|
+
rc["axes.grid"] = False
|
|
138
|
+
|
|
139
|
+
plt.rcParams.update(rc)
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
"""Utility functions for saving and configuring plots."""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
from matplotlib.axes import Axes
|
|
7
|
+
from matplotlib.figure import Figure
|
|
8
|
+
|
|
9
|
+
# Constants
|
|
10
|
+
OUTPUT_DIR = Path("output")
|
|
11
|
+
logger = logging.getLogger(__name__)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def save_plot(
|
|
15
|
+
fig: Figure, filename_base: str, output_dir: Path | None = None, dpi: int = 300
|
|
16
|
+
) -> None:
|
|
17
|
+
"""Save current figure to PNG and PDF.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
fig: Figure to save.
|
|
21
|
+
filename_base: Base filename (no extension).
|
|
22
|
+
output_dir: Directory to save files. Defaults to OUTPUT_DIR.
|
|
23
|
+
dpi: Resolution for the PNG output.
|
|
24
|
+
|
|
25
|
+
"""
|
|
26
|
+
if output_dir is None:
|
|
27
|
+
output_dir = OUTPUT_DIR
|
|
28
|
+
|
|
29
|
+
# Ensure output_dir is a Path object
|
|
30
|
+
if isinstance(output_dir, str):
|
|
31
|
+
output_dir = Path(output_dir)
|
|
32
|
+
|
|
33
|
+
output_dir.mkdir(parents=True, exist_ok=True)
|
|
34
|
+
|
|
35
|
+
png_path = output_dir / f"{filename_base}.png"
|
|
36
|
+
pdf_path = output_dir / f"{filename_base}.pdf"
|
|
37
|
+
fig.savefig(png_path, dpi=dpi)
|
|
38
|
+
fig.savefig(pdf_path, dpi=dpi)
|
|
39
|
+
logger.info("Saved %s and %s", png_path, pdf_path)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def configure_24h_axis(ax: Axes) -> None:
|
|
43
|
+
"""Standardise 24-hour time axes (0-24h with 4h ticks).
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
ax: Axes to configure.
|
|
47
|
+
|
|
48
|
+
"""
|
|
49
|
+
ax.set_xticks(range(0, 25, 4))
|
|
50
|
+
ax.set_xlim(0, 24)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def add_stats_box(
|
|
54
|
+
ax: Axes,
|
|
55
|
+
avg: float,
|
|
56
|
+
peak: float,
|
|
57
|
+
unit: str = r"\text{kW}",
|
|
58
|
+
loc: str = "upper left",
|
|
59
|
+
) -> None:
|
|
60
|
+
"""Add annotation boxes showing Average and Peak values.
|
|
61
|
+
|
|
62
|
+
Args:
|
|
63
|
+
ax: Axes to annotate.
|
|
64
|
+
avg: Average value.
|
|
65
|
+
peak: Peak value.
|
|
66
|
+
unit: LaTeX unit string.
|
|
67
|
+
loc: Position of the box (standard matplotlib loc strings).
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
stats_text = (
|
|
71
|
+
rf"$\text{{Avg}}: {avg:.1f}\ {unit}$"
|
|
72
|
+
"\n"
|
|
73
|
+
rf"$\text{{Peak}}: {peak:.1f}\ {unit}$"
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Convert loc string to coordinates if needed, or use ax.text with transform
|
|
77
|
+
props = dict(boxstyle="round", facecolor="white", alpha=0.8, edgecolor="gray")
|
|
78
|
+
|
|
79
|
+
# Mapping standard locs to coordinates for simple implementation
|
|
80
|
+
loc_map = {
|
|
81
|
+
"upper left": (0.05, 0.95),
|
|
82
|
+
"upper right": (0.95, 0.95),
|
|
83
|
+
"upper center": (0.5, 0.95),
|
|
84
|
+
}
|
|
85
|
+
x, y = loc_map.get(loc, (0.05, 0.95))
|
|
86
|
+
|
|
87
|
+
ha = "left" if "left" in loc else ("right" if "right" in loc else "center")
|
|
88
|
+
va = "top" if "upper" in loc else "bottom"
|
|
89
|
+
|
|
90
|
+
ax.text(
|
|
91
|
+
x,
|
|
92
|
+
y,
|
|
93
|
+
stats_text,
|
|
94
|
+
transform=ax.transAxes,
|
|
95
|
+
verticalalignment=va,
|
|
96
|
+
horizontalalignment=ha,
|
|
97
|
+
bbox=props,
|
|
98
|
+
)
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: scienceplots-toolkit
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Publication-quality Matplotlib plotting utilities with SciencePlots styles and LaTeX typesetting
|
|
5
|
+
Project-URL: Homepage, https://github.com/jakobbuch/scienceplots-toolkit
|
|
6
|
+
Project-URL: Bug Tracker, https://github.com/jakobbuch/scienceplots-toolkit/issues
|
|
7
|
+
Project-URL: Source, https://github.com/jakobbuch/scienceplots-toolkit
|
|
8
|
+
Project-URL: Changelog, https://github.com/jakobbuch/scienceplots-toolkit/blob/main/CHANGELOG.md
|
|
9
|
+
Author-email: Jakob Buchmeier <jakob.buchmeier@tuwien.ac.at>
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.12
|
|
24
|
+
Requires-Dist: cmap>=0.6.2
|
|
25
|
+
Requires-Dist: matplotlib>=3.10.7
|
|
26
|
+
Requires-Dist: scienceplots>=2.1.1
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: pre-commit>=4.3.0; extra == 'dev'
|
|
29
|
+
Requires-Dist: ruff>=0.4; extra == 'dev'
|
|
30
|
+
Requires-Dist: ty; extra == 'dev'
|
|
31
|
+
Provides-Extra: tests
|
|
32
|
+
Requires-Dist: numpy>=1.24; extra == 'tests'
|
|
33
|
+
Requires-Dist: pytest-cov>=4; extra == 'tests'
|
|
34
|
+
Requires-Dist: pytest>=8; extra == 'tests'
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
|
|
37
|
+
# SciencePlots Toolkit
|
|
38
|
+
|
|
39
|
+
[](https://pypi.org/project/scienceplots-toolkit)
|
|
40
|
+
[](https://pypi.org/project/scienceplots-toolkit)
|
|
41
|
+
[](https://github.com/jakobbuch/scienceplots-toolkit/blob/main/LICENSE)
|
|
42
|
+
|
|
43
|
+
Publication-quality Matplotlib plotting utilities with SciencePlots styles and LaTeX typesetting.
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
- **Pre-configured SciencePlots styles** with professional defaults
|
|
48
|
+
- **LaTeX typesetting** for mathematical expressions and units
|
|
49
|
+
- **24-hour time axis** utilities for daily profiles
|
|
50
|
+
- **Statistical annotations** for average/peak values
|
|
51
|
+
- **Quantile shading** for uncertainty visualization
|
|
52
|
+
- **Multi-panel grid** generation for comparative plots
|
|
53
|
+
|
|
54
|
+
## Installation
|
|
55
|
+
|
|
56
|
+
### From PyPI
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
pip install scienceplots-toolkit
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### From source with uv
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
git clone https://github.com/jakobbuch/scienceplots-toolkit.git
|
|
66
|
+
cd scienceplots-toolkit
|
|
67
|
+
uv sync
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### From source with pip
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
git clone https://github.com/jakobbuch/scienceplots-toolkit.git
|
|
74
|
+
cd scienceplots-toolkit
|
|
75
|
+
pip install -e .
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Quick Start
|
|
79
|
+
|
|
80
|
+
```python
|
|
81
|
+
from scienceplots_toolkit import configure_matplotlib_style, save_plot
|
|
82
|
+
from scienceplots_toolkit.utils import configure_24h_axis, add_stats_box
|
|
83
|
+
import matplotlib.pyplot as plt
|
|
84
|
+
import numpy as np
|
|
85
|
+
|
|
86
|
+
# Configure the style
|
|
87
|
+
configure_matplotlib_style(use_latex=True)
|
|
88
|
+
|
|
89
|
+
# Create a simple plot
|
|
90
|
+
fig, ax = plt.subplots()
|
|
91
|
+
x = np.linspace(0, 10, 400)
|
|
92
|
+
ax.plot(x, np.sin(x), label=r"$\sin(x)$")
|
|
93
|
+
ax.set_xlabel(r"Time (s)")
|
|
94
|
+
ax.set_ylabel(r"Amplitude")
|
|
95
|
+
ax.legend()
|
|
96
|
+
|
|
97
|
+
# Save the plot
|
|
98
|
+
save_plot(fig, "my_first_plot")
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
## Examples
|
|
102
|
+
|
|
103
|
+
### Basic Plots
|
|
104
|
+
|
|
105
|
+
Run the basic examples to see all features in action:
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
# Without LaTeX (uses mathtext)
|
|
109
|
+
uv run examples/example_basic.py
|
|
110
|
+
|
|
111
|
+
# With LaTeX rendering (requires LaTeX installation)
|
|
112
|
+
uv run examples/example_basic.py --latex
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Energy Profiles
|
|
116
|
+
|
|
117
|
+
Advanced examples with 24h load profiles and quantile shading:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
uv run examples/example_energy.py
|
|
121
|
+
uv run examples/example_energy.py --latex
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Generated plots are saved to the `output/` directory in both PNG and PDF formats.
|
|
125
|
+
|
|
126
|
+
## API Reference
|
|
127
|
+
|
|
128
|
+
### Style Configuration
|
|
129
|
+
|
|
130
|
+
```python
|
|
131
|
+
from scienceplots_toolkit import configure_matplotlib_style
|
|
132
|
+
|
|
133
|
+
configure_matplotlib_style(
|
|
134
|
+
styles=["science", "ieee", "grid"], # SciencePlots styles to use
|
|
135
|
+
grid_linewidth=3, # Grid line width in points
|
|
136
|
+
lines_linewidth=4, # Plot line width in points
|
|
137
|
+
fontsize=26, # Base font size
|
|
138
|
+
figsize=(16, 10), # Default figure size (inches)
|
|
139
|
+
font="serif", # Font family
|
|
140
|
+
sans_serif_math=False, # Use sans-serif for math
|
|
141
|
+
cmap_name="seaborn:tab10_new", # Qualitative colormap
|
|
142
|
+
use_latex=False, # Enable LaTeX rendering
|
|
143
|
+
grid=True, # Enable axis gridlines
|
|
144
|
+
legend_framealpha=1.0, # Legend background transparency
|
|
145
|
+
legend_shadow=True, # Legend shadow effect
|
|
146
|
+
)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Utilities
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
from scienceplots_toolkit.utils import (
|
|
153
|
+
save_plot, # Save figure to PNG and PDF
|
|
154
|
+
configure_24h_axis, # Set up 0-24h x-axis with 4h ticks
|
|
155
|
+
add_stats_box, # Add average/peak annotation box
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Save a figure
|
|
159
|
+
save_plot(fig, "my_plot", dpi=300)
|
|
160
|
+
|
|
161
|
+
# Configure 24-hour axis
|
|
162
|
+
configure_24h_axis(ax)
|
|
163
|
+
|
|
164
|
+
# Add statistics box
|
|
165
|
+
add_stats_box(ax, avg=5.2, peak=12.3, unit=r"\text{kW}")
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### Analysis Tools
|
|
169
|
+
|
|
170
|
+
```python
|
|
171
|
+
from scienceplots_toolkit import (
|
|
172
|
+
plot_profile_with_quantiles, # Plot mean with shaded quantiles
|
|
173
|
+
generate_profile_grid, # Create multi-panel grid of plots
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Plot with uncertainty shading
|
|
177
|
+
plot_profile_with_quantiles(
|
|
178
|
+
ax, x, mean, q10, q90,
|
|
179
|
+
label="Load Profile",
|
|
180
|
+
color="C0"
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
# Create a 2x2 grid of subplots
|
|
184
|
+
fig, axes = generate_profile_grid(n_rows=2, n_cols=2)
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## LaTeX Support
|
|
188
|
+
|
|
189
|
+
The package supports two modes:
|
|
190
|
+
|
|
191
|
+
1. **Mathtext (default)**: Uses Matplotlib's built-in math renderer. No external dependencies.
|
|
192
|
+
2. **LaTeX**: Uses system LaTeX for professional typesetting. Requires:
|
|
193
|
+
- TeX Live or MiKTeX installation
|
|
194
|
+
- Packages: `amsmath`, `amssymb`, `amsfonts`, `textcomp`, `gensymb`, `siunitx`, `graphicx`
|
|
195
|
+
|
|
196
|
+
Enable LaTeX mode:
|
|
197
|
+
|
|
198
|
+
```python
|
|
199
|
+
configure_matplotlib_style(use_latex=True)
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Or via CLI:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
uv run examples/example_basic.py --latex
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Project Structure
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
scienceplots-toolkit/
|
|
212
|
+
├── src/scienceplots_toolkit/
|
|
213
|
+
│ ├── __init__.py # Public API exports
|
|
214
|
+
│ ├── style.py # Matplotlib style configuration
|
|
215
|
+
│ ├── utils.py # Utility functions
|
|
216
|
+
│ └── analysis.py # Analysis and visualization tools
|
|
217
|
+
├── examples/
|
|
218
|
+
│ ├── example_basic.py # Basic plotting examples
|
|
219
|
+
│ └── example_energy.py # Energy profile examples
|
|
220
|
+
├── tests/
|
|
221
|
+
├── pyproject.toml
|
|
222
|
+
├── README.md
|
|
223
|
+
└── LICENSE
|
|
224
|
+
## Development
|
|
225
|
+
|
|
226
|
+
### Setup
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
uv sync --group dev
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Run Tests
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
uv run pytest tests/ -v
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### Linting and Formatting
|
|
239
|
+
|
|
240
|
+
```bash
|
|
241
|
+
uv run ruff format .
|
|
242
|
+
uv run ruff check .
|
|
243
|
+
uv run ty check .
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Acknowledgments
|
|
247
|
+
|
|
248
|
+
This package builds upon the excellent [SciencePlots](https://github.com/garrettj403/SciencePlots) library by John Garrett, which is also licensed under the MIT License.
|
|
249
|
+
|
|
250
|
+
SciencePlots provides Matplotlib styles for publication-quality plots. For more information, see: <https://github.com/garrettj403/SciencePlots>
|
|
251
|
+
|
|
252
|
+
## License
|
|
253
|
+
|
|
254
|
+
Distributed under the MIT License. See [LICENSE](LICENSE) for details.
|
|
255
|
+
|
|
256
|
+
## Contact
|
|
257
|
+
|
|
258
|
+
Jakob Buchmeier - <jakob.buchmeier@tuwien.ac.at>
|
|
259
|
+
|
|
260
|
+
Project Link: <https://github.com/jakobbuch/scienceplots-toolkit>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
scienceplots_toolkit/__init__.py,sha256=ebbrkttVMcVAMA5fHINki7KQcAYbak-SK1mHlKaT4pI,1386
|
|
2
|
+
scienceplots_toolkit/analysis.py,sha256=eZ8Bzu_q3AfEaoVYXz90Sqr6oycOeIPXUeXuw891CHI,1794
|
|
3
|
+
scienceplots_toolkit/style.py,sha256=Wqwcc4sBvmqV_srJyxEUS8dqZgmQ8k0N_DXuoekQ5vk,6044
|
|
4
|
+
scienceplots_toolkit/utils.py,sha256=roFZhXvn7_txMkXJKFI5Wof_gJDXt8HHfygzIbSDLdg,2534
|
|
5
|
+
scienceplots_toolkit-0.1.1.dist-info/METADATA,sha256=hZ52Bwck5ouJEmHccSbPXW-3rS2ZJ6m2FwnZ2bKxXWA,7504
|
|
6
|
+
scienceplots_toolkit-0.1.1.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
7
|
+
scienceplots_toolkit-0.1.1.dist-info/licenses/LICENSE,sha256=5A1dCM0wc9ndzCo5UbXkLck-2lOqwicsKeutpYeQ2Cg,1411
|
|
8
|
+
scienceplots_toolkit-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jakob Buchmeier
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Acknowledgments
|
|
26
|
+
|
|
27
|
+
This package builds upon the excellent [SciencePlots](https://github.com/garrettj403/SciencePlots)
|
|
28
|
+
library by John Garrett, which is also licensed under the MIT License.
|
|
29
|
+
|
|
30
|
+
SciencePlots provides Matplotlib styles for publication-quality plots.
|
|
31
|
+
For more information, see: https://github.com/garrettj403/SciencePlots
|