Skip to content
5 changes: 2 additions & 3 deletions examples/gallery/3d_plots/grdview_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,11 @@ def ackley(x, y):
SCALE = 0.5 # in centimeters
fig.grdview(
data,
# Set annotations and gridlines in steps of five, and
# tick marks in steps of one
# Set annotations and gridlines in steps of five, and tick marks in steps of one
frame=["a5f1g5", "za5f1g5"],
projection=f"x{SCALE}c",
zscale=f"{SCALE}c",
surftype="s",
surftype="surface",
cmap="roma",
perspective=[135, 30], # Azimuth southeast (135°), at elevation 30°
shading="+a45",
Expand Down
10 changes: 4 additions & 6 deletions examples/tutorials/advanced/3d_perspective_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,8 @@
frame=["xa", "yaf", "WSnE"],
projection="M15c",
zsize="1.5c",
# Set the surftype to "surface"
surftype="s",
# Set the CPT to "geo"
cmap="geo",
surftype="surface",
cmap="geo", # Set the CPT to "geo"
)
fig.show()

Expand All @@ -65,7 +63,7 @@
frame=["xa", "yaf", "WSnE"],
projection="M15c",
zsize="1.5c",
surftype="s",
surftype="surface",
cmap="geo",
# Set the plane elevation to 1,000 meters and make the fill "gray"
plane="1000+ggray",
Expand All @@ -88,7 +86,7 @@
frame=["xaf", "yaf", "WSnE"],
projection="M15c",
zsize="1.5c",
surftype="s",
surftype="surface",
cmap="geo",
plane="1000+ggrey",
# Set the contour pen thickness to "0.1p"
Expand Down
4 changes: 2 additions & 2 deletions examples/tutorials/advanced/draping_on_3d_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
grid=grd_relief, # Use elevation grid for z values
drapegrid=grd_age, # Use crustal age grid for color-coding
cmap=True, # Use colormap created for the crustal age
surftype="i", # Create an image plot
surftype="image", # Create an image plot
# Use an illumination from the azimuthal directions 0° (north) and 270°
# (west) with a normalization via a cumulative Laplace distribution for
# the shading
Expand Down Expand Up @@ -122,7 +122,7 @@
grid=grd_relief, # Use elevation grid for z values
drapegrid=drapegrid, # Drap image grid for the EU flag on top
cmap=True, # Use colormap defined for the EU flag
surftype="i", # Create an image plot
surftype="image", # Create an image plot
# Use an illumination from the azimuthal directions 0° (north) and 270° (west) with
# a normalization via a cumulative Laplace distribution for the shading
shading="+a0/270+ne0.6",
Expand Down
87 changes: 73 additions & 14 deletions pygmt/src/grdview.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from pygmt._typing import PathLike
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import build_arg_list, fmt_docstring, use_alias

