From dd3abe13640a80b43ba42c33df351bb075c1b898 Mon Sep 17 00:00:00 2001 From: chuan Date: Wed, 25 Feb 2026 20:55:13 +0800 Subject: [PATCH 01/29] add grdmask for required arguments --- pygmt/__init__.py | 1 + pygmt/src/__init__.py | 1 + pygmt/src/grdmask.py | 110 ++++++++++++++++++++++++++++++++++++ pygmt/tests/test_grdmask.py | 107 +++++++++++++++++++++++++++++++++++ 4 files changed, 219 insertions(+) create mode 100644 pygmt/src/grdmask.py create mode 100644 pygmt/tests/test_grdmask.py diff --git a/pygmt/__init__.py b/pygmt/__init__.py index f10c4fad8a5..8adecdf429a 100644 --- a/pygmt/__init__.py +++ b/pygmt/__init__.py @@ -45,6 +45,7 @@ grdhisteq, grdinfo, grdlandmask, + grdmask, grdpaste, grdproject, grdsample, diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py index 3c3fb2c39e3..b3a41b3f637 100644 --- a/pygmt/src/__init__.py +++ b/pygmt/src/__init__.py @@ -25,6 +25,7 @@ from pygmt.src.grdimage import grdimage from pygmt.src.grdinfo import grdinfo from pygmt.src.grdlandmask import grdlandmask +from pygmt.src.grdmask import grdmask from pygmt.src.grdpaste import grdpaste from pygmt.src.grdproject import grdproject from pygmt.src.grdsample import grdsample diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py new file mode 100644 index 00000000000..7561ac7f8ca --- /dev/null +++ b/pygmt/src/grdmask.py @@ -0,0 +1,110 @@ +""" +grdmask - Create mask grid from polygons or point coverage. +""" + +from collections.abc import Sequence +from typing import Literal + +import xarray as xr +from pygmt._typing import PathLike +from pygmt.alias import Alias, AliasSystem +from pygmt.clib import Session +from pygmt.exceptions import GMTParameterError +from pygmt.helpers import build_arg_list, fmt_docstring + +__doctest_skip__ = ["grdmask"] + + +@fmt_docstring +def grdmask( + data, + outgrid: PathLike | None = None, + spacing: Sequence[float | str] | None = None, + region: Sequence[float | str] | str | None = None, + mask_values: Sequence[float] | None = None, + verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] + | bool = False, + **kwargs, +) -> xr.DataArray | None: + r""" + Create mask grid from polygons or point coverage. + + Reads one or more files (or standard input) containing polygon or data point + coordinates, and creates a binary grid file where nodes that fall inside, on the + edge, or outside the polygons (or within the search radius from data points) are + assigned values based on ``mask_values``. + + The mask grid can be used to mask out specific regions in other grids using + :func:`pygmt.grdmath` or similar tools. For masking based on coastline features, + consider using :func:`pygmt.grdlandmask` instead. + + Full GMT docs at :gmt-docs:`grdmask.html`. + + $aliases + - G = outgrid + - I = spacing + - N = mask_values + - R = region + - V = verbose + + Parameters + ---------- + data + Pass in either a file name, :class:`pandas.DataFrame`, :class:`numpy.ndarray`, + or a list of file names containing the polygon(s) or data points. Input can be: + + - **Polygon mode**: One or more files containing closed polygon coordinates + - **Point coverage mode**: Data points (used with ``search_radius`` parameter) + $outgrid + $spacing + mask_values : list of float, optional + Set the values that will be assigned to nodes. Provide three values in the form + [*outside*, *edge*, *inside*]. Default is ``[0, 0, 1]``, meaning nodes outside + and on the edge are set to 0, and nodes inside are set to 1. + + Values can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for + setting nodes to NaN. + $region + $verbose + + Returns + ------- + ret + Return type depends on whether the ``outgrid`` parameter is set: + + - :class:`xarray.DataArray` if ``outgrid`` is not set + - ``None`` if ``outgrid`` is set (grid output will be stored in the file set by + ``outgrid``) + + Example + ------- + >>> import pygmt + >>> import numpy as np + >>> # Create a simple polygon as a triangle + >>> polygon = np.array([[125, 30], [130, 30], [130, 35], [125, 30]]) + >>> # Create a mask grid with 1 arc-degree spacing + >>> mask = pygmt.grdmask(data=polygon, spacing=1, region=[125, 130, 30, 35]) + """ + if spacing is None or region is None: + raise GMTParameterError(required=["region", "spacing"]) + + aliasdict = AliasSystem( + I=Alias(spacing, name="spacing", sep="/", size=2), + N=Alias(mask_values, name="mask_values", sep="/", size=3), + ).add_common( + R=region, + V=verbose, + ) + aliasdict.merge(kwargs) + + with Session() as lib: + with ( + lib.virtualfile_in(check_kind="vector", data=data) as vintbl, + lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd, + ): + aliasdict["G"] = voutgrd + lib.call_module( + module="grdmask", + args=build_arg_list(aliasdict, infile=vintbl), + ) + return lib.virtualfile_to_raster(vfname=voutgrd, outgrid=outgrid) diff --git a/pygmt/tests/test_grdmask.py b/pygmt/tests/test_grdmask.py new file mode 100644 index 00000000000..15452ddaa98 --- /dev/null +++ b/pygmt/tests/test_grdmask.py @@ -0,0 +1,107 @@ +""" +Test pygmt.grdmask. +""" + +from pathlib import Path + +import numpy as np +import pytest +import xarray as xr +from pygmt import grdmask +from pygmt.enums import GridRegistration, GridType +from pygmt.exceptions import GMTParameterError +from pygmt.helpers import GMTTempFile + + +@pytest.fixture(scope="module", name="polygon_data") +def fixture_polygon_data(): + """ + Create a simple polygon for testing. + A triangle polygon covering the region [125, 130, 30, 35]. + """ + return np.array([[125, 30], [130, 30], [130, 35], [125, 30]]) + + +@pytest.fixture(scope="module", name="expected_grid") +def fixture_expected_grid(): + """ + Load the expected grdmask grid result. + """ + return xr.DataArray( + data=[ + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 1.0, 1.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 1.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 0.0, 1.0, 0.0], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + [0.0, 0.0, 0.0, 0.0, 0.0, 0.0], + ], + coords={ + "x": [125.0, 126.0, 127.0, 128.0, 129.0, 130.0], + "y": [30.0, 31.0, 32.0, 33.0, 34.0, 35.0], + }, + dims=["y", "x"], + ) + + +def test_grdmask_outgrid(polygon_data, expected_grid): + """ + Creates a mask grid with an outgrid argument. + """ + with GMTTempFile(suffix=".nc") as tmpfile: + result = grdmask( + data=polygon_data, + outgrid=tmpfile.name, + spacing=1, + region=[125, 130, 30, 35], + ) + assert result is None # return value is None + assert Path(tmpfile.name).stat().st_size > 0 # check that outgrid exists + temp_grid = xr.load_dataarray(tmpfile.name, engine="gmt", raster_kind="grid") + # Check grid properties + assert temp_grid.dims == ("y", "x") + assert temp_grid.gmt.gtype is GridType.CARTESIAN + assert temp_grid.gmt.registration is GridRegistration.GRIDLINE + # Check grid values + xr.testing.assert_allclose(a=temp_grid, b=expected_grid) + + +@pytest.mark.benchmark +def test_grdmask_no_outgrid(polygon_data, expected_grid): + """ + Test grdmask with no set outgrid. + """ + result = grdmask(data=polygon_data, spacing=1, region=[125, 130, 30, 35]) + # Check grid properties + assert isinstance(result, xr.DataArray) + assert result.dims == ("y", "x") + assert result.gmt.gtype is GridType.CARTESIAN + assert result.gmt.registration is GridRegistration.GRIDLINE + # Check grid values + xr.testing.assert_allclose(a=result, b=expected_grid) + + +def test_grdmask_custom_mask_values(polygon_data): + """ + Test grdmask with custom mask_values. + """ + result = grdmask( + data=polygon_data, + spacing=1, + region=[125, 130, 30, 35], + mask_values=[10, 20, 30], # outside, edge, inside + ) + assert isinstance(result, xr.DataArray) + # Check that the grid has the right dimensions + assert result.shape == (6, 6) + # Check that we have values in the expected range + assert result.values.max() <= 30.0 + assert result.values.min() >= 0.0 + + +def test_grdmask_fails(): + """ + Check that grdmask fails correctly when region and spacing are not given. + """ + with pytest.raises(GMTParameterError): + grdmask(data=np.array([[0, 0], [1, 1], [1, 0], [0, 0]])) From caedc1a644284d34f7cfa1324d2efb3f260cca40 Mon Sep 17 00:00:00 2001 From: chuan Date: Wed, 25 Feb 2026 21:15:57 +0800 Subject: [PATCH 02/29] add grdmask doc api --- doc/api/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/api/index.rst b/doc/api/index.rst index 6fad08b8165..1b886914aa6 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -155,6 +155,7 @@ Operations on raster data grdhisteq.equalize_grid grdhisteq.compute_bins grdlandmask + grdmask grdpaste grdproject grdsample From 44d969c59849cc398f955344b16bd4324e34071b Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Wed, 25 Feb 2026 22:01:56 +0800 Subject: [PATCH 03/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 7561ac7f8ca..ec35fb7fa0f 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -26,7 +26,7 @@ def grdmask( | bool = False, **kwargs, ) -> xr.DataArray | None: - r""" + """ Create mask grid from polygons or point coverage. Reads one or more files (or standard input) containing polygon or data point From fdee10959ba574cc4e6fdb4ca8bdcfa126ce76d4 Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Wed, 25 Feb 2026 22:02:01 +0800 Subject: [PATCH 04/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index ec35fb7fa0f..7631efd61af 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -57,7 +57,7 @@ def grdmask( - **Point coverage mode**: Data points (used with ``search_radius`` parameter) $outgrid $spacing - mask_values : list of float, optional + mask_values Set the values that will be assigned to nodes. Provide three values in the form [*outside*, *edge*, *inside*]. Default is ``[0, 0, 1]``, meaning nodes outside and on the edge are set to 0, and nodes inside are set to 1. From 7f0ddfff51af111c71cf903104490d300d1f83e0 Mon Sep 17 00:00:00 2001 From: chuan Date: Wed, 25 Feb 2026 22:02:27 +0800 Subject: [PATCH 05/29] change grdmask category --- doc/api/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/index.rst b/doc/api/index.rst index 1b886914aa6..7c61b0f4738 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -126,6 +126,7 @@ Operations on tabular data blockmedian blockmode filter1d + grdmask nearneighbor project select @@ -155,7 +156,6 @@ Operations on raster data grdhisteq.equalize_grid grdhisteq.compute_bins grdlandmask - grdmask grdpaste grdproject grdsample From 68123cfc1c54a2343239f175d87fab869b8184a8 Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Wed, 25 Feb 2026 22:21:16 +0800 Subject: [PATCH 06/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 7631efd61af..94b2e5a0a75 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -40,7 +40,11 @@ def grdmask( Full GMT docs at :gmt-docs:`grdmask.html`. - $aliases + **Aliases** + + .. hlist:: + :columns: 3 + - G = outgrid - I = spacing - N = mask_values From e70ca8c97bb56f1eeeb0be949597abf6842d90d8 Mon Sep 17 00:00:00 2001 From: chuan Date: Wed, 25 Feb 2026 22:24:38 +0800 Subject: [PATCH 07/29] show the value of mask --- pygmt/src/grdmask.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 94b2e5a0a75..83d9d4ae83d 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -41,10 +41,10 @@ def grdmask( Full GMT docs at :gmt-docs:`grdmask.html`. **Aliases** - + .. hlist:: :columns: 3 - + - G = outgrid - I = spacing - N = mask_values @@ -88,6 +88,13 @@ def grdmask( >>> polygon = np.array([[125, 30], [130, 30], [130, 35], [125, 30]]) >>> # Create a mask grid with 1 arc-degree spacing >>> mask = pygmt.grdmask(data=polygon, spacing=1, region=[125, 130, 30, 35]) + >>> mask.values + array([[0., 0., 0., 0., 0., 0.], + [0., 0., 0., 0., 1., 0.], + [0., 0., 1., 1., 1., 0.], + [0., 0., 1., 1., 1., 0.], + [0., 0., 1., 1., 1., 0.], + [0., 0., 0., 0., 0., 0.]]) """ if spacing is None or region is None: raise GMTParameterError(required=["region", "spacing"]) From 1b0e05714574cc7c4f9191098c11e54c557d27f9 Mon Sep 17 00:00:00 2001 From: chuan Date: Thu, 26 Feb 2026 13:34:59 +0800 Subject: [PATCH 08/29] change parameter name from mask_values to outside, edge, inside. --- pygmt/src/grdmask.py | 26 +++++++++++++++----------- pygmt/tests/test_grdmask.py | 6 ++++-- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 83d9d4ae83d..e0c341a84dc 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -21,7 +21,9 @@ def grdmask( outgrid: PathLike | None = None, spacing: Sequence[float | str] | None = None, region: Sequence[float | str] | str | None = None, - mask_values: Sequence[float] | None = None, + outside: float | str = 0, + edge: float | str = 0, + inside: float | str = 1, verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, **kwargs, @@ -32,7 +34,7 @@ def grdmask( Reads one or more files (or standard input) containing polygon or data point coordinates, and creates a binary grid file where nodes that fall inside, on the edge, or outside the polygons (or within the search radius from data points) are - assigned values based on ``mask_values``. + assigned values based on ``outside``, ``edge``, and ``inside`` parameters. The mask grid can be used to mask out specific regions in other grids using :func:`pygmt.grdmath` or similar tools. For masking based on coastline features, @@ -47,7 +49,7 @@ def grdmask( - G = outgrid - I = spacing - - N = mask_values + - N = outside/edge/inside - R = region - V = verbose @@ -61,13 +63,15 @@ def grdmask( - **Point coverage mode**: Data points (used with ``search_radius`` parameter) $outgrid $spacing - mask_values - Set the values that will be assigned to nodes. Provide three values in the form - [*outside*, *edge*, *inside*]. Default is ``[0, 0, 1]``, meaning nodes outside - and on the edge are set to 0, and nodes inside are set to 1. - - Values can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for - setting nodes to NaN. + outside + Set the value assigned to nodes outside the polygons. Default is 0. + Can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for NaN. + edge + Set the value assigned to nodes on the polygon edges. Default is 0. + Can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for NaN. + inside + Set the value assigned to nodes inside the polygons. Default is 1. + Can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for NaN. $region $verbose @@ -101,7 +105,7 @@ def grdmask( aliasdict = AliasSystem( I=Alias(spacing, name="spacing", sep="/", size=2), - N=Alias(mask_values, name="mask_values", sep="/", size=3), + N=Alias([outside, edge, inside], name="mask_values", sep="/", size=3), ).add_common( R=region, V=verbose, diff --git a/pygmt/tests/test_grdmask.py b/pygmt/tests/test_grdmask.py index 15452ddaa98..120ad68a543 100644 --- a/pygmt/tests/test_grdmask.py +++ b/pygmt/tests/test_grdmask.py @@ -83,13 +83,15 @@ def test_grdmask_no_outgrid(polygon_data, expected_grid): def test_grdmask_custom_mask_values(polygon_data): """ - Test grdmask with custom mask_values. + Test grdmask with custom outside, edge, inside values. """ result = grdmask( data=polygon_data, spacing=1, region=[125, 130, 30, 35], - mask_values=[10, 20, 30], # outside, edge, inside + outside=10, + edge=20, + inside=30, ) assert isinstance(result, xr.DataArray) # Check that the grid has the right dimensions From 7a166e97f4c64b61e5e18bc0332c1ebdd5d068ce Mon Sep 17 00:00:00 2001 From: chuan Date: Thu, 26 Feb 2026 21:02:31 +0800 Subject: [PATCH 09/29] reset the N parameter --- pygmt/src/grdmask.py | 61 ++++++++++++++++++++++++++++++++----- pygmt/tests/test_grdmask.py | 14 +++++++++ 2 files changed, 68 insertions(+), 7 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index e0c341a84dc..9b9815a0f4c 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -21,9 +21,9 @@ def grdmask( outgrid: PathLike | None = None, spacing: Sequence[float | str] | None = None, region: Sequence[float | str] | str | None = None, - outside: float | str = 0, - edge: float | str = 0, - inside: float | str = 1, + outside: float | Literal["z", "id"] = 0, + edge: float | Literal["z", "id"] = 0, + inside: float | Literal["z", "id"] = 1, verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] | bool = False, **kwargs, @@ -66,12 +66,26 @@ def grdmask( outside Set the value assigned to nodes outside the polygons. Default is 0. Can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for NaN. + + When using ``inside="z"`` or ``inside="id"``, this sets the outside value + appended after the mode (e.g., ``outside=1, inside="z"`` gives ``-Nz/1``). edge Set the value assigned to nodes on the polygon edges. Default is 0. Can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for NaN. + + When using ``inside="z"``, setting ``edge="z"`` treats edges as inside + (corresponds to ``-NZ``). Similarly, ``inside="id", edge="id"`` gives ``-NP``. + The combination ``inside="z", edge="id"`` or ``inside="id", edge="z"`` is + invalid and will raise an error. inside Set the value assigned to nodes inside the polygons. Default is 1. Can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for NaN. + + Special values: + + - ``"z"``: Use the z-value from polygon data (segment header ``-Zzval``, + ``-Lheader``, or via ``-aZ=name``). Corresponds to GMT ``-Nz``. + - ``"id"``: Use a running polygon ID number. Corresponds to GMT ``-Np``. $region $verbose @@ -103,10 +117,43 @@ def grdmask( if spacing is None or region is None: raise GMTParameterError(required=["region", "spacing"]) - aliasdict = AliasSystem( - I=Alias(spacing, name="spacing", sep="/", size=2), - N=Alias([outside, edge, inside], name="mask_values", sep="/", size=3), - ).add_common( + # Build the -N parameter string + special_modes = {"z", "id"} + inside_is_special = inside in special_modes + edge_is_special = edge in special_modes + + # Validate combinations + if inside_is_special and edge_is_special and inside != edge: + msg = f"Invalid combination: inside={inside!r} and edge={edge!r}. " + raise GMTParameterError( + reason=msg + "When both are special modes, they must be the same." + ) + + # Build -N argument + if inside_is_special: + # Mode: -Nz, -NZ, -Np, or -NP + mode_char = ( + "Z" + if edge == inside + else "z" + if inside == "z" + else "P" + if edge == inside + else "p" + ) + n_value = f"{mode_char}/{outside}" if outside != 0 else mode_char + aliasdict = AliasSystem( + I=Alias(spacing, name="spacing", sep="/", size=2), + N=n_value, + ) + else: + # Standard mode: outside/edge/inside + aliasdict = AliasSystem( + I=Alias(spacing, name="spacing", sep="/", size=2), + N=Alias([outside, edge, inside], name="mask_values", sep="/", size=3), + ) + + aliasdict = aliasdict.add_common( R=region, V=verbose, ) diff --git a/pygmt/tests/test_grdmask.py b/pygmt/tests/test_grdmask.py index 120ad68a543..707869ba5e2 100644 --- a/pygmt/tests/test_grdmask.py +++ b/pygmt/tests/test_grdmask.py @@ -107,3 +107,17 @@ def test_grdmask_fails(): """ with pytest.raises(GMTParameterError): grdmask(data=np.array([[0, 0], [1, 1], [1, 0], [0, 0]])) + + +def test_grdmask_invalid_combination(polygon_data): + """ + Check that grdmask fails when inside and edge have different special modes. + """ + with pytest.raises(GMTParameterError): + grdmask( + data=polygon_data, + spacing=1, + region=[125, 130, 30, 35], + inside="z", + edge="id", + ) From da0cc55c2948561d1dc590026fbf679d548da1fc Mon Sep 17 00:00:00 2001 From: chuan Date: Mon, 2 Mar 2026 11:26:43 +0800 Subject: [PATCH 10/29] set a private function --- pygmt/src/grdmask.py | 111 +++++++++++++++++++++++++++++-------------- 1 file changed, 76 insertions(+), 35 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 9b9815a0f4c..ef7abe618ce 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -15,6 +15,78 @@ __doctest_skip__ = ["grdmask"] +def _alias_option_N( # noqa: N802 + outside: float | Literal["z", "id"] = 0, + edge: float | Literal["z", "id"] = 0, + inside: float | Literal["z", "id"] = 1, +) -> Alias: + """ + Return an Alias object for the -N option. + + Builds the -N parameter string for grdmask based on the inside, edge, and + outside values. Handles special modes "z" (use z-value from polygon data) + and "id" (use running polygon ID). + + Parameters + ---------- + outside + Set the value assigned to nodes outside the polygons. Default is 0. + edge + Set the value assigned to nodes on the polygon edges. Default is 0. + inside + Set the value assigned to nodes inside the polygons. Default is 1. + + Returns + ------- + Alias + An Alias object representing the -N option value. + + Raises + ------ + GMTParameterError + If inside and edge are both special modes but different values. + + Examples + -------- + >>> _alias_option_N()._value + '0/0/1' + >>> _alias_option_N(outside=1, edge=1, inside=1)._value + '1/1/1' + >>> _alias_option_N(inside="z")._value + 'z' + >>> _alias_option_N(inside="z", outside=1)._value + 'z/1' + >>> _alias_option_N(inside="z", edge="z")._value + 'Z' + >>> _alias_option_N(inside="id")._value + 'p' + >>> _alias_option_N(inside="id", edge="id")._value + 'P' + """ + special_modes = {"z", "id"} + inside_is_special = inside in special_modes + edge_is_special = edge in special_modes + + # Validate combinations + if inside_is_special and edge_is_special and inside != edge: + msg = f"Invalid combination: inside={inside!r} and edge={edge!r}. " + raise GMTParameterError( + reason=msg + "When both are special modes, they must be the same." + ) + + # Build -N argument + if inside_is_special: + # Mode: -Nz, -NZ, -Np, or -NP + if edge == inside: + mode_char = "Z" if inside == "z" else "P" + else: + mode_char = "z" if inside == "z" else "p" + n_value = f"{mode_char}/{outside}" if outside != 0 else mode_char + return Alias(n_value, name="mask_values") + # Standard mode: outside/edge/inside + return Alias([outside, edge, inside], name="mask_values", sep="/", size=3) + + @fmt_docstring def grdmask( data, @@ -117,41 +189,10 @@ def grdmask( if spacing is None or region is None: raise GMTParameterError(required=["region", "spacing"]) - # Build the -N parameter string - special_modes = {"z", "id"} - inside_is_special = inside in special_modes - edge_is_special = edge in special_modes - - # Validate combinations - if inside_is_special and edge_is_special and inside != edge: - msg = f"Invalid combination: inside={inside!r} and edge={edge!r}. " - raise GMTParameterError( - reason=msg + "When both are special modes, they must be the same." - ) - - # Build -N argument - if inside_is_special: - # Mode: -Nz, -NZ, -Np, or -NP - mode_char = ( - "Z" - if edge == inside - else "z" - if inside == "z" - else "P" - if edge == inside - else "p" - ) - n_value = f"{mode_char}/{outside}" if outside != 0 else mode_char - aliasdict = AliasSystem( - I=Alias(spacing, name="spacing", sep="/", size=2), - N=n_value, - ) - else: - # Standard mode: outside/edge/inside - aliasdict = AliasSystem( - I=Alias(spacing, name="spacing", sep="/", size=2), - N=Alias([outside, edge, inside], name="mask_values", sep="/", size=3), - ) + aliasdict = AliasSystem( + I=Alias(spacing, name="spacing", sep="/", size=2), + N=_alias_option_N(outside=outside, edge=edge, inside=inside), + ) aliasdict = aliasdict.add_common( R=region, From 6302abe6aa43b880ce0d6d66ebd6c1541b185bf8 Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Mon, 2 Mar 2026 17:53:37 +0800 Subject: [PATCH 11/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index ef7abe618ce..13ce05150aa 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -63,7 +63,7 @@ def _alias_option_N( # noqa: N802 >>> _alias_option_N(inside="id", edge="id")._value 'P' """ - special_modes = {"z", "id"} + special_modes = {"z": "z", "id": "p"} inside_is_special = inside in special_modes edge_is_special = edge in special_modes From 1d6d753f0a998f9a4fd970d720568d9e5d688caf Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Mon, 2 Mar 2026 17:53:46 +0800 Subject: [PATCH 12/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 13ce05150aa..2fdff58713e 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -77,10 +77,9 @@ def _alias_option_N( # noqa: N802 # Build -N argument if inside_is_special: # Mode: -Nz, -NZ, -Np, or -NP + mode_char = special_modes[inside] if edge == inside: - mode_char = "Z" if inside == "z" else "P" - else: - mode_char = "z" if inside == "z" else "p" + mode_char = mode_char.upper() n_value = f"{mode_char}/{outside}" if outside != 0 else mode_char return Alias(n_value, name="mask_values") # Standard mode: outside/edge/inside From d4293de0514834eedf59535c2b130695d5de59e8 Mon Sep 17 00:00:00 2001 From: chuan Date: Mon, 2 Mar 2026 17:56:58 +0800 Subject: [PATCH 13/29] delete docs --- pygmt/src/grdmask.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 2fdff58713e..59f8e3d56eb 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -27,25 +27,6 @@ def _alias_option_N( # noqa: N802 outside values. Handles special modes "z" (use z-value from polygon data) and "id" (use running polygon ID). - Parameters - ---------- - outside - Set the value assigned to nodes outside the polygons. Default is 0. - edge - Set the value assigned to nodes on the polygon edges. Default is 0. - inside - Set the value assigned to nodes inside the polygons. Default is 1. - - Returns - ------- - Alias - An Alias object representing the -N option value. - - Raises - ------ - GMTParameterError - If inside and edge are both special modes but different values. - Examples -------- >>> _alias_option_N()._value From a0ded6445f4a9bf97feb9a281844907bfffa7811 Mon Sep 17 00:00:00 2001 From: chuan Date: Mon, 2 Mar 2026 18:08:04 +0800 Subject: [PATCH 14/29] fix type error --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 59f8e3d56eb..7fc204a41e6 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -58,7 +58,7 @@ def _alias_option_N( # noqa: N802 # Build -N argument if inside_is_special: # Mode: -Nz, -NZ, -Np, or -NP - mode_char = special_modes[inside] + mode_char = special_modes[inside] # type: ignore[index] if edge == inside: mode_char = mode_char.upper() n_value = f"{mode_char}/{outside}" if outside != 0 else mode_char From 871bcff16b1c5471c103455c424a6502d998f141 Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Tue, 3 Mar 2026 10:16:12 +0800 Subject: [PATCH 15/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 7fc204a41e6..aa3ea23a1a4 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -31,8 +31,8 @@ def _alias_option_N( # noqa: N802 -------- >>> _alias_option_N()._value '0/0/1' - >>> _alias_option_N(outside=1, edge=1, inside=1)._value - '1/1/1' + >>> _alias_option_N(outside=1, edge=2, inside=3)._value + '1/2/3' >>> _alias_option_N(inside="z")._value 'z' >>> _alias_option_N(inside="z", outside=1)._value From a0519e6d8a278db2d292af79fc8dcc2f4179808e Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Tue, 3 Mar 2026 10:16:19 +0800 Subject: [PATCH 16/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index aa3ea23a1a4..eb6b8b8ade7 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -16,9 +16,9 @@ def _alias_option_N( # noqa: N802 - outside: float | Literal["z", "id"] = 0, - edge: float | Literal["z", "id"] = 0, - inside: float | Literal["z", "id"] = 1, + outside: float | Literal["z", "id"] | None = None, + edge: float | Literal["z", "id"] | None = None, + inside: float | Literal["z", "id"] | None = None, ) -> Alias: """ Return an Alias object for the -N option. From 7d98d67bcbca08d23db47682cbd9e8eafa60bd8d Mon Sep 17 00:00:00 2001 From: chuan Date: Tue, 3 Mar 2026 10:25:38 +0800 Subject: [PATCH 17/29] simplified code logic --- pygmt/src/grdmask.py | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index eb6b8b8ade7..7b62a55938d 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -29,39 +29,35 @@ def _alias_option_N( # noqa: N802 Examples -------- - >>> _alias_option_N()._value + >>> _alias_option_N(outside=0, edge=0, inside=1)._value '0/0/1' >>> _alias_option_N(outside=1, edge=2, inside=3)._value '1/2/3' - >>> _alias_option_N(inside="z")._value + >>> _alias_option_N(outside=0, edge=0, inside="z")._value 'z' - >>> _alias_option_N(inside="z", outside=1)._value + >>> _alias_option_N(outside=1, edge=0, inside="z")._value 'z/1' - >>> _alias_option_N(inside="z", edge="z")._value + >>> _alias_option_N(outside=0, edge="z", inside="z")._value 'Z' - >>> _alias_option_N(inside="id")._value + >>> _alias_option_N(outside=0, edge=0, inside="id")._value 'p' - >>> _alias_option_N(inside="id", edge="id")._value + >>> _alias_option_N(outside=0, edge="id", inside="id")._value 'P' """ - special_modes = {"z": "z", "id": "p"} - inside_is_special = inside in special_modes - edge_is_special = edge in special_modes - # Validate combinations - if inside_is_special and edge_is_special and inside != edge: + if inside in {"z", "id"} and edge in {"z", "id"} and inside != edge: msg = f"Invalid combination: inside={inside!r} and edge={edge!r}. " raise GMTParameterError( reason=msg + "When both are special modes, they must be the same." ) # Build -N argument - if inside_is_special: + if inside in {"z", "id"}: # Mode: -Nz, -NZ, -Np, or -NP - mode_char = special_modes[inside] # type: ignore[index] + mode_char = "z" if inside == "z" else "p" if edge == inside: mode_char = mode_char.upper() - n_value = f"{mode_char}/{outside}" if outside != 0 else mode_char + n_value = mode_char if outside == 0 else f"{mode_char}/{outside}" return Alias(n_value, name="mask_values") # Standard mode: outside/edge/inside return Alias([outside, edge, inside], name="mask_values", sep="/", size=3) From ad2379439bb1f23e69b698340737bde71360236f Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Tue, 3 Mar 2026 14:43:50 +0800 Subject: [PATCH 18/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 7b62a55938d..22618122df8 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -57,7 +57,7 @@ def _alias_option_N( # noqa: N802 mode_char = "z" if inside == "z" else "p" if edge == inside: mode_char = mode_char.upper() - n_value = mode_char if outside == 0 else f"{mode_char}/{outside}" + mask_values = mode_char if outside is None else [mode_char, outside] return Alias(n_value, name="mask_values") # Standard mode: outside/edge/inside return Alias([outside, edge, inside], name="mask_values", sep="/", size=3) From 8e2a99864d0afef1f044baa1c717dd4189f5f27e Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Tue, 3 Mar 2026 14:44:12 +0800 Subject: [PATCH 19/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 22618122df8..fe8f74bec8e 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -58,7 +58,7 @@ def _alias_option_N( # noqa: N802 if edge == inside: mode_char = mode_char.upper() mask_values = mode_char if outside is None else [mode_char, outside] - return Alias(n_value, name="mask_values") + return Alias(mask_values, name="mask_values", sep="/", size=2) # Standard mode: outside/edge/inside return Alias([outside, edge, inside], name="mask_values", sep="/", size=3) From 21b543d760eff42885327ad2dee58e15bd2cea0a Mon Sep 17 00:00:00 2001 From: chuan Date: Tue, 3 Mar 2026 17:11:15 +0800 Subject: [PATCH 20/29] check output --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index fe8f74bec8e..576c792e3e9 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -57,7 +57,7 @@ def _alias_option_N( # noqa: N802 mode_char = "z" if inside == "z" else "p" if edge == inside: mode_char = mode_char.upper() - mask_values = mode_char if outside is None else [mode_char, outside] + mask_values = mode_char if outside in {None, 0} else [mode_char, outside] return Alias(mask_values, name="mask_values", sep="/", size=2) # Standard mode: outside/edge/inside return Alias([outside, edge, inside], name="mask_values", sep="/", size=3) From 53b334646130b550bff1ea6f4047ace2b77046d1 Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Wed, 4 Mar 2026 12:22:30 +0800 Subject: [PATCH 21/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 576c792e3e9..e1a92cd8510 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -168,9 +168,7 @@ def grdmask( aliasdict = AliasSystem( I=Alias(spacing, name="spacing", sep="/", size=2), N=_alias_option_N(outside=outside, edge=edge, inside=inside), - ) - - aliasdict = aliasdict.add_common( + ).add_common( R=region, V=verbose, ) From 8e9a3b69d271e6560bd31a70eea5a661946039bc Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Wed, 4 Mar 2026 12:22:49 +0800 Subject: [PATCH 22/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index e1a92cd8510..e94a66d2e36 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -112,28 +112,18 @@ def grdmask( $outgrid $spacing outside - Set the value assigned to nodes outside the polygons. Default is 0. - Can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for NaN. - - When using ``inside="z"`` or ``inside="id"``, this sets the outside value - appended after the mode (e.g., ``outside=1, inside="z"`` gives ``-Nz/1``). edge - Set the value assigned to nodes on the polygon edges. Default is 0. - Can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for NaN. - - When using ``inside="z"``, setting ``edge="z"`` treats edges as inside - (corresponds to ``-NZ``). Similarly, ``inside="id", edge="id"`` gives ``-NP``. - The combination ``inside="z", edge="id"`` or ``inside="id", edge="z"`` is - invalid and will raise an error. inside - Set the value assigned to nodes inside the polygons. Default is 1. + Set the value assigned to nodes outside, on the edge, or inside the polygons. Can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for NaN. - - Special values: + + ``inside`` can also be set to one of the following values: - ``"z"``: Use the z-value from polygon data (segment header ``-Zzval``, - ``-Lheader``, or via ``-aZ=name``). Corresponds to GMT ``-Nz``. - - ``"id"``: Use a running polygon ID number. Corresponds to GMT ``-Np``. + ``-Lheader``, or via ``-aZ=name``). + - ``"id"``: Use a running polygon ID number. + + To treats edges as inside, using the same value as ``inside``. $region $verbose From 2a19936ff929fbd0e359992476c0632b64eed5bd Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Wed, 4 Mar 2026 12:23:17 +0800 Subject: [PATCH 23/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index e94a66d2e36..d3f50a1aeac 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -58,9 +58,9 @@ def _alias_option_N( # noqa: N802 if edge == inside: mode_char = mode_char.upper() mask_values = mode_char if outside in {None, 0} else [mode_char, outside] - return Alias(mask_values, name="mask_values", sep="/", size=2) - # Standard mode: outside/edge/inside - return Alias([outside, edge, inside], name="mask_values", sep="/", size=3) + else: + mask_values = [outside, edge, inside] + return Alias([outside, edge, inside], name="mask_values", sep="/", size={2, 3}) @fmt_docstring From 813b8e27286a77bf7ebd96da356cec6b3733d22a Mon Sep 17 00:00:00 2001 From: chuan Date: Wed, 4 Mar 2026 12:25:41 +0800 Subject: [PATCH 24/29] fix format --- pygmt/src/grdmask.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index d3f50a1aeac..4d7fa6a15d4 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -60,7 +60,7 @@ def _alias_option_N( # noqa: N802 mask_values = mode_char if outside in {None, 0} else [mode_char, outside] else: mask_values = [outside, edge, inside] - return Alias([outside, edge, inside], name="mask_values", sep="/", size={2, 3}) + return Alias(mask_values, name="mask_values", sep="/", size={2, 3}) @fmt_docstring @@ -116,14 +116,14 @@ def grdmask( inside Set the value assigned to nodes outside, on the edge, or inside the polygons. Can be any number, or one of ``None``, ``"NaN"``, and ``np.nan`` for NaN. - - ``inside`` can also be set to one of the following values: + + ``inside`` can also be set to one of the following values: - ``"z"``: Use the z-value from polygon data (segment header ``-Zzval``, ``-Lheader``, or via ``-aZ=name``). - ``"id"``: Use a running polygon ID number. - - To treats edges as inside, using the same value as ``inside``. + + To treats edges as inside, using the same value as ``inside``. $region $verbose From 1eb9667ceba205d9ff5aa915ba3249439a992cf3 Mon Sep 17 00:00:00 2001 From: chuan Date: Wed, 4 Mar 2026 12:28:28 +0800 Subject: [PATCH 25/29] fix static type error --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 4d7fa6a15d4..21ce1bfb15f 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -60,7 +60,7 @@ def _alias_option_N( # noqa: N802 mask_values = mode_char if outside in {None, 0} else [mode_char, outside] else: mask_values = [outside, edge, inside] - return Alias(mask_values, name="mask_values", sep="/", size={2, 3}) + return Alias(mask_values, name="mask_values", sep="/", size=(2, 3)) @fmt_docstring From a1ba80073e96d4659720d11488c91d3294c80242 Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Wed, 4 Mar 2026 15:14:29 +0800 Subject: [PATCH 26/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 21ce1bfb15f..7e811870319 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -57,7 +57,7 @@ def _alias_option_N( # noqa: N802 mode_char = "z" if inside == "z" else "p" if edge == inside: mode_char = mode_char.upper() - mask_values = mode_char if outside in {None, 0} else [mode_char, outside] + mask_values = mode_char if outside is None else [mode_char, outside] else: mask_values = [outside, edge, inside] return Alias(mask_values, name="mask_values", sep="/", size=(2, 3)) From 05e963556bd840b32e4d8c32414ff00f303ff69f Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Wed, 4 Mar 2026 15:14:38 +0800 Subject: [PATCH 27/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index 7e811870319..ad67a3ae2ff 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -44,8 +44,9 @@ def _alias_option_N( # noqa: N802 >>> _alias_option_N(outside=0, edge="id", inside="id")._value 'P' """ + _inside_modes = {"z": "z", "id": "p"} # Validate combinations - if inside in {"z", "id"} and edge in {"z", "id"} and inside != edge: + if inside in _inside_modes and edge in _inside_modes and inside != edge: msg = f"Invalid combination: inside={inside!r} and edge={edge!r}. " raise GMTParameterError( reason=msg + "When both are special modes, they must be the same." From f9a87fe0a389db568bc29e695eeb87a97ceea9c1 Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Wed, 4 Mar 2026 15:14:46 +0800 Subject: [PATCH 28/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index ad67a3ae2ff..afefcf7837d 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -53,7 +53,7 @@ def _alias_option_N( # noqa: N802 ) # Build -N argument - if inside in {"z", "id"}: + if inside in _inside_modes: # Mode: -Nz, -NZ, -Np, or -NP mode_char = "z" if inside == "z" else "p" if edge == inside: From b63a8dece4bdf56a91efd515b7bf1e44a28bc864 Mon Sep 17 00:00:00 2001 From: Xingchen He Date: Wed, 4 Mar 2026 15:14:53 +0800 Subject: [PATCH 29/29] Update pygmt/src/grdmask.py Co-authored-by: Dongdong Tian --- pygmt/src/grdmask.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/grdmask.py b/pygmt/src/grdmask.py index afefcf7837d..9ae8dcf217a 100644 --- a/pygmt/src/grdmask.py +++ b/pygmt/src/grdmask.py @@ -55,7 +55,7 @@ def _alias_option_N( # noqa: N802 # Build -N argument if inside in _inside_modes: # Mode: -Nz, -NZ, -Np, or -NP - mode_char = "z" if inside == "z" else "p" + mode_char = _inside_modes[inside] if edge == inside: mode_char = mode_char.upper() mask_values = mode_char if outside is None else [mode_char, outside]