Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Figure.coast/pygmt.select/pygmt.grdlandmask: Use long names ("crude"/"low"/"intermediate"/"high"/"full") for the 'resolution' parameter #3013

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 11 additions & 15 deletions examples/tutorials/basics/coastlines.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
# 3. island-in-lake shore
# 4. lake-in-island-in-lake shore
#
# You can specify which level you want to plot by passing the level number and
# a GMT pen configuration. For example, to plot just the coastlines with 0.5p
# thickness and black lines:
# You can specify which level you want to plot by passing the level number and a GMT
# pen configuration. For example, to plot just the coastlines with 0.5p thickness and
# black lines:

fig = pygmt.Figure()
fig.basemap(region="g", projection="W15c", frame=True)
Expand All @@ -50,18 +50,14 @@
# Resolutions
# -----------
#
# The coastline database comes with 5 resolutions. The resolution drops by 80%
# between levels:
#
# 1. ``"c"``: crude
# 2. ``"l"``: low (default)
# 3. ``"i"``: intermediate
# 4. ``"h"``: high
# 5. ``"f"``: full
# The coastline database comes with 5 resolutions: ``"full"``, ``"high"``,
# ``"intermediate"``, ``"low"``, and ``"crude"``. The resolution drops by 80% between
# levels. The ``resolution`` parameter defaults to ``"auto"`` to automatically select
# the best resolution given the chosen map scale.

oahu = [-158.3, -157.6, 21.2, 21.8]
fig = pygmt.Figure()
for res in ["c", "l", "i", "h", "f"]:
for res in ["crude", "low", "intermediate", "high", "full"]:
fig.coast(resolution=res, shorelines="1p", region=oahu, projection="M5c")
fig.shift_origin(xshift="5c")
fig.show()
Expand All @@ -71,9 +67,9 @@
# Land and water
# --------------
#
# Use the ``land`` and ``water`` parameters to specify a fill color for land
# and water bodies. The colors can be given by name or hex codes (like the ones
# used in HTML and CSS):
# Use the ``land`` and ``water`` parameters to specify a fill color for land and water
# bodies. The colors can be given by name or hex codes (like the ones used in HTML and
# CSS):

fig = pygmt.Figure()
fig.basemap(region="g", projection="W15c", frame=True)
Expand Down
61 changes: 60 additions & 1 deletion pygmt/src/_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
"""

from pathlib import Path
from typing import Any
from typing import Any, Literal

from pygmt.exceptions import GMTInvalidInput
from pygmt.src.which import which


Expand Down Expand Up @@ -39,3 +40,61 @@ def _data_geometry_is_point(data: Any, kind: str) -> bool:
except FileNotFoundError:
pass
return False


def _parse_coastline_resolution(
resolution: Literal["auto", "full", "high", "intermediate", "low", "crude", None],
allow_auto: bool = False,
) -> str | None:
"""
Parse the resolution parameter for coastline-related functions.

Parameters
----------
resolution
The resolution of the coastline dataset to use. The available resolutions from
highest to lowest are: ``"full"``, ``"high"``, ``"intermediate"``, ``"low"``,
and ``"crude"``, which drops by 80% between levels.
allow_auto
Whether to allow the ``"auto"`` resolution.

Returns
-------
The parsed single-letter resolution or ``None``.

Raises
------
GMTInvalidInput
If the resolution is invalid.

Examples
--------
>>> _parse_coastline_resolution("full")
'f'
>>> _parse_coastline_resolution("f")
'f'
>>> _parse_coastline_resolution("auto", allow_auto=True)
'a'
>>> _parse_coastline_resolution(None)
>>> _parse_coastline_resolution("invalid")
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: Invalid resolution: 'invalid'. Valid values ...
>>> _parse_coastline_resolution("auto")
Traceback (most recent call last):
...
pygmt.exceptions.GMTInvalidInput: Invalid resolution: 'auto'. Valid values ...
"""
if resolution is None:
return None

valid_resolutions = {"full", "high", "intermediate", "low", "crude"}
if allow_auto:
valid_resolutions.add("auto")
if resolution not in {*valid_resolutions, *[res[0] for res in valid_resolutions]}:
msg = (
f"Invalid resolution: '{resolution}'. "
f"Valid values are {', '.join(valid_resolutions)}."
)
raise GMTInvalidInput(msg)
return resolution[0]
25 changes: 19 additions & 6 deletions pygmt/src/coast.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
coast - Plot land and water.
"""

from typing import Literal

from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import (
Expand All @@ -11,6 +13,7 @@
kwargs_to_strings,
use_alias,
)
from pygmt.src._common import _parse_coastline_resolution

__doctest_skip__ = ["coast"]

Expand All @@ -20,7 +23,6 @@
A="area_thresh",
B="frame",
C="lakes",
D="resolution",
E="dcw",
F="box",
G="land",
Expand All @@ -37,7 +39,13 @@
t="transparency",
)
@kwargs_to_strings(R="sequence", c="sequence_comma", p="sequence")
def coast(self, **kwargs):
def coast(
self,
resolution: Literal[
"auto", "full", "high", "intermediate", "low", "crude", None
] = None,
**kwargs,
):
r"""
Plot continents, shorelines, rivers, and borders on maps.

Expand Down Expand Up @@ -73,10 +81,12 @@ def coast(self, **kwargs):
parameter. Optionally, specify separate fills by appending
**+l** for lakes or **+r** for river-lakes, and passing multiple
strings in a list.
resolution : str
**f**\|\ **h**\|\ **i**\|\ **l**\|\ **c**.
Select the resolution of the data set to: (**f**\ )ull, (**h**\ )igh,
(**i**\ )ntermediate, (**l**\ )ow, and (**c**\ )rude.
resolution
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from https://docs.generic-mapping-tools.org/dev/coast.html#d, but the +f modifier is not mentioned at all, since it's rarely used. It may not work as documented since in recent GMT versions, GMT can automatically download GSHHG and DCW datasets from the GMT data server.

Select the resolution of the coastline dataset to use. The available resolutions
from highest to lowest are: ``"full"``, ``"high"``, ``"intermediate"``,
``"low"``, and ``"crude"``, which drops by 80% between levels. Default is
``"auto"`` to automatically select the most suitable resolution given the chosen
map scale.
land : str
Select filling of "dry" areas.
rivers : int, str, or list
Expand Down Expand Up @@ -199,5 +209,8 @@ def coast(self, **kwargs):
"""At least one of the following parameters must be specified:
lakes, land, water, rivers, borders, dcw, Q, or shorelines"""
)
kwargs["D"] = kwargs.get(
"D", _parse_coastline_resolution(resolution, allow_auto=True)
)
with Session() as lib:
lib.call_module(module="coast", args=build_arg_list(kwargs))
33 changes: 20 additions & 13 deletions pygmt/src/grdlandmask.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,20 @@
grdlandmask - Create a "wet-dry" mask grid from shoreline data base
"""

from typing import Literal

import xarray as xr
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias
from pygmt.src._common import _parse_coastline_resolution

__doctest_skip__ = ["grdlandmask"]


@fmt_docstring
@use_alias(
A="area_thresh",
D="resolution",
E="bordervalues",
I="spacing",
N="maskvalues",
Expand All @@ -23,7 +25,11 @@
x="cores",
)
@kwargs_to_strings(I="sequence", R="sequence", N="sequence", E="sequence")
def grdlandmask(outgrid: str | None = None, **kwargs) -> xr.DataArray | None:
def grdlandmask(
outgrid: str | None = None,
resolution: Literal["full", "high", "intermediate", "low", "crude", None] = None,
**kwargs,
) -> xr.DataArray | None:
r"""
Create a grid file with set values for land and water.

Expand All @@ -44,17 +50,14 @@ def grdlandmask(outgrid: str | None = None, **kwargs) -> xr.DataArray | None:
{spacing}
{region}
{area_thresh}
resolution : str
*res*\[\ **+f**\]. Select the resolution of the data set to use
((**f**)ull, (**h**)igh, (**i**)ntermediate, (**l**)ow, or
(**c**)rude). The resolution drops off by ~80% between data sets.
[Default is **l**]. Append **+f** to automatically select a lower
resolution should the one requested not be available
[abort if not found]. Alternatively, choose (**a**)uto to automatically
select the best resolution given the chosen region. Note that because
the coastlines differ in details a node in a mask file using one
resolution is not guaranteed to remain inside [or outside] when a
different resolution is selected.
resolution
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from https://docs.generic-mapping-tools.org/dev/grdlandmask.html#d, but the +f modifier is not mentioned.

Ignored unless ``mask`` is set. Select the resolution of the coastline dataset
to use. The available resolutions from highest to lowest are: ``"full"``,
``"high"``, ``"intermediate"``, ``"low"``, and ``"crude"``, which drops by 80%
between levels. Note that because the coastlines differ in details a node in a
mask file using one resolution is not guaranteed to remain inside [or outside]
when a different resolution is selected. If ``None``, the low resolution is used
by default.
bordervalues : bool, str, float, or list
Nodes that fall exactly on a polygon boundary should be
considered to be outside the polygon [Default considers them to be
Expand Down Expand Up @@ -98,6 +101,10 @@ def grdlandmask(outgrid: str | None = None, **kwargs) -> xr.DataArray | None:
if kwargs.get("I") is None or kwargs.get("R") is None:
raise GMTInvalidInput("Both 'region' and 'spacing' must be specified.")

kwargs["D"] = kwargs.get(
"D", _parse_coastline_resolution(resolution, allow_auto=True)
)

with Session() as lib:
with lib.virtualfile_out(kind="grid", fname=outgrid) as voutgrd:
kwargs["G"] = voutgrd
Expand Down
22 changes: 11 additions & 11 deletions pygmt/src/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use_alias,
validate_output_table_type,
)
from pygmt.src._common import _parse_coastline_resolution

__doctest_skip__ = ["select"]

Expand All @@ -22,7 +23,6 @@
@use_alias(
A="area_thresh",
C="dist2pt",
D="resolution",
F="polygon",
G="gridmask",
I="reverse",
Expand All @@ -48,6 +48,7 @@ def select(
data=None,
output_type: Literal["pandas", "numpy", "file"] = "pandas",
outfile: str | None = None,
resolution: Literal["full", "high", "intermediate", "low", "crude", None] = None,
**kwargs,
) -> pd.DataFrame | np.ndarray | None:
r"""
Expand Down Expand Up @@ -116,16 +117,13 @@ def select(
<reference/file-formats.html#optional-segment-header-records>`
*polygonfile*. For spherical polygons (lon, lat), make sure no
consecutive points are separated by 180 degrees or more in longitude.
resolution : str
*resolution*\ [**+f**].
Ignored unless ``mask`` is set. Selects the resolution of the coastline
data set to use ((**f**)ull, (**h**)igh, (**i**)ntermediate, (**l**)ow,
or (**c**)rude). The resolution drops off by ~80% between data sets.
[Default is **l**]. Append (**+f**) to automatically select a lower
resolution should the one requested not be available [Default is abort
if not found]. Note that because the coastlines differ in details
it is not guaranteed that a point will remain inside [or outside] when
a different resolution is selected.
resolution
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from https://docs.generic-mapping-tools.org/dev/gmtselect.html#d, but the +f modifier is not mentioned.

Ignored unless ``mask`` is set. Select the resolution of the coastline dataset
to use. The available resolutions from highest to lowest are: ``"full"``,
``"high"``, ``"intermediate"``, ``"low"``, and ``"crude"``, which drops by 80%
between levels. Note that because the coastlines differ in details it is not
guaranteed that a point will remain inside [or outside] when a different
resolution is selected. If ``None``, the low resolution is used by default.
gridmask : str
Pass all locations that are inside the valid data area of the grid
*gridmask*. Nodes that are outside are either NaN or zero.
Expand Down Expand Up @@ -205,6 +203,8 @@ def select(
>>> # longitudes 246 and 247 and latitudes 20 and 21
>>> out = pygmt.select(data=ship_data, region=[246, 247, 20, 21])
"""
kwargs["D"] = kwargs.get("D", _parse_coastline_resolution(resolution))

output_type = validate_output_table_type(output_type, outfile=outfile)

column_names = None
Expand Down
2 changes: 1 addition & 1 deletion pygmt/tests/test_coast.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ def test_coast_world_mercator():
projection="M15c",
frame="af",
land="#aaaaaa",
resolution="c",
resolution="crude",
water="white",
)
return fig
Expand Down
Loading