__doctest_skip__ = ["grdview"]
Expand All @@ -19,7 +20,6 @@
C="cmap",
G="drapegrid",
N="plane",
Q="surftype",
Wc="contourpen",
Wm="meshpen",
Wf="facadepen",
Expand All @@ -30,6 +30,14 @@
def grdview( # noqa: PLR0913
self,
grid: PathLike | xr.DataArray,
surftype: Literal[
"mesh", "surface", "surface+mesh", "image", "waterfall_x", "waterfall_y"
]
| None = None,
dpi: int | None = None,
mesh_fill: float | None = None,
nan_transparent: bool = False,
monochrome: bool = False,
projection: str | None = None,
zscale: float | str | None = None,
zsize: float | str | None = None,
Expand Down Expand Up @@ -59,6 +67,7 @@ def grdview( # noqa: PLR0913
- Jz = zscale
- JZ = zsize
- R = region
- Q = surftype, dpi, mesh_fill, nan_transparent, monochrome
- V = verbose
- c = panel
- p = perspective
Expand Down Expand Up @@ -89,18 +98,24 @@ def grdview( # noqa: PLR0913
Draw a plane at this z-level. If the optional color is provided via the **+g**
modifier, and the projection is not oblique, the frontal facade between the
plane and the data perimeter is colored.
surftype : str
Specify cover type of the grid. Select one of following settings:

- **m**: mesh plot [Default].
- **mx** or **my**: waterfall plots (row or column profiles).
- **s**: surface plot, and optionally append **m** to have mesh lines drawn on
top of the surface.
- **i**: image plot.
- **c**: Same as **i** but will make nodes with z = NaN transparent.

For any of these choices, you may force a monochrome image by appending the
modifier **+m**.
surftype
Specify surface type of the grid. Valid values are:

- ``"mesh"``: mesh plot [Default].
- ``"surface``: surface plot.
- ``"surface+mesh"``: surface plot with mesh lines drawn on top of the surface.
- ``"image"``: image plot.
- ``"waterfall_x"``/``"waterfall_y"``: waterfall plots (row or column profiles).
dpi
Effective dots-per-unit resolution for the rasterization for image plots (i.e.,
``surftype="image"``) [Default is :gmt-term:`GMT_GRAPHICS_DPU`]
mesh_fill
Set the mesh fill in mesh plot or waterfall plots [Default is white].
nan_transparent
Make grid nodes with z = NaN transparent, using the color-masking feature in
PostScript Level 3. Only applies when ``surftype="image"``.
monochrome
Force conversion to monochrome image using the (television) YIQ transformation.
contourpen : str
Draw contour lines on top of surface or mesh (not image). Append pen attributes
used for the contours.
Expand Down Expand Up @@ -150,7 +165,7 @@ def grdview( # noqa: PLR0913
... # Set the vertical scale (z-axis) to 2 cm
... zsize="2c",
... # Set "surface plot" to color the surface via a CPT
... surftype="s",
... surftype="surface",
... # Specify CPT to "geo"
... cmap="geo",
... )
Expand All @@ -159,9 +174,53 @@ def grdview( # noqa: PLR0913
"""
self._activate_figure()

if dpi is not None and surftype != "image":
msg = "Parameter 'dpi' can only be used when 'surftype' is 'image'."
raise GMTInvalidInput(msg)
if nan_transparent and surftype != "image":
msg = "Parameter 'nan_transparent' can only be used when 'surftype' is 'image'."
raise GMTInvalidInput(msg)
if mesh_fill is not None and surftype not in {"mesh", "waterfall_x", "waterfall_y"}:
msg = (
"Parameter 'mesh_fill' can only be used when 'surftype' is 'mesh', "
"'waterfall_x', or 'waterfall_y'."
)
raise GMTInvalidInput(msg)

_surftype_mapping = {
"surface": "s",
"mesh": "m",
"surface+mesh": "sm",
"image": "c" if nan_transparent is True else "i",
"waterfall_x": "mx",
"waterfall_y": "my",
}

# Previously, 'surftype' was aliased to Q.
_old_surftype_syntax = surftype is not None and surftype not in _surftype_mapping

if _old_surftype_syntax and any(
v not in {None, False} for v in (dpi, mesh_fill, monochrome, nan_transparent)
):
msg = (
"Parameter 'surftype' is given with a raw GMT command string, and conflicts "
"with parameters 'dpi', 'mesh_fill', 'monochrome', or 'nan_transparent'."
)
raise GMTInvalidInput(msg)

aliasdict = AliasSystem(
Jz=Alias(zscale, name="zscale"),
JZ=Alias(zsize, name="zsize"),
Q=[
Alias(
surftype,
name="surftype",
mapping=_surftype_mapping if not _old_surftype_syntax else None,
),
Alias(dpi, name="dpi"),
Alias(mesh_fill, name="mesh_fill"),
Alias(monochrome, name="monochrome", prefix="+m"),
],
).add_common(
B=frame,
J=projection,
Expand Down
56 changes: 49 additions & 7 deletions pygmt/tests/test_grdview.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

import pytest
from pygmt import Figure, grdcut
from pygmt.exceptions import GMTTypeError
from pygmt.exceptions import GMTInvalidInput, GMTTypeError
from pygmt.helpers import GMTTempFile
from pygmt.helpers.testing import load_static_earth_relief

Expand Down Expand Up @@ -104,7 +104,7 @@ def test_grdview_with_cmap_for_image_plot(xrgrid):
Run grdview by passing in a grid and setting a colormap for producing an image plot.
"""
fig = Figure()
fig.grdview(grid=xrgrid, cmap="oleron", surftype="i")
fig.grdview(grid=xrgrid, cmap="oleron", surftype="image")
return fig


Expand All @@ -115,7 +115,7 @@ def test_grdview_with_cmap_for_surface_monochrome_plot(xrgrid):
monochrome plot.
"""
fig = Figure()
fig.grdview(grid=xrgrid, cmap="oleron", surftype="s+m")
fig.grdview(grid=xrgrid, cmap="oleron", surftype="surface", monochrome=True)
return fig


Expand All @@ -127,7 +127,11 @@ def test_grdview_with_cmap_for_perspective_surface_plot(xrgrid):
"""
fig = Figure()
fig.grdview(
grid=xrgrid, cmap="oleron", surftype="s", perspective=[225, 30], zscale=0.005
grid=xrgrid,
cmap="oleron",
surftype="surface",
perspective=[225, 30],
zscale=0.005,
)
return fig

Expand Down Expand Up @@ -179,7 +183,9 @@ def test_grdview_surface_plot_styled_with_contourpen(xrgrid):
surface plot.
"""
fig = Figure()
fig.grdview(grid=xrgrid, cmap="relief", surftype="s", contourpen="0.5p,black,dash")
fig.grdview(
grid=xrgrid, cmap="relief", surftype="surface", contourpen="0.5p,black,dash"
)
return fig


Expand All @@ -190,7 +196,9 @@ def test_grdview_surface_mesh_plot_styled_with_meshpen(xrgrid):
mesh plot.
"""
fig = Figure()
fig.grdview(grid=xrgrid, cmap="relief", surftype="sm", meshpen="0.5p,black,dash")
fig.grdview(
grid=xrgrid, cmap="relief", surftype="surface+mesh", meshpen="0.5p,black,dash"
)
return fig


Expand Down Expand Up @@ -226,7 +234,12 @@ def test_grdview_drapegrid_dataarray(xrgrid):

fig = Figure()
fig.grdview(
grid=xrgrid, drapegrid=drapegrid, cmap="oleron", surftype="c", frame=True
grid=xrgrid,
drapegrid=drapegrid,
cmap="oleron",
surftype="image",
nan_transparent=True,
frame=True,
)
return fig

Expand All @@ -239,3 +252,32 @@ def test_grdview_wrong_kind_of_drapegrid(xrgrid):
fig = Figure()
with pytest.raises(GMTTypeError):
fig.grdview(grid=xrgrid, drapegrid=dataset)


def test_grdview_invalid_surftype(gridfile):
"""
Test grdview with an invalid surftype or invalid combination of surftype and other
parameters.
"""
fig = Figure()
with pytest.raises(GMTInvalidInput):
fig.grdview(grid=gridfile, surftype="surface", dpi=300)
with pytest.raises(GMTInvalidInput):
fig.grdview(grid=gridfile, surftype="surface", nan_transparent=True)
with pytest.raises(GMTInvalidInput):
fig.grdview(grid=gridfile, surftype="surface", mesh_fill="red")


def test_grdview_mixed_syntax(gridfile):
"""
Run grdview using grid as a file and drapegrid as an xarray.DataArray.
"""
fig = Figure()
with pytest.raises(GMTInvalidInput):
fig.grdview(grid=gridfile, cmap="oleron", surftype="i", dpi=300)
with pytest.raises(GMTInvalidInput):
fig.grdview(grid=gridfile, cmap="oleron", surftype="m", mesh_fill="red")
with pytest.raises(GMTInvalidInput):
fig.grdview(grid=gridfile, cmap="oleron", surftype="s", monochrome=True)
with pytest.raises(GMTInvalidInput):
fig.grdview(grid=gridfile, cmap="oleron", surftype="i", nan_transparent=True)