roms-tools 2.6.2__py3-none-any.whl → 2.7.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.
- roms_tools/__init__.py +1 -0
- roms_tools/analysis/roms_output.py +11 -77
- roms_tools/analysis/utils.py +0 -66
- roms_tools/constants.py +2 -0
- roms_tools/download.py +46 -3
- roms_tools/plot.py +22 -5
- roms_tools/setup/cdr_forcing.py +1126 -0
- roms_tools/setup/datasets.py +742 -87
- roms_tools/setup/grid.py +42 -4
- roms_tools/setup/river_forcing.py +11 -84
- roms_tools/setup/tides.py +81 -411
- roms_tools/setup/utils.py +241 -37
- roms_tools/tests/test_setup/test_cdr_forcing.py +772 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/.zmetadata +53 -1
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/river_tracer/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_long_name/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_long_name/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_long_name/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_unit/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_unit/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing_no_climatology.zarr/tracer_unit/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/.zmetadata +53 -1
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/river_tracer/.zattrs +1 -1
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_long_name/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_long_name/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_long_name/0 +0 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_unit/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_unit/.zattrs +6 -0
- roms_tools/tests/test_setup/test_data/river_forcing_with_bgc.zarr/tracer_unit/0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/.zattrs +1 -2
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/.zmetadata +27 -5
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ntides/.zarray +20 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ntides/.zattrs +5 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ntides/0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/omega/.zattrs +1 -3
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/pot_Im/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/pot_Re/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ssh_Im/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/ssh_Re/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Im/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/u_Re/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Im/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_data/tidal_forcing.zarr/v_Re/0.0.0 +0 -0
- roms_tools/tests/test_setup/test_datasets.py +103 -1
- roms_tools/tests/test_setup/test_tides.py +112 -47
- roms_tools/utils.py +115 -1
- {roms_tools-2.6.2.dist-info → roms_tools-2.7.0.dist-info}/METADATA +1 -1
- {roms_tools-2.6.2.dist-info → roms_tools-2.7.0.dist-info}/RECORD +51 -33
- {roms_tools-2.6.2.dist-info → roms_tools-2.7.0.dist-info}/WHEEL +1 -1
- {roms_tools-2.6.2.dist-info → roms_tools-2.7.0.dist-info}/licenses/LICENSE +0 -0
- {roms_tools-2.6.2.dist-info → roms_tools-2.7.0.dist-info}/top_level.txt +0 -0
roms_tools/__init__.py
CHANGED
|
@@ -14,6 +14,7 @@ from roms_tools.setup.surface_forcing import SurfaceForcing # noqa: F401
|
|
|
14
14
|
from roms_tools.setup.initial_conditions import InitialConditions # noqa: F401
|
|
15
15
|
from roms_tools.setup.boundary_forcing import BoundaryForcing # noqa: F401
|
|
16
16
|
from roms_tools.setup.river_forcing import RiverForcing # noqa: F401
|
|
17
|
+
from roms_tools.setup.cdr_forcing import CDRVolumePointSource # noqa: F401
|
|
17
18
|
from roms_tools.setup.nesting import ChildGrid # noqa: F401
|
|
18
19
|
from roms_tools.tiling.partition import partition_netcdf # noqa: F401
|
|
19
20
|
from roms_tools.analysis.roms_output import ROMSOutput # noqa: F401
|
|
@@ -2,7 +2,6 @@ import xarray as xr
|
|
|
2
2
|
import numpy as np
|
|
3
3
|
import matplotlib.pyplot as plt
|
|
4
4
|
from roms_tools.plot import _plot, _section_plot, _profile_plot, _line_plot
|
|
5
|
-
from roms_tools.utils import _load_data
|
|
6
5
|
from roms_tools.regrid import LateralRegridFromROMS, VerticalRegridFromROMS
|
|
7
6
|
from dataclasses import dataclass, field
|
|
8
7
|
from typing import Union, Optional
|
|
@@ -15,8 +14,14 @@ from roms_tools import Grid
|
|
|
15
14
|
from roms_tools.vertical_coordinate import (
|
|
16
15
|
compute_depth_coordinates,
|
|
17
16
|
)
|
|
18
|
-
from roms_tools.utils import
|
|
19
|
-
|
|
17
|
+
from roms_tools.utils import (
|
|
18
|
+
_load_data,
|
|
19
|
+
interpolate_from_rho_to_u,
|
|
20
|
+
interpolate_from_rho_to_v,
|
|
21
|
+
_generate_coordinate_range,
|
|
22
|
+
_remove_edge_nans,
|
|
23
|
+
)
|
|
24
|
+
from roms_tools.analysis.utils import _validate_plot_inputs
|
|
20
25
|
|
|
21
26
|
|
|
22
27
|
@dataclass(kw_only=True)
|
|
@@ -301,7 +306,7 @@ class ROMSOutput:
|
|
|
301
306
|
lats = [lat]
|
|
302
307
|
title = title + f", lat = {lat}°N"
|
|
303
308
|
else:
|
|
304
|
-
resolution = self._infer_nominal_horizontal_resolution()
|
|
309
|
+
resolution = self.grid._infer_nominal_horizontal_resolution()
|
|
305
310
|
lats = _generate_coordinate_range(
|
|
306
311
|
field.lat.min().values, field.lat.max().values, resolution
|
|
307
312
|
)
|
|
@@ -311,7 +316,7 @@ class ROMSOutput:
|
|
|
311
316
|
lons = [lon]
|
|
312
317
|
title = title + f", lon = {lon}°E"
|
|
313
318
|
else:
|
|
314
|
-
resolution = self._infer_nominal_horizontal_resolution(lat)
|
|
319
|
+
resolution = self.grid._infer_nominal_horizontal_resolution(lat)
|
|
315
320
|
lons = _generate_coordinate_range(
|
|
316
321
|
field.lon.min().values, field.lon.max().values, resolution
|
|
317
322
|
)
|
|
@@ -327,33 +332,6 @@ class ROMSOutput:
|
|
|
327
332
|
if compute_layer_depth:
|
|
328
333
|
field = field.assign_coords({"layer_depth": layer_depth})
|
|
329
334
|
|
|
330
|
-
def _remove_edge_nans(field, xdim, layer_depth=None):
|
|
331
|
-
"""Removes NaNs from the edges along the specified dimension."""
|
|
332
|
-
if xdim in field.dims:
|
|
333
|
-
if layer_depth is not None:
|
|
334
|
-
nan_mask = layer_depth.isnull().sum(
|
|
335
|
-
dim=[dim for dim in layer_depth.dims if dim != xdim]
|
|
336
|
-
)
|
|
337
|
-
else:
|
|
338
|
-
nan_mask = field.isnull().sum(
|
|
339
|
-
dim=[dim for dim in field.dims if dim != xdim]
|
|
340
|
-
)
|
|
341
|
-
|
|
342
|
-
# Find the valid indices where the sum of the nans is 0
|
|
343
|
-
valid_indices = np.where(nan_mask.values == 0)[0]
|
|
344
|
-
|
|
345
|
-
if len(valid_indices) > 0:
|
|
346
|
-
first_valid = valid_indices[0]
|
|
347
|
-
last_valid = valid_indices[-1]
|
|
348
|
-
|
|
349
|
-
field = field.isel({xdim: slice(first_valid, last_valid + 1)})
|
|
350
|
-
if layer_depth is not None:
|
|
351
|
-
layer_depth = layer_depth.isel(
|
|
352
|
-
{xdim: slice(first_valid, last_valid + 1)}
|
|
353
|
-
)
|
|
354
|
-
|
|
355
|
-
return field, layer_depth
|
|
356
|
-
|
|
357
335
|
if lat is not None:
|
|
358
336
|
field, layer_depth = _remove_edge_nans(
|
|
359
337
|
field, "lon", layer_depth if "layer_depth" in locals() else None
|
|
@@ -459,7 +437,7 @@ class ROMSOutput:
|
|
|
459
437
|
lon_deg = xr.where(lon_deg > 180, lon_deg - 360, lon_deg)
|
|
460
438
|
|
|
461
439
|
if horizontal_resolution is None:
|
|
462
|
-
horizontal_resolution = self._infer_nominal_horizontal_resolution()
|
|
440
|
+
horizontal_resolution = self.grid._infer_nominal_horizontal_resolution()
|
|
463
441
|
lons = _generate_coordinate_range(
|
|
464
442
|
lon_deg.min().values, lon_deg.max().values, horizontal_resolution
|
|
465
443
|
)
|
|
@@ -809,50 +787,6 @@ class ROMSOutput:
|
|
|
809
787
|
ds = ds.assign_coords(coords_to_add)
|
|
810
788
|
return ds
|
|
811
789
|
|
|
812
|
-
def _infer_nominal_horizontal_resolution(self, lat=None):
|
|
813
|
-
"""Estimate the nominal horizontal resolution of the grid in degrees at a
|
|
814
|
-
specified latitude.
|
|
815
|
-
|
|
816
|
-
This method calculates the nominal horizontal resolution of the grid by first
|
|
817
|
-
determining the average grid spacing in meters. The spacing is then converted
|
|
818
|
-
to degrees, accounting for the Earth's curvature, and the latitude where the
|
|
819
|
-
resolution is being computed.
|
|
820
|
-
|
|
821
|
-
Parameters
|
|
822
|
-
----------
|
|
823
|
-
lat : float, optional
|
|
824
|
-
Latitude (in degrees) at which to estimate the horizontal resolution.
|
|
825
|
-
If not provided, the resolution is calculated at the average latitude of
|
|
826
|
-
the grid (`lat_rho`).
|
|
827
|
-
|
|
828
|
-
Returns
|
|
829
|
-
-------
|
|
830
|
-
float
|
|
831
|
-
The estimated horizontal resolution in degrees, adjusted for the Earth's curvature.
|
|
832
|
-
"""
|
|
833
|
-
# Earth radius in meters
|
|
834
|
-
r_earth = 6371315.0
|
|
835
|
-
|
|
836
|
-
if lat is None:
|
|
837
|
-
# Center latitude in degrees
|
|
838
|
-
lat = (self.grid.ds.lat_rho.max() + self.grid.ds.lat_rho.min()) / 2
|
|
839
|
-
|
|
840
|
-
# Convert latitude to radians
|
|
841
|
-
lat_rad = np.deg2rad(lat)
|
|
842
|
-
|
|
843
|
-
# Mean resolution in meters
|
|
844
|
-
resolution_in_m = (
|
|
845
|
-
(1 / self.grid.ds.pm).mean() + (1 / self.grid.ds.pn).mean()
|
|
846
|
-
) / 2
|
|
847
|
-
|
|
848
|
-
# Meters per degree at the equator
|
|
849
|
-
meters_per_degree = 2 * np.pi * r_earth / 360
|
|
850
|
-
|
|
851
|
-
# Correct for latitude by multiplying by cos(latitude) for longitude
|
|
852
|
-
resolution_in_degrees = resolution_in_m / (meters_per_degree * np.cos(lat_rad))
|
|
853
|
-
|
|
854
|
-
return resolution_in_degrees
|
|
855
|
-
|
|
856
790
|
def _compute_exponential_depth_levels(self, Nz=None, depth=None, h=None):
|
|
857
791
|
"""Compute vertical grid center and face depths using an exponential profile.
|
|
858
792
|
|
roms_tools/analysis/utils.py
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
|
|
3
|
-
|
|
4
1
|
def _validate_plot_inputs(field, s, eta, xi, depth, lat, lon, include_boundary):
|
|
5
2
|
"""Validate input parameters for the plot method.
|
|
6
3
|
|
|
@@ -104,66 +101,3 @@ def _validate_plot_inputs(field, s, eta, xi, depth, lat, lon, include_boundary):
|
|
|
104
101
|
f"Invalid xi index: {xi} lies on the boundary, which is excluded when `include_boundary = False`. "
|
|
105
102
|
"Either set `include_boundary = True`, or adjust eta to avoid boundary values."
|
|
106
103
|
)
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
def _generate_coordinate_range(min, max, resolution):
|
|
110
|
-
"""Generate an array of target coordinates (e.g., latitude or longitude) within a
|
|
111
|
-
specified range, with a resolution that is rounded to the nearest value of the form
|
|
112
|
-
`1/n` (or integer).
|
|
113
|
-
|
|
114
|
-
This method generates an array of target coordinates between the provided `min` and `max`
|
|
115
|
-
values, ensuring that both `min` and `max` are included in the resulting range. The resolution
|
|
116
|
-
is rounded to the nearest fraction of the form `1/n` or an integer, based on the input.
|
|
117
|
-
|
|
118
|
-
Parameters
|
|
119
|
-
----------
|
|
120
|
-
min : float
|
|
121
|
-
The minimum value (in degrees) of the coordinate range (inclusive).
|
|
122
|
-
|
|
123
|
-
max : float
|
|
124
|
-
The maximum value (in degrees) of the coordinate range (inclusive).
|
|
125
|
-
|
|
126
|
-
resolution : float
|
|
127
|
-
The spacing (in degrees) between each coordinate in the array. The resolution will
|
|
128
|
-
be rounded to the nearest value of the form `1/n` or an integer, depending on the size
|
|
129
|
-
of the resolution value.
|
|
130
|
-
|
|
131
|
-
Returns
|
|
132
|
-
-------
|
|
133
|
-
numpy.ndarray
|
|
134
|
-
An array of target coordinates generated from the specified range, with the resolution
|
|
135
|
-
rounded to a suitable fraction (e.g., `1/n`) or integer, depending on the input resolution.
|
|
136
|
-
"""
|
|
137
|
-
|
|
138
|
-
# Find the closest fraction of the form 1/n or integer to match the resolution
|
|
139
|
-
resolution_rounded = None
|
|
140
|
-
min_diff = float("inf") # Initialize the minimum difference as infinity
|
|
141
|
-
|
|
142
|
-
# Search for the best fraction or integer approximation to the resolution
|
|
143
|
-
for n in range(1, 1000): # Try fractions 1/n, where n ranges from 1 to 999
|
|
144
|
-
if resolution <= 1:
|
|
145
|
-
fraction = (
|
|
146
|
-
1 / n
|
|
147
|
-
) # For small resolutions (<= 1), consider fractions of the form 1/n
|
|
148
|
-
else:
|
|
149
|
-
fraction = n # For larger resolutions (>1), consider integers (n)
|
|
150
|
-
|
|
151
|
-
diff = abs(
|
|
152
|
-
fraction - resolution
|
|
153
|
-
) # Calculate the difference between the fraction and the resolution
|
|
154
|
-
|
|
155
|
-
if diff < min_diff: # If the current fraction is a better approximation
|
|
156
|
-
min_diff = diff
|
|
157
|
-
resolution_rounded = fraction # Update the best fraction (or integer) found
|
|
158
|
-
|
|
159
|
-
# Adjust the start and end of the range to include integer values
|
|
160
|
-
start_int = np.floor(min) # Round the minimum value down to the nearest integer
|
|
161
|
-
end_int = np.ceil(max) # Round the maximum value up to the nearest integer
|
|
162
|
-
|
|
163
|
-
# Generate the array of target coordinates, including both the min and max values
|
|
164
|
-
target = np.arange(start_int, end_int + resolution_rounded, resolution_rounded)
|
|
165
|
-
|
|
166
|
-
# Truncate any values that exceed max (including small floating point errors)
|
|
167
|
-
target = target[target <= end_int + 1e-10]
|
|
168
|
-
|
|
169
|
-
return target.astype(np.float32)
|
roms_tools/constants.py
ADDED
roms_tools/download.py
CHANGED
|
@@ -22,7 +22,7 @@ correction_data = pooch.create(
|
|
|
22
22
|
},
|
|
23
23
|
)
|
|
24
24
|
|
|
25
|
-
# Create a Pooch object to manage the global
|
|
25
|
+
# Create a Pooch object to manage the global river data
|
|
26
26
|
river_data = pooch.create(
|
|
27
27
|
# Use the default cache folder for the operating system
|
|
28
28
|
path=pooch.os_cache("roms-tools"),
|
|
@@ -32,6 +32,18 @@ river_data = pooch.create(
|
|
|
32
32
|
"dai_trenberth_may2019.nc": "sha256:793849e6aa60d1f6bdb480c345515fb2453d903c0a30599241b3d752f53715ab",
|
|
33
33
|
},
|
|
34
34
|
)
|
|
35
|
+
|
|
36
|
+
# Create a Pooch object to manage the global SAL TPXO data
|
|
37
|
+
sal_data = pooch.create(
|
|
38
|
+
# Use the default cache folder for the operating system
|
|
39
|
+
path=pooch.os_cache("roms-tools"),
|
|
40
|
+
base_url="https://github.com/CWorthy-ocean/roms-tools-data/raw/main/",
|
|
41
|
+
# The registry specifies the files that can be fetched
|
|
42
|
+
registry={
|
|
43
|
+
"sal_tpxo9.v2a.nc": "sha256:5343d745b4374170a069bfc2c67dcdd9f1dc4eb0df7c0e6de5c004432c903f40",
|
|
44
|
+
},
|
|
45
|
+
)
|
|
46
|
+
|
|
35
47
|
# Create a Pooch object to manage the test data
|
|
36
48
|
pup_test_data = pooch.create(
|
|
37
49
|
# Use the default cache folder for the operating system
|
|
@@ -46,8 +58,19 @@ pup_test_data = pooch.create(
|
|
|
46
58
|
"GLORYS_NA_20121231.nc": "03c1155087195deff76ad3f136d6a7f35bc01ccae3402f3d95557a2886d39e71",
|
|
47
59
|
"ERA5_regional_test_data.nc": "bd12ce3b562fbea2a80a3b79ba74c724294043c28dc98ae092ad816d74eac794",
|
|
48
60
|
"ERA5_global_test_data.nc": "8ed177ab64c02caf509b9fb121cf6713f286cc603b1f302f15f3f4eb0c21dc4f",
|
|
49
|
-
"
|
|
50
|
-
"
|
|
61
|
+
"global_grid_tpxo10.v2.nc": "26eb97cd135cd6f2b4e894c5f11bf7f860ff19cec8dbaa9190e37d30ee6e744e",
|
|
62
|
+
"global_h_tpxo10.v2.nc": "ef60fae6d52fa514dcc59a737435d74aa798dc114b57f01b123aa39dbaffc592",
|
|
63
|
+
"global_u_tpxo10.v2.nc": "022e57e6287e51f52eb1e5296614b1086e0e22ecd0bd57c9fd8d0e155babf5c3",
|
|
64
|
+
"regional_grid_tpxo10v2a.nc": "c5022bfe93ead7cd46e836578645bd87cb5be63c736e660937c7f5703c968cbc",
|
|
65
|
+
"regional_h_tpxo10.v2.nc": "202fd0c197490ac460af12cd9fa1156aa40023c0023c705f145c596de5b5ad3d",
|
|
66
|
+
"regional_grid_tpxo10v2.nc": "0789b6a24ecb2ced522481dfcfb7282e32f999984747b9b9f46f044a8898d0ac",
|
|
67
|
+
"regional_grid_tpxo9v5a.nc": "497a2ae9e6adc7e4b06408dadb57734e2ad24afaa3f0e2e4fd90ebc6eafc2557",
|
|
68
|
+
"regional_h_tpxo10v2a.nc": "2df2f181f748a960e4072f975226f6f98f6a6c4d5b77da23057946585152d59c",
|
|
69
|
+
"regional_h_tpxo10v2.nc": "202fd0c197490ac460af12cd9fa1156aa40023c0023c705f145c596de5b5ad3d",
|
|
70
|
+
"regional_h_tpxo9v5a.nc": "c7e4d9ab73bc11dcb415f88c48131531488e1aed5113df5797e80d3d374607fc",
|
|
71
|
+
"regional_u_tpxo10v2a.nc": "2d1680ecd53242e858281a762221d91827999967f8e1f3cb7de3d23b47efe8c8",
|
|
72
|
+
"regional_u_tpxo10v2.nc": "3b0849473cbb7f9076ca907e4fc39eceda3c7d64659c121fa0692024d59dcdb3",
|
|
73
|
+
"regional_u_tpxo9v5a.nc": "b0cc5f6934d2e212549c7120d458d61a4963ba73d17055e67cc9e4312901b041",
|
|
51
74
|
"CESM_BGC_coarse_global_clim.nc": "20806e4e99285d6de168d3236e2d9245f4e9106474b1464beaa266a73e6ef79f",
|
|
52
75
|
"CESM_BGC_2012.nc": "e374d5df3c1be742d564fd26fd861c2d40af73be50a432c51d258171d5638eb6",
|
|
53
76
|
"CESM_regional_test_data_one_time_slice.nc": "43b578ecc067c85f95d6b97ed7b9dc8da7846f07c95331c6ba7f4a3161036a17",
|
|
@@ -127,6 +150,26 @@ def download_correction_data(filename: str) -> str:
|
|
|
127
150
|
return fname
|
|
128
151
|
|
|
129
152
|
|
|
153
|
+
def download_sal_data(filename: str) -> str:
|
|
154
|
+
"""Download the SAL data file.
|
|
155
|
+
|
|
156
|
+
Parameters
|
|
157
|
+
----------
|
|
158
|
+
filename : str
|
|
159
|
+
The name of the test data file to be downloaded. Available options:
|
|
160
|
+
- "sal_tpxo9.v2a.nc"
|
|
161
|
+
|
|
162
|
+
Returns
|
|
163
|
+
-------
|
|
164
|
+
str
|
|
165
|
+
The path to the downloaded test data file.
|
|
166
|
+
"""
|
|
167
|
+
# Fetch the file using Pooch, downloading if necessary
|
|
168
|
+
fname = sal_data.fetch(filename)
|
|
169
|
+
|
|
170
|
+
return fname
|
|
171
|
+
|
|
172
|
+
|
|
130
173
|
def download_test_data(filename: str) -> str:
|
|
131
174
|
"""Download the test data file.
|
|
132
175
|
|
roms_tools/plot.py
CHANGED
|
@@ -11,7 +11,9 @@ def _plot(
|
|
|
11
11
|
title="",
|
|
12
12
|
with_dim_names=False,
|
|
13
13
|
plot_data=True,
|
|
14
|
+
add_colorbar=True,
|
|
14
15
|
kwargs={},
|
|
16
|
+
ax=None,
|
|
15
17
|
):
|
|
16
18
|
"""Plots a grid or field on a map with optional depth contours.
|
|
17
19
|
|
|
@@ -30,13 +32,17 @@ def _plot(
|
|
|
30
32
|
plot_data : bool, optional
|
|
31
33
|
If True, plots the provided field data on the map. If False, only the grid
|
|
32
34
|
boundaries and optional depth contours are plotted. Default is True.
|
|
35
|
+
add_colorbar : bool, optional
|
|
36
|
+
If True, add colobar.
|
|
33
37
|
kwargs : dict, optional
|
|
34
38
|
Additional keyword arguments to pass to `pcolormesh` (e.g., colormap or color limits).
|
|
39
|
+
ax : matplotlib.axes.Axes, optional
|
|
40
|
+
Pre-existing axes to draw the plot on. If None, a new figure and axes are created.
|
|
35
41
|
|
|
36
42
|
Returns
|
|
37
43
|
-------
|
|
38
44
|
matplotlib.figure.Figure
|
|
39
|
-
The generated figure with the plotted data.
|
|
45
|
+
The generated figure with the plotted data, if a new figure was created.
|
|
40
46
|
|
|
41
47
|
Raises
|
|
42
48
|
------
|
|
@@ -56,18 +62,27 @@ def _plot(
|
|
|
56
62
|
|
|
57
63
|
trans = _get_projection(lon_deg, lat_deg)
|
|
58
64
|
|
|
65
|
+
if ax is None:
|
|
66
|
+
fig, ax = plt.subplots(1, 1, figsize=(13, 7), subplot_kw={"projection": trans})
|
|
67
|
+
|
|
59
68
|
lon_deg = lon_deg.values
|
|
60
69
|
lat_deg = lat_deg.values
|
|
61
70
|
|
|
62
|
-
fig, ax = plt.subplots(1, 1, figsize=(13, 7), subplot_kw={"projection": trans})
|
|
63
|
-
|
|
64
71
|
if c is not None:
|
|
65
72
|
_add_boundary_to_ax(
|
|
66
73
|
ax, lon_deg, lat_deg, trans, c, with_dim_names=with_dim_names
|
|
67
74
|
)
|
|
68
75
|
|
|
69
76
|
if plot_data:
|
|
70
|
-
_add_field_to_ax(
|
|
77
|
+
_add_field_to_ax(
|
|
78
|
+
ax,
|
|
79
|
+
lon_deg,
|
|
80
|
+
lat_deg,
|
|
81
|
+
field,
|
|
82
|
+
depth_contours,
|
|
83
|
+
add_colorbar=add_colorbar,
|
|
84
|
+
kwargs=kwargs,
|
|
85
|
+
)
|
|
71
86
|
|
|
72
87
|
ax.coastlines(
|
|
73
88
|
resolution="50m", linewidth=0.5, color="black"
|
|
@@ -90,7 +105,9 @@ def _plot(
|
|
|
90
105
|
|
|
91
106
|
ax.set_title(title)
|
|
92
107
|
|
|
93
|
-
return fig
|
|
108
|
+
# Only return fig if it was created inside the function (i.e., ax was not provided)
|
|
109
|
+
if ax is None:
|
|
110
|
+
return fig
|
|
94
111
|
|
|
95
112
|
|
|
96
113
|
def _plot_nesting(parent_grid_ds, child_grid_ds, parent_straddle, with_dim_names=False):
|