climplot 0.1.0__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.
climplot/style.py ADDED
@@ -0,0 +1,201 @@
1
+ """
2
+ Style management for publication and presentation figures.
3
+
4
+ This module provides functions to configure matplotlib for publication-quality
5
+ or presentation-quality figures with appropriate font sizes, DPI, and other
6
+ settings.
7
+
8
+ Examples
9
+ --------
10
+ >>> import climplot
11
+ >>> climplot.publication() # For journal figures
12
+ >>> climplot.presentation() # For slides/posters
13
+ """
14
+
15
+ import matplotlib.pyplot as plt
16
+ from pathlib import Path
17
+ from typing import Optional
18
+
19
+ # Track current mode
20
+ _current_mode: Optional[str] = None
21
+
22
+ # Style file directory
23
+ _STYLE_DIR = Path(__file__).parent / "data"
24
+
25
+
26
+ def publication(
27
+ width: float = 3.5,
28
+ for_pdf: bool = False,
29
+ font_family: Optional[str] = None,
30
+ ):
31
+ """
32
+ Configure matplotlib for publication-quality figures.
33
+
34
+ Sets up small font sizes and high DPI appropriate for journal figures.
35
+ Single-column figures are 3.5 inches wide (89 mm).
36
+
37
+ Parameters
38
+ ----------
39
+ width : float, optional
40
+ Default figure width in inches. Default is 3.5 (single-column).
41
+ Use 7.0 for two-column figures.
42
+ for_pdf : bool, optional
43
+ If True, configure for PDF output with embedded fonts.
44
+ Uses Myriad Pro font family by default.
45
+ font_family : str, optional
46
+ Font family to use. If None and for_pdf=True, uses 'Myriad Pro'.
47
+
48
+ Examples
49
+ --------
50
+ >>> import climplot
51
+ >>> climplot.publication() # Standard PNG output
52
+ >>> climplot.publication(for_pdf=True) # PDF with embedded fonts
53
+ >>> climplot.publication(width=7.0) # Two-column width
54
+
55
+ Notes
56
+ -----
57
+ Publication mode settings:
58
+ - Figure width: 3.5" (single-column) or 7.0" (two-column)
59
+ - DPI: 300
60
+ - Axis labels: 10 pt
61
+ - Tick labels: 8 pt
62
+ - Title: 11 pt
63
+ - Legend: 8 pt
64
+ """
65
+ global _current_mode
66
+
67
+ settings = {
68
+ # Font sizes (publication: smaller, dense)
69
+ "font.size": 10,
70
+ "axes.labelsize": 10,
71
+ "axes.titlesize": 11,
72
+ "xtick.labelsize": 8,
73
+ "ytick.labelsize": 8,
74
+ "legend.fontsize": 8,
75
+ # Figure settings
76
+ "figure.figsize": (width, width * 0.75),
77
+ "figure.dpi": 300,
78
+ "savefig.dpi": 300,
79
+ "savefig.bbox": "tight",
80
+ "savefig.facecolor": "white",
81
+ # Line widths
82
+ "axes.linewidth": 0.8,
83
+ "grid.linewidth": 0.3,
84
+ "lines.linewidth": 1.5,
85
+ # PDF settings
86
+ "pdf.fonttype": 42, # TrueType for editability
87
+ }
88
+
89
+ if for_pdf:
90
+ if font_family is None:
91
+ font_family = "Myriad Pro"
92
+ settings["font.family"] = font_family
93
+
94
+ plt.rcParams.update(settings)
95
+ _current_mode = "publication"
96
+
97
+
98
+ def presentation(
99
+ width: float = 7.0,
100
+ for_pdf: bool = False,
101
+ font_family: Optional[str] = None,
102
+ ):
103
+ """
104
+ Configure matplotlib for presentation-quality figures.
105
+
106
+ Sets up larger font sizes and moderate DPI appropriate for slides
107
+ and posters. Default width is 7.0 inches for good visibility.
108
+
109
+ Parameters
110
+ ----------
111
+ width : float, optional
112
+ Default figure width in inches. Default is 7.0.
113
+ for_pdf : bool, optional
114
+ If True, configure for PDF output with embedded fonts.
115
+ font_family : str, optional
116
+ Font family to use. If None and for_pdf=True, uses 'Myriad Pro'.
117
+
118
+ Examples
119
+ --------
120
+ >>> import climplot
121
+ >>> climplot.presentation() # Standard output
122
+ >>> climplot.presentation(for_pdf=True) # PDF for slides
123
+
124
+ Notes
125
+ -----
126
+ Presentation mode settings:
127
+ - Figure width: 7.0" (full slide width)
128
+ - DPI: 150
129
+ - Axis labels: 14 pt
130
+ - Tick labels: 14 pt
131
+ - Title: 16 pt
132
+ - Legend: 12 pt
133
+ """
134
+ global _current_mode
135
+
136
+ settings = {
137
+ # Font sizes (presentation: larger, readable)
138
+ "font.size": 14,
139
+ "axes.labelsize": 14,
140
+ "axes.titlesize": 16,
141
+ "xtick.labelsize": 14,
142
+ "ytick.labelsize": 14,
143
+ "legend.fontsize": 12,
144
+ # Figure settings
145
+ "figure.figsize": (width, width * 0.6),
146
+ "figure.dpi": 150,
147
+ "savefig.dpi": 150,
148
+ "savefig.bbox": "tight",
149
+ "savefig.facecolor": "white",
150
+ # Line widths (thicker for visibility)
151
+ "axes.linewidth": 1.2,
152
+ "grid.linewidth": 0.5,
153
+ "lines.linewidth": 2.5,
154
+ # PDF settings
155
+ "pdf.fonttype": 42,
156
+ }
157
+
158
+ if for_pdf:
159
+ if font_family is None:
160
+ font_family = "Myriad Pro"
161
+ settings["font.family"] = font_family
162
+
163
+ plt.rcParams.update(settings)
164
+ _current_mode = "presentation"
165
+
166
+
167
+ def reset_style():
168
+ """
169
+ Reset matplotlib to default settings.
170
+
171
+ Restores all rcParams to their default values and clears the
172
+ current mode tracker.
173
+
174
+ Examples
175
+ --------
176
+ >>> climplot.publication()
177
+ >>> # ... make some figures ...
178
+ >>> climplot.reset_style() # Back to defaults
179
+ """
180
+ global _current_mode
181
+
182
+ plt.rcdefaults()
183
+ _current_mode = None
184
+
185
+
186
+ def get_current_mode() -> Optional[str]:
187
+ """
188
+ Get the currently active style mode.
189
+
190
+ Returns
191
+ -------
192
+ str or None
193
+ 'publication', 'presentation', or None if no mode is set.
194
+
195
+ Examples
196
+ --------
197
+ >>> climplot.publication()
198
+ >>> climplot.get_current_mode()
199
+ 'publication'
200
+ """
201
+ return _current_mode
climplot/timeseries.py ADDED
@@ -0,0 +1,110 @@
1
+ """
2
+ Time series plotting utilities.
3
+
4
+ This module provides functions for creating publication-quality time series
5
+ plots with consistent styling.
6
+
7
+ Examples
8
+ --------
9
+ >>> import climplot
10
+ >>> climplot.publication()
11
+ >>> fig, ax = climplot.timeseries_figure()
12
+ >>> ax.plot(time, data)
13
+ """
14
+
15
+ import matplotlib.pyplot as plt
16
+ from typing import Tuple, Optional
17
+
18
+
19
+ # Standard colors for model configurations
20
+ CONFIG_COLORS = {
21
+ "obs": "#000000", # Black - observations
22
+ "model": "#1f77b4", # Blue - default model
23
+ "model1": "#1f77b4", # Blue
24
+ "model2": "#ff7f0e", # Orange
25
+ "model3": "#2ca02c", # Green
26
+ "model4": "#d62728", # Red
27
+ "model5": "#9467bd", # Purple
28
+ }
29
+
30
+ # Standard line styles
31
+ CONFIG_LINESTYLES = {
32
+ "obs": "--", # Dashed for observations
33
+ "model": "-", # Solid for models
34
+ "model1": "-",
35
+ "model2": "-",
36
+ "model3": "-",
37
+ "model4": "-",
38
+ "model5": "-",
39
+ }
40
+
41
+
42
+ def timeseries_figure(
43
+ figsize: Optional[Tuple[float, float]] = None,
44
+ grid: bool = True,
45
+ grid_alpha: float = 0.3,
46
+ **kwargs,
47
+ ) -> Tuple[plt.Figure, plt.Axes]:
48
+ """
49
+ Create a figure sized for time series plots.
50
+
51
+ Parameters
52
+ ----------
53
+ figsize : tuple, optional
54
+ Figure size (width, height) in inches. If None, uses (7.0, 3.5).
55
+ grid : bool, optional
56
+ Whether to add grid lines. Default is True.
57
+ grid_alpha : float, optional
58
+ Grid transparency. Default is 0.3.
59
+ **kwargs
60
+ Additional arguments passed to plt.subplots()
61
+
62
+ Returns
63
+ -------
64
+ fig : Figure
65
+ The figure object
66
+ ax : Axes
67
+ The axes object
68
+
69
+ Examples
70
+ --------
71
+ >>> fig, ax = climplot.timeseries_figure()
72
+ >>> ax.plot(time, data, label='Model')
73
+ >>> ax.set_xlabel('Year')
74
+ >>> ax.set_ylabel('Sea Level (m)')
75
+ >>> ax.legend()
76
+ """
77
+ if figsize is None:
78
+ figsize = (7.0, 3.5)
79
+
80
+ fig, ax = plt.subplots(figsize=figsize, **kwargs)
81
+
82
+ if grid:
83
+ ax.grid(True, alpha=grid_alpha, linewidth=0.3)
84
+
85
+ return fig, ax
86
+
87
+
88
+ def get_config_style(config: str) -> dict:
89
+ """
90
+ Get standard style parameters for a configuration name.
91
+
92
+ Parameters
93
+ ----------
94
+ config : str
95
+ Configuration name (e.g., 'obs', 'model', 'model1')
96
+
97
+ Returns
98
+ -------
99
+ dict
100
+ Style parameters with 'color' and 'linestyle' keys
101
+
102
+ Examples
103
+ --------
104
+ >>> style = get_config_style('obs')
105
+ >>> ax.plot(time, data, **style)
106
+ """
107
+ return {
108
+ "color": CONFIG_COLORS.get(config, "#1f77b4"),
109
+ "linestyle": CONFIG_LINESTYLES.get(config, "-"),
110
+ }
@@ -0,0 +1,198 @@
1
+ Metadata-Version: 2.4
2
+ Name: climplot
3
+ Version: 0.1.0
4
+ Summary: Publication-quality climate science plotting utilities
5
+ Author-email: John Krasting <john.krasting@noaa.gov>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/jkrasting/climplot
8
+ Project-URL: Documentation, https://climplot.readthedocs.io
9
+ Project-URL: Repository, https://github.com/jkrasting/climplot
10
+ Keywords: climate,plotting,visualization,cartopy,xarray,oceanography
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Science/Research
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Operating System :: OS Independent
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Topic :: Scientific/Engineering :: Atmospheric Science
20
+ Classifier: Topic :: Scientific/Engineering :: Visualization
21
+ Requires-Python: >=3.10
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: matplotlib>=3.7
25
+ Requires-Dist: numpy>=1.24
26
+ Requires-Dist: xarray>=2023.1
27
+ Requires-Dist: cartopy>=0.21
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7.0; extra == "dev"
30
+ Requires-Dist: pytest-cov>=4.0; extra == "dev"
31
+ Requires-Dist: black>=23.0; extra == "dev"
32
+ Requires-Dist: ruff>=0.1; extra == "dev"
33
+ Provides-Extra: docs
34
+ Requires-Dist: sphinx>=6.0; extra == "docs"
35
+ Requires-Dist: sphinx-rtd-theme>=1.3; extra == "docs"
36
+ Requires-Dist: sphinx-gallery>=0.14; extra == "docs"
37
+ Requires-Dist: nbsphinx>=0.9; extra == "docs"
38
+ Provides-Extra: all
39
+ Requires-Dist: climplot[dev,docs]; extra == "all"
40
+ Dynamic: license-file
41
+
42
+ # climplot
43
+
44
+ Publication-quality climate science plotting utilities for Python.
45
+
46
+ **Mission:** Help climate science beginners make beautiful, publication-ready plots with minimal effort.
47
+
48
+ ## Features
49
+
50
+ - **Style Modes**: Switch between publication and presentation styles with one function call
51
+ - **Climate Colormaps**: Discrete colormaps optimized for anomaly fields, with center-on-white option
52
+ - **Map Utilities**: Easy map creation with Cartopy projections
53
+ - **Multi-panel Figures**: Consistent panel labeling and colorbars
54
+ - **Area-weighted Metrics**: Accurate statistics for gridded climate data
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ pip install climplot
60
+ ```
61
+
62
+ Or install from source:
63
+
64
+ ```bash
65
+ git clone https://github.com/jkrasting/climplot.git
66
+ cd climplot
67
+ pip install -e .
68
+ ```
69
+
70
+ ## Quick Start
71
+
72
+ ```python
73
+ import climplot
74
+ import matplotlib.pyplot as plt
75
+
76
+ # Set publication style
77
+ climplot.publication()
78
+
79
+ # Create a map figure
80
+ fig, ax = climplot.map_figure()
81
+
82
+ # Plot with discrete colormap
83
+ cmap, norm, levels = climplot.anomaly_cmap(-0.3, 0.3, 0.05)
84
+ cs = ax.pcolormesh(lon, lat, data, cmap=cmap, norm=norm, transform=ccrs.PlateCarree())
85
+
86
+ # Add colorbar
87
+ climplot.add_colorbar(cs, ax, 'SSH Anomaly (m)')
88
+
89
+ # Save
90
+ climplot.save_figure('my_figure.png')
91
+ plt.close()
92
+ ```
93
+
94
+ ## Style Modes
95
+
96
+ ### Publication Mode
97
+ For journal figures with small, dense typography:
98
+ - 3.5" width (single-column), 7.0" (two-column)
99
+ - 8-11pt fonts
100
+ - 300 DPI
101
+
102
+ ```python
103
+ climplot.publication() # Single column
104
+ climplot.publication(width=7.0) # Two-column
105
+ climplot.publication(for_pdf=True) # PDF with embedded fonts
106
+ ```
107
+
108
+ ### Presentation Mode
109
+ For slides and posters with larger, readable typography:
110
+ - 7.0" width
111
+ - 12-16pt fonts
112
+ - 150 DPI
113
+
114
+ ```python
115
+ climplot.presentation()
116
+ climplot.presentation(for_pdf=True) # PDF for slides
117
+ ```
118
+
119
+ ## Colormaps
120
+
121
+ ### Anomaly Colormap
122
+ Red-blue diverging, centered on zero:
123
+
124
+ ```python
125
+ cmap, norm, levels = climplot.anomaly_cmap(-0.3, 0.3, 0.05)
126
+ ```
127
+
128
+ ### Center-on-White
129
+ For difference plots where near-zero values should appear neutral:
130
+
131
+ ```python
132
+ cmap, norm, levels = climplot.anomaly_cmap(-0.3, 0.3, 0.05, center_on_white=True)
133
+ ```
134
+
135
+ ## Maps
136
+
137
+ ```python
138
+ # Robinson projection (Pacific-centered)
139
+ fig, ax = climplot.map_figure()
140
+
141
+ # Atlantic-centered
142
+ fig, ax = climplot.map_figure(central_longitude=0)
143
+
144
+ # Different projection
145
+ fig, ax = climplot.map_figure(projection='mollweide')
146
+ ```
147
+
148
+ ## Multi-panel Figures
149
+
150
+ ```python
151
+ # 2x3 panel figure
152
+ fig, axes = climplot.panel_figure(2, 3)
153
+
154
+ # Add panel labels (a. b. c. etc.)
155
+ climplot.add_panel_labels(axes.flatten())
156
+
157
+ # Single colorbar below all panels
158
+ climplot.bottom_colorbar(cs, fig, axes, 'Temperature (K)')
159
+ ```
160
+
161
+ ## Area-weighted Metrics
162
+
163
+ **Why area weighting matters:** Simple averaging over-weights polar regions.
164
+ This can produce errors of ~1 cm in global sea level means.
165
+
166
+ ```python
167
+ import climplot
168
+
169
+ # Area-weighted mean (CORRECT)
170
+ gmsl = climplot.area_weighted_mean(ssh, areacello, dim=['yh', 'xh'])
171
+
172
+ # Simple mean (WRONG - ~1 cm error)
173
+ # gmsl = ssh.mean(dim=['yh', 'xh'])
174
+
175
+ # Other metrics
176
+ bias = climplot.area_weighted_bias(model, obs, areacello, dim=['yh', 'xh'])
177
+ rmse = climplot.area_weighted_rmse(model, obs, areacello, dim=['yh', 'xh'])
178
+ corr = climplot.area_weighted_corr(model, obs, areacello, dim=['yh', 'xh'])
179
+
180
+ # Comprehensive summary
181
+ metrics = climplot.metrics_summary(model, obs, areacello, dim=['yh', 'xh'])
182
+ climplot.print_metrics_summary(metrics, name='My Model')
183
+ ```
184
+
185
+ ## Dependencies
186
+
187
+ - matplotlib >= 3.7
188
+ - numpy >= 1.24
189
+ - xarray >= 2023.1
190
+ - cartopy >= 0.21
191
+
192
+ ## License
193
+
194
+ MIT License - see [LICENSE](LICENSE)
195
+
196
+ ## Contributing
197
+
198
+ Contributions are welcome! Please see our [contributing guide](CONTRIBUTING.md).
@@ -0,0 +1,14 @@
1
+ climplot/__init__.py,sha256=G2AtbrQNibpC_nTL7mQXtwxb-YR5GgOcywNmPM3kJv8,2399
2
+ climplot/colormaps.py,sha256=HGqJ97OO00joQt0txTXJ96OW6f7oAtAAzHSirA5dnSM,7351
3
+ climplot/maps.py,sha256=soGyPmfb1agkrFmW1W-Mh1z28gsrmtXKovd2n2DHk_Y,6412
4
+ climplot/metrics.py,sha256=6TT9owbt0Wpm5M_pSeAoeuTs2W230gOMAYEqHIprbVw,10486
5
+ climplot/panels.py,sha256=XRDUunjEMxE8WGuG8uiy_h8EahRkjkd3lbnCAfdbAG4,7375
6
+ climplot/style.py,sha256=h2eShIWmoEvJiAgYMZIp6_uT8cTY8CDAhMkcNkqGZGE,5253
7
+ climplot/timeseries.py,sha256=3GKaiLI1Mu8lk6dDSYtPFXB8PC5NA0-WhrO9qstP-xE,2564
8
+ climplot/data/presentation.mplstyle,sha256=7HglEd230iXcig3WlDpelzkIrDfEvE4BOS3mL5bpbS8,787
9
+ climplot/data/publication.mplstyle,sha256=yCPZbqRW2-ZK-00FXO_Ddzc-_lhQiYAKhftIcRrWIKY,771
10
+ climplot-0.1.0.dist-info/licenses/LICENSE,sha256=ZiKJpFHnFzvheHo0qXxeGQFJYayoUCGRr9WIE3AAemM,1070
11
+ climplot-0.1.0.dist-info/METADATA,sha256=q_eOT9SRaY_oDcskX-E-mb4qObDPAmirfCV_Bup7qgY,5316
12
+ climplot-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
13
+ climplot-0.1.0.dist-info/top_level.txt,sha256=3b48RU3qa_y6oEFVqhZn5X_RsePmwRRjkuOQD0myfdM,9
14
+ climplot-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 John Krasting
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.
@@ -0,0 +1 @@
1
+ climplot