Skip to content

Commit 15cc0e1

Browse files
Merge branch 'main' into add-tutorial-meca
2 parents 40a330d + 6a88408 commit 15cc0e1

21 files changed

+184
-59
lines changed

.github/workflows/ci_tests.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ jobs:
151151
GH_TOKEN: ${{ github.token }}
152152

153153
- name: Install uv
154-
uses: astral-sh/setup-uv@v5.2.2
154+
uses: astral-sh/setup-uv@v5.3.1
155155
with:
156156
python-version: ${{ matrix.python-version }}
157157

@@ -182,7 +182,7 @@ jobs:
182182

183183
# Upload coverage to Codecov
184184
- name: Upload coverage to Codecov
185-
uses: codecov/codecov-action@v5.3.1
185+
uses: codecov/codecov-action@v5.4.0
186186
if: success() || failure()
187187
with:
188188
use_oidc: true

pygmt/datasets/earth_age.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def load_earth_age(
4040
**@earth_age**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
4141
registration type (**p** for pixel registration, **g** for gridline registration).
4242
If *reg* is omitted (e.g., ``@earth_age_01d``), the gridline-registered grid will be
43-
loaded for grid proccessing functions and the pixel-registered grid will be loaded
43+
loaded for grid processing functions and the pixel-registered grid will be loaded
4444
for plotting functions. If *res* is also omitted (i.e., ``@earth_age``), GMT
4545
automatically selects a suitable resolution based on the current region and
4646
projection settings.

pygmt/datasets/earth_deflection.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def load_earth_deflection(
4949
the grid resolution; *reg* is the grid registration type (**p** for pixel
5050
registration, **g** for gridline registration). If *reg* is omitted (e.g.,
5151
``@earth_edefl_01d``), the gridline-registered grid will be loaded for grid
52-
proccessing functions and the pixel-registered grid will be loaded for plotting
52+
processing functions and the pixel-registered grid will be loaded for plotting
5353
functions. If *res* is also omitted (i.e., ``@earth_edefl``), GMT automatically
5454
selects a suitable resolution based on the current region and projection settings.
5555

pygmt/datasets/earth_dist.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def load_earth_dist(
4040
**@earth_dist**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
4141
registration type (**p** for pixel registration, **g** for gridline registration).
4242
If *reg* is omitted (e.g., ``@earth_dist_01d``), the gridline-registered grid will
43-
be loaded for grid proccessing functions and the pixel-registered grid will be
43+
be loaded for grid processing functions and the pixel-registered grid will be
4444
loaded for plotting functions. If *res* is also omitted (i.e., ``@earth_dist``), GMT
4545
automatically selects a suitable resolution based on the current region and
4646
projection settings.

pygmt/datasets/earth_free_air_anomaly.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def load_earth_free_air_anomaly(
4949
the grid resolution; *reg* is the grid registration type (**p** for pixel
5050
registration, **g** for gridline registration). If *reg* is omitted (e.g.,
5151
``@earth_faa_01d``), the gridline-registered grid will be loaded for grid
52-
proccessing functions and the pixel-registered grid will be loaded for plotting
52+
processing functions and the pixel-registered grid will be loaded for plotting
5353
functions. If *res* is also omitted (i.e., ``@earth_faa``), GMT automatically
5454
selects a suitable resolution based on the current region and projection settings.
5555

pygmt/datasets/earth_geoid.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def load_earth_geoid(
4040
**@earth_geoid**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
4141
registration type (**p** for pixel registration, **g** for gridline registration).
4242
If *reg* is omitted (e.g., ``@earth_geoid_01d``), the gridline-registered grid will
43-
be loaded for grid proccessing functions and the pixel-registered grid will be
43+
be loaded for grid processing functions and the pixel-registered grid will be
4444
loaded for plotting functions. If *res* is also omitted (i.e., ``@earth_geoid``),
4545
GMT automatically selects a suitable resolution based on the current region and
4646
projection settings.

pygmt/datasets/earth_magnetic_anomaly.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def load_earth_magnetic_anomaly(
4949
**earth_wdmam**; *res* is the grid resolution; *reg* is the grid
5050
registration type (**p** for pixel registration, **g** for gridline registration).
5151
If *reg* is omitted (e.g., ``@earth_mag_01d``), the gridline-registered grid will be
52-
loaded for grid proccessing functions and the pixel-registered grid will be loaded
52+
loaded for grid processing functions and the pixel-registered grid will be loaded
5353
for plotting functions. If *res* is also omitted (i.e., ``@earth_mag``), GMT
5454
automatically selects a suitable resolution based on the current region and
5555
projection settings.

pygmt/datasets/earth_mask.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def load_earth_mask(
5252
**@earth_mask**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
5353
registration type (**p** for pixel registration, **g** for gridline registration).
5454
If *reg* is omitted (e.g., ``@earth_mask_01d``), the gridline-registered grid will
55-
be loaded for grid proccessing functions and the pixel-registered grid will be
55+
be loaded for grid processing functions and the pixel-registered grid will be
5656
loaded for plotting functions. If *res* is also omitted (i.e., ``@earth_mask``), GMT
5757
automatically selects a suitable resolution based on the current region and
5858
projection settings.

pygmt/datasets/earth_mean_dynamic_topography.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def load_earth_mean_dynamic_topography(
3838
**@earth_mdt**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
3939
registration type (**p** for pixel registration, **g** for gridline registration).
4040
If *reg* is omitted (e.g., ``@earth_mdt_01d``), the gridline-registered grid will be
41-
loaded for grid proccessing functions and the pixel-registered grid will be loaded
41+
loaded for grid processing functions and the pixel-registered grid will be loaded
4242
for plotting functions. If *res* is also omitted (i.e., ``@earth_mdt``), GMT
4343
automatically selects a suitable resolution based on the current region and
4444
projection settings.

pygmt/datasets/earth_mean_sea_surface.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def load_earth_mean_sea_surface(
4040
**@earth_mss**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
4141
registration type (**p** for pixel registration, **g** for gridline registration).
4242
If *reg* is omitted (e.g., ``@earth_mss_01d``), the gridline-registered grid will be
43-
loaded for grid proccessing functions and the pixel-registered grid will be loaded
43+
loaded for grid processing functions and the pixel-registered grid will be loaded
4444
for plotting functions. If *res* is also omitted (i.e., ``@earth_mss``), GMT
4545
automatically selects a suitable resolution based on the current region and
4646
projection settings.

pygmt/datasets/earth_relief.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ def load_earth_relief(
6262
**earth_gebcosi**\, and **earth_synbath**\. *res* is the grid resolution; *reg* is
6363
the grid registration type (**p** for pixel registration, **g** for gridline
6464
registration). If *reg* is omitted (e.g., ``@earth_relief_01d``), the
65-
gridline-registered grid will be loaded for grid proccessing functions and the
65+
gridline-registered grid will be loaded for grid processing functions and the
6666
pixel-registered grid willcbe loaded for plotting functions. If *res* is also
6767
omitted (i.e., ``@earth_relief``), GMT automatically selects a suitable resolution
6868
based on the current region and projection settings.

pygmt/datasets/earth_vertical_gravity_gradient.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def load_earth_vertical_gravity_gradient(
4040
**@earth_vgg**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
4141
registration type (**p** for pixel registration, **g** for gridline registration).
4242
If *reg* is omitted (e.g., ``@earth_vgg_01d``), the gridline-registered grid will be
43-
loaded for grid proccessing functions and the pixel-registered grid will be loaded
43+
loaded for grid processing functions and the pixel-registered grid will be loaded
4444
for plotting functions. If *res* is also omitted (i.e., ``@earth_vgg``), GMT
4545
automatically selects a suitable resolution based on the current region and
4646
projection settings.

pygmt/datasets/mars_relief.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def load_mars_relief(
5353
**@mars_relief**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
5454
registration type (**p** for pixel registration, **g** for gridline registration).
5555
If *reg* is omitted (e.g., ``@mars_relief_01d``), the gridline-registered grid will
56-
be loaded for grid proccessing functions and the pixel-registered grid will be
56+
be loaded for grid processing functions and the pixel-registered grid will be
5757
loaded for plotting functions. If *res* is also omitted (i.e., ``@mars_relief``),
5858
GMT automatically selects a suitable resolution based on the current region and
5959
projection settings.

pygmt/datasets/mercury_relief.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def load_mercury_relief(
5252
**@mercury_relief**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the
5353
grid registration type (**p** for pixel registration, **g** for gridline
5454
registration). If *reg* is omitted (e.g., ``@mercury_relief_01d``), the
55-
gridline-registered grid will be loaded for grid proccessing functions and the
55+
gridline-registered grid will be loaded for grid processing functions and the
5656
pixel-registered grid will be loaded for plotting functions. If *res* is also
5757
omitted (i.e., ``@mercury_relief``), GMT automatically selects a suitable resolution
5858
based on the current region and projection settings.

pygmt/datasets/moon_relief.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def load_moon_relief(
5353
**@moon_relief**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
5454
registration type (**p** for pixel registration, **g** for gridline registration).
5555
If *reg* is omitted (e.g., ``@moon_relief_01d``), the gridline-registered grid will
56-
be loaded for grid proccessing functions and the pixel-registered grid will be
56+
be loaded for grid processing functions and the pixel-registered grid will be
5757
loaded for plotting functions. If *res* is also omitted (i.e., ``@moon_relief``),
5858
GMT automatically selects a suitable resolution based on the current region and
5959
projection settings.

pygmt/datasets/pluto_relief.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ def load_pluto_relief(
5151
**@pluto_relief**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
5252
registration type (**p** for pixel registration, **g** for gridline registration).
5353
If *reg* is omitted (e.g., ``@pluto_relief_01d``), the gridline-registered grid will
54-
be loaded for grid proccessing functions and the pixel-registered grid will be
54+
be loaded for grid processing functions and the pixel-registered grid will be
5555
loaded for plotting functions. If *res* is also omitted (i.e., ``@pluto_relief``),
5656
GMT automatically selects a suitable resolution based on the current region and
5757
projection settings.

pygmt/datasets/venus_relief.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def load_venus_relief(
4040
**@venus_relief**\_\ *res*\_\ *reg*. *res* is the grid resolution; *reg* is the grid
4141
registration type (**p** for pixel registration, **g** for gridline registration).
4242
If *reg* is omitted (e.g., ``@venus_relief_01d``), the gridline-registered grid will
43-
be loaded for grid proccessing functions and the pixel-registered grid will be
43+
be loaded for grid processing functions and the pixel-registered grid will be
4444
loaded for plotting functions. If *res* is also omitted (i.e., ``@venus_relief``),
4545
GMT automatically selects a suitable resolution based on the current region and
4646
projection settings.

pygmt/src/grdcut.py

+36-14
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,24 @@
22
grdcut - Extract subregion from a grid.
33
"""
44

5+
from typing import Literal
6+
57
import xarray as xr
68
from pygmt.clib import Session
9+
from pygmt.exceptions import GMTInvalidInput
710
from pygmt.helpers import (
8-
GMTTempFile,
911
build_arg_list,
12+
data_kind,
1013
fmt_docstring,
1114
kwargs_to_strings,
1215
use_alias,
1316
)
14-
from pygmt.io import load_dataarray
1517

1618
__doctest_skip__ = ["grdcut"]
1719

1820

1921
@fmt_docstring
2022
@use_alias(
21-
G="outgrid",
2223
R="region",
2324
J="projection",
2425
N="extend",
@@ -28,9 +29,11 @@
2829
f="coltypes",
2930
)
3031
@kwargs_to_strings(R="sequence")
31-
def grdcut(grid, **kwargs) -> xr.DataArray | None:
32+
def grdcut(
33+
grid, kind: Literal["grid", "image"] = "grid", outgrid: str | None = None, **kwargs
34+
) -> xr.DataArray | None:
3235
r"""
33-
Extract subregion from a grid.
36+
Extract subregion from a grid or image.
3437
3538
Produce a new ``outgrid`` file which is a subregion of ``grid``. The
3639
subregion is specified with ``region``; the specified range must not exceed
@@ -48,6 +51,11 @@ def grdcut(grid, **kwargs) -> xr.DataArray | None:
4851
Parameters
4952
----------
5053
{grid}
54+
kind
55+
The raster data kind. Valid values are ``"grid"`` and ``"image"``. When the
56+
input ``grid`` is a file name, it's difficult to determine if the file is a grid
57+
or an image, so we need to specify the raster kind explicitly. The default is
58+
``"grid"``.
5159
{outgrid}
5260
{projection}
5361
{region}
@@ -100,13 +108,27 @@ def grdcut(grid, **kwargs) -> xr.DataArray | None:
100108
>>> # 12° E to 15° E and a latitude range of 21° N to 24° N
101109
>>> new_grid = pygmt.grdcut(grid=grid, region=[12, 15, 21, 24])
102110
"""
103-
with GMTTempFile(suffix=".nc") as tmpfile:
104-
with Session() as lib:
105-
with lib.virtualfile_in(check_kind="raster", data=grid) as vingrd:
106-
if (outgrid := kwargs.get("G")) is None:
107-
kwargs["G"] = outgrid = tmpfile.name # output to tmpfile
108-
lib.call_module(
109-
module="grdcut", args=build_arg_list(kwargs, infile=vingrd)
110-
)
111+
if kind not in {"grid", "image"}:
112+
msg = f"Invalid raster kind: '{kind}'. Valid values are 'grid' and 'image'."
113+
raise GMTInvalidInput(msg)
114+
115+
# Determine the output data kind based on the input data kind.
116+
match inkind := data_kind(grid):
117+
case "grid" | "image":
118+
outkind = inkind
119+
case "file":
120+
outkind = kind
121+
case _:
122+
msg = f"Unsupported data type {type(grid)}."
123+
raise GMTInvalidInput(msg)
111124

112-
return load_dataarray(outgrid) if outgrid == tmpfile.name else None
125+
with Session() as lib:
126+
with (
127+
lib.virtualfile_in(check_kind="raster", data=grid) as vingrd,
128+
lib.virtualfile_out(kind=outkind, fname=outgrid) as voutgrd,
129+
):
130+
kwargs["G"] = voutgrd
131+
lib.call_module(module="grdcut", args=build_arg_list(kwargs, infile=vingrd))
132+
return lib.virtualfile_to_raster(
133+
vfname=voutgrd, kind=outkind, outgrid=outgrid
134+
)

pygmt/src/meca.py

+34-27
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
meca - Plot focal mechanisms.
33
"""
44

5+
from collections.abc import Sequence
6+
from typing import Literal
7+
58
import numpy as np
69
import pandas as pd
710
from pygmt.clib import Session
@@ -131,14 +134,14 @@ def meca( # noqa: PLR0913
131134
self,
132135
spec,
133136
scale,
134-
convention=None,
135-
component="full",
136-
longitude=None,
137-
latitude=None,
138-
depth=None,
139-
plot_longitude=None,
140-
plot_latitude=None,
141-
event_name=None,
137+
convention: Literal["aki", "gcmt", "mt", "partial", "principal_axis"] | None = None,
138+
component: Literal["full", "dc", "deviatoric"] = "full",
139+
longitude: float | Sequence[float] | None = None,
140+
latitude: float | Sequence[float] | None = None,
141+
depth: float | Sequence[float] | None = None,
142+
plot_longitude: float | Sequence[float] | None = None,
143+
plot_latitude: float | Sequence[float] | None = None,
144+
event_name: str | Sequence[str] | None = None,
142145
**kwargs,
143146
):
144147
r"""
@@ -248,28 +251,32 @@ def meca( # noqa: PLR0913
248251
to change its font (size,fontname,color); append **+j**\ *justify* to change
249252
the text location relative to the beachball [Default is ``"TC"``, i.e., Top
250253
Center]; append **+o** to offset the text string by *dx*\ /*dy*.
251-
convention : str
252-
Focal mechanism convention. See the table above for the supported conventions.
253-
Ignored if ``spec`` is a dict or :class:`pandas.DataFrame`.
254-
component : str
255-
The component of the seismic moment tensor to plot.
254+
convention
255+
Specify the focal mechanism convention of the input data. Ignored if ``spec`` is
256+
a dict or :class:`pandas.DataFrame`. See the table above for the supported
257+
conventions.
258+
component
259+
The component of the seismic moment tensor to plot. Valid values are:
256260
257261
- ``"full"``: the full seismic moment tensor
258-
- ``"dc"``: the closest double couple defined from the moment tensor (zero
259-
trace and zero determinant)
262+
- ``"dc"``: the closest double couple defined from the moment tensor (zero trace
263+
and zero determinant)
260264
- ``"deviatoric"``: deviatoric part of the moment tensor (zero trace)
261-
longitude/latitude/depth : float, list, or 1-D numpy array
262-
Longitude(s) / latitude(s) / depth(s) of the event(s). Length must match the
263-
number of events. Overrides the ``longitude`` / ``latitude`` / ``depth`` values
264-
in ``spec`` if ``spec`` is a dict or :class:`pandas.DataFrame`.
265-
plot_longitude/plot_latitude : float, str, list, or 1-D numpy array
266-
Longitude(s) / Latitude(s) at which to place the beachball(s). Length must match
267-
the number of events. Overrides the ``plot_longitude`` / ``plot_latitude``
268-
values in ``spec`` if ``spec`` is a dict or :class:`pandas.DataFrame`.
269-
event_name : str, list of str, or 1-D numpy array
270-
Text string(s), e.g., event name(s) to appear near the beachball(s). Length
271-
must match the number of events. Overrides the ``event_name`` labels in ``spec``
272-
if ``spec`` is a dict or :class:`pandas.DataFrame`.
265+
longitude/latitude/depth
266+
Longitude(s), latitude(s), and depth(s) of the event(s). The length of each must
267+
match the number of events. These parameters are only used if ``spec`` is a
268+
dictionary or a :class:`pandas.DataFrame`, and they override any existing
269+
``longitude``, ``latitude``, or ``depth`` values in ``spec``.
270+
plot_longitude/plot_latitude
271+
Longitude(s) and latitude(s) at which to place the beachball(s). The length of
272+
each must match the number of events. These parameters are only used if ``spec``
273+
is a dictionary or a :class:`pandas.DataFrame`, and they override any existing
274+
``plot_longitude`` or ``plot_latitude`` values in ``spec``.
275+
event_name
276+
Text string(s), such as event name(s), to appear near the beachball(s). The
277+
length must match the number of events. This parameter is only used if ``spec``
278+
is a dictionary or a :class:`pandas.DataFrame`, and it overrides any existing
279+
``event_name`` labels in ``spec``.
273280
labelbox : bool or str
274281
[*fill*].
275282
Draw a box behind the label if given via ``event_name``. Use *fill* to give a

pygmt/tests/test_grdcut.py

+8
Original file line numberDiff line numberDiff line change
@@ -70,3 +70,11 @@ def test_grdcut_fails():
7070
"""
7171
with pytest.raises(GMTInvalidInput):
7272
grdcut(np.arange(10).reshape((5, 2)))
73+
74+
75+
def test_grdcut_invalid_kind(grid, region):
76+
"""
77+
Check that grdcut fails with incorrect 'kind'.
78+
"""
79+
with pytest.raises(GMTInvalidInput):
80+
grdcut(grid, kind="invalid", region=region)

0 commit comments

Comments
 (0)