Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
2f32c36
Figure.grdview: Pythonic syntax for surftype parameter
seisman Dec 2, 2025
25af727
Also migrate the meshpen parameter to the new alias system
seisman Dec 2, 2025
6be6476
Merge branch 'main' into grdview/surftype
seisman Dec 9, 2025
af37916
Revert "Also migrate the meshpen parameter to the new alias system"
seisman Dec 9, 2025
fcf69e6
Improve docstrings and add more checks
seisman Dec 9, 2025
19cd544
Update existing tests
seisman Dec 9, 2025
831d5c2
Update existing gallery examples
seisman Dec 9, 2025
16051a0
Add more tests
seisman Dec 9, 2025
af8da8f
Update examples/gallery/3d_plots/grdview_surface.py
seisman Dec 9, 2025
e1b7740
Fix a typo
seisman Dec 9, 2025
40beb74
Do not check invalid surftype
seisman Dec 9, 2025
0bd3efd
Merge branch 'main' into grdview/surftype
seisman Dec 10, 2025
aedfd1c
Update docstrings for mesh_pen
seisman Dec 10, 2025
74882f0
Merge branch 'main' into grdview/surftype
seisman Dec 18, 2025
d2accb9
Add one test for surftype
seisman Dec 18, 2025
ec9d3ec
Add one more test for dpi
seisman Dec 18, 2025
f1ea73f
Add one more test for mesh_pen/mesh_fill
seisman Dec 18, 2025
b8f7ffa
Fix test_grdview_mesh_pen_and_mesh_fill
seisman Dec 18, 2025
073d3b6
Remove duplicated tests
seisman Dec 18, 2025
bb098d0
Merge branch 'main' into grdview/surftype
seisman Jan 10, 2026
799db52
Merge branch 'main' into grdview/surftype
seisman Jan 10, 2026
f01d32e
Refactor to simplify the tests of option -Q
seisman Jan 10, 2026
97540c9
Update tests
seisman Jan 10, 2026
82718b8
Remove one more dvc file
seisman Jan 10, 2026
36079b2
Fix
seisman Jan 10, 2026
aa9eb73
Add tests for backward compatibility
seisman Jan 10, 2026
05682df
Merge branch 'main' into grdview/surftype
seisman Jan 19, 2026
4fc7e37
Merge branch 'main' into grdview/surftype
seisman Jan 23, 2026
6d83cb6
Improve the checking of conflicting parameters
seisman Jan 23, 2026
13b00ee
Merge branch 'main' into grdview/surftype
seisman Jan 24, 2026
a9ba352
Fix a typo [skip ci]
seisman Jan 26, 2026
0114016
Improve docstrings for gallery example
seisman Jan 26, 2026
ee0c403
Fix a typo
seisman Jan 26, 2026
fd5353d
Fix a typo
seisman Jan 26, 2026
ccd0cf0
Remove trailing whitespaces
seisman Jan 26, 2026
7cb3da6
Move parameter check to the _alias_option_Q function
seisman Jan 26, 2026
27ddac0
Merge remote-tracking branch 'origin/grdview/surftype' into grdview/s…
seisman Jan 26, 2026
824b694
Update baseline image
seisman Jan 26, 2026
25072e5
Merge branch 'main' into grdview/surftype
seisman Jan 26, 2026
050b7e6
Merge branch 'main' into grdview/surftype
seisman Jan 28, 2026
727a938
Move tests as doctests
seisman Jan 28, 2026
9ae8445
Merge branch 'main' into grdview/surftype
seisman Jan 29, 2026
b5c3840
Merge branch 'main' into grdview/surftype
seisman Jan 29, 2026
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
19 changes: 9 additions & 10 deletions examples/gallery/3d_plots/grdview_surface.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,14 @@
==================

The :meth:`pygmt.Figure.grdview()` method can plot 3-D surfaces with
``surftype="s"``. Here, we supply the data as an :class:`xarray.DataArray` with
the coordinate vectors ``x`` and ``y`` defined. Note that the ``perspective``
parameter here controls the azimuth and elevation angle of the view. We provide
a list of two arguments to ``frame`` - the first argument specifies the
:math:`x`- and :math:`y`-axes frame attributes and the second argument,
prepended with ``"z"``, specifies the :math:`z`-axis frame attributes.
Specifying the same scale for the ``projection`` and ``zscale`` parameters
ensures equal axis scaling. The ``shading`` parameter specifies illumination;
here we choose an azimuth of 45° with ``shading="+a45"``.
``surftype="surface"``. Here, we supply the data as an :class:`xarray.DataArray` with
the coordinate vectors ``x`` and ``y`` defined. Note that the ``perspective`` parameter
here controls the azimuth and elevation angle of the view. We provide a list of two
arguments to ``frame`` - the first argument specifies the :math:`x`- and :math:`y`-axes
frame attributes and the second argument, prepended with ``"z"``, specifies the
:math:`z`-axis frame attributes. Specifying the same scale for the ``projection`` and
``zscale`` parameters ensures equal axis scaling. The ``shading`` parameter specifies
illumination; here we choose an azimuth of 45° with ``shading="+a45"``.
"""

# %%
Expand Down Expand Up @@ -51,7 +50,7 @@ def ackley(x, y):
frame=["a5f1g5", "za5f1g5"],
projection=f"x{SCALE}c",
zscale=f"{SCALE}c",
surftype="s",
surftype="surface",
cmap="SCM/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="gmt/geo",
surftype="surface",
cmap="gmt/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="gmt/geo",
plane=1000, # Set the plane elevation to 1,000 meters
facade_fill="gray", # Color the facade in "gray"
Expand All @@ -88,7 +86,7 @@
frame=["xaf", "yaf", "WSnE"],
projection="M15c",
zsize="1.5c",
surftype="s",
surftype="surface",
cmap="gmt/geo",
plane=1000,
facade_fill="gray",
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
drape_grid=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
drape_grid=drape_grid, # Drape 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
169 changes: 135 additions & 34 deletions pygmt/src/grdview.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,45 +10,132 @@
from pygmt._typing import PathLike
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session, __gmt_version__
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import build_arg_list, deprecate_parameter, fmt_docstring, use_alias
from pygmt.src.grdinfo import grdinfo

__doctest_skip__ = ["grdview"]


def _alias_option_Q( # noqa: N802
surftype=None, dpi=None, mesh_fill=None, monochrome=False, nan_transparent=False
):
"""
Helper function to build the Alias list for the -Q option.

Examples
--------
>>> def parse(**kwargs):
... return AliasSystem(Q=_alias_option_Q(**kwargs)).get("Q")
>>> parse(surftype="surface")
's'
>>> parse(surftype="mesh")
'm'
>>> parse(surftype="surface+mesh")
'sm'
>>> parse(surftype="waterfall_x")
'mx'
>>> parse(surftype="waterfall_y")
'my'
>>> parse(surftype="image")
'i'
>>> parse(surftype="image", nan_transparent=True)
'c'
>>> parse(surftype="image", dpi=150)
'i150'
>>> parse(surftype="image", dpi=150, nan_transparent=True)
'c150'
>>> parse(surftype="mesh", mesh_fill="blue")
'mblue'
>>> parse(surftype="surface", monochrome=True)
's+m'
>>> parse(surftype="surface+mesh", monochrome=True)
'sm+m'

>>> # Check for backward compatibility with old raw GMT syntax.
>>> for surftype in ["s", "m", "sm", "i", "c", "mx", "my", "mblue", "i150"]:
... assert parse(surftype=surftype) == surftype
"""
_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 is not None and v is not 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)

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)

return [
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"),
]


@fmt_docstring
# TODO(PyGMT>=0.20.0): Remove the deprecated '*pen' parameters.
# TODO(PyGMT>=0.20.0): Remove the deprecated 'drapegrid' parameter.
@deprecate_parameter("contourpen", "contour_pen", "v0.18.0", remove_version="v0.20.0")
@deprecate_parameter("facadepen", "facade_pen", "v0.18.0", remove_version="v0.20.0")
@deprecate_parameter("meshpen", "mesh_pen", "v0.18.0", remove_version="v0.20.0")
@deprecate_parameter("drapegrid", "drape_grid", "v0.18.0", remove_version="v0.20.0")
@use_alias(
C="cmap",
G="drape_grid",
Q="surftype",
I="shading",
f="coltypes",
n="interpolation",
)
@use_alias(C="cmap", G="drape_grid", I="shading", f="coltypes", n="interpolation")
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,
nan_transparent: bool = False,
monochrome: bool = False,
contour_pen: str | None = None,
mesh_fill: str | None = None,
mesh_pen: str | None = None,
plane: float | bool = False,
facade_fill: str | None = None,
facade_pen: str | None = None,
projection: str | None = None,
zscale: float | str | None = None,
zsize: float | str | None = None,
frame: str | Sequence[str] | bool = False,
region: Sequence[float | str] | str | None = None,
frame: str | Sequence[str] | bool = False,
verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"]
| bool = False,
panel: int | Sequence[int] | bool = False,
transparency: float | None = None,
perspective: float | Sequence[float] | str | bool = False,
transparency: float | None = None,
**kwargs,
):
r"""
Expand All @@ -69,6 +156,7 @@ def grdview( # noqa: PLR0913
- JZ = zsize
- N = plane, facade_fill
- R = region
- Q = surftype, dpi, mesh_fill, nan_transparent, **+m**: monochrome
- V = verbose
- Wc = contour_pen
- Wf = facade_pen
Expand All @@ -80,15 +168,6 @@ def grdview( # noqa: PLR0913
Parameters
----------
$grid
region : str or list
*xmin/xmax/ymin/ymax*\ [**+r**][**+u**\ *unit*].
Specify the :doc:`region </tutorials/basics/regions>` of interest. When used
with ``perspective``, optionally append */zmin/zmax* to indicate the range to
use for the 3-D axes [Default is the region given by the input grid].
$projection
zscale/zsize
Set z-axis scaling or z-axis size.
$frame
cmap : str
The name of the color palette table to use.
drape_grid : str or :class:`xarray.DataArray`
Expand All @@ -97,24 +176,30 @@ def grdview( # noqa: PLR0913
Note that ``zscale`` and ``plane`` always refer to ``grid``. ``drape_grid`` only
provides the information pertaining to colors, which (if ``drape_grid`` is a
grid) will be looked-up via the CPT (see ``cmap``).
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 for the grid. Valid values are:

- ``"mesh"``: mesh plot [Default].
Copy link
Member

Choose a reason for hiding this comment

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

Default is technically None if no argument is passed to surftype. Should we remove the [Default] then, or allow for surftype=True to mean surftype="m"?

Copy link
Member Author

Choose a reason for hiding this comment

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

I feel surftype=True is not intuitive, mainly because:

  • surftype=False is meaningless in this context (False usually means "disable")
  • surftype=True is mapped to -Q but -Q without any arguments is invalid in GMT.

Copy link
Member

@weiji14 weiji14 Jan 28, 2026

Choose a reason for hiding this comment

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

Agree, so let's just remove the [Default] to only allow string literals

Suggested change
- ``"mesh"``: mesh plot [Default].
- ``"mesh"``: mesh plot.

and probably need to update the docs to remove [Default] too at https://docs.generic-mapping-tools.org/6.6/grdview.html#q if -Q by itself is invalid. Unless I'm missing some context?

Copy link
Member Author

Choose a reason for hiding this comment

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

"Default" actually means -Q is not required, and if not given, -Qm is used.

Copy link
Member

Choose a reason for hiding this comment

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

Ah ok, so surftype=None essentially maps to -Qm (even if -Q is not passed to GMT grdview). Then ok to keep the [Default] (though it is slightly confusing).

- ``"surface"``: surface plot.
- ``"surface+mesh"``: surface plot with mesh lines drawn on top of the surface.
- ``"image"``: image plot.
Comment on lines +183 to +185
Copy link
Member

@weiji14 weiji14 Jan 27, 2026

Choose a reason for hiding this comment

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

I've used surftype="sim" before here. It's been a few years so I can't remember, but maybe check if -Qsim is equal to -Qsm, or if we need to add a surface+image+mesh option 😂

Copy link
Member Author

@seisman seisman Jan 28, 2026

Choose a reason for hiding this comment

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

surftype="sim" is identical to surftype="s":

import pygmt

grd_relief = pygmt.datasets.load_earth_relief(
    resolution="15m", region=[-25, -13, 63.2, 66.7]
)

args = dict(
    region=[-25, -13, 63.2, 66.7],
    projection="M10c",
    perspective=(-150, 25),
    cmap="SCM/oleron",
    frame=True,
    zsize="1.5c",
    plane="+ggray",
)

fig = pygmt.Figure()
fig.grdview(grid=grd_relief, surftype="sim", **args)
fig.shift_origin(xshift="w+2c")
fig.grdview(grid=grd_relief, surftype="surface", **args)
fig.show()
map

-Qsim is taken as -Qs based on the GMT source code https://github.com/GenericMappingTools/gmt/blob/a091f7542cfded0ab0cc7f7fe1f899790b5eed56/src/grdview.c#L773-L777.

Copy link
Member

Choose a reason for hiding this comment

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

Nice, glad to know we don't need to add more combinations!

- ``"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`]
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.
contour_pen
Draw contour lines on top of surface or mesh (not image). Append pen attributes
used for the contours.
mesh_pen
Set the pen attributes used for the mesh. You must also select ``surftype`` of
**m** or **sm** for meshlines to be drawn.
Set the pen attributes used for the mesh. Need to set ``surftype`` to
``"mesh"``, or ``"surface+mesh"`` to draw meshlines.
mesh_fill
Set the mesh fill in mesh plot or waterfall plots [Default is white].
plane
Draw a plane at the specified z-level. If ``True``, defaults to the minimum
value in the grid. However, if ``region`` was used to set *zmin/zmax* then
Expand All @@ -135,6 +220,15 @@ def grdview( # noqa: PLR0913
**+m**\ *ambient* to specify azimuth, intensity, and ambient arguments for that
function, or just give **+d** to select the default arguments [Default is
``"+a-45+nt1+m0"``].
$projection
zscale/zsize
Set z-axis scaling or z-axis size.
region : str or list
*xmin/xmax/ymin/ymax*\ [**+r**][**+u**\ *unit*].
Specify the :doc:`region </tutorials/basics/regions>` of interest. When used
with ``perspective``, optionally append */zmin/zmax* to indicate the range to
use for the 3-D axes [Default is the region given by the input grid].
$frame
$verbose
$panel
$coltypes
Expand Down Expand Up @@ -167,7 +261,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="gmt/geo",
... )
Expand Down Expand Up @@ -195,6 +289,13 @@ def grdview( # noqa: PLR0913
aliasdict = AliasSystem(
Jz=Alias(zscale, name="zscale"),
JZ=Alias(zsize, name="zsize"),
Q=_alias_option_Q(
surftype=surftype,
dpi=dpi,
mesh_fill=mesh_fill,
monochrome=monochrome,
nan_transparent=nan_transparent,
),
N=[
Alias(plane, name="plane"),
Alias(facade_fill, name="facade_fill", prefix="+g"),
Expand Down
5 changes: 5 additions & 0 deletions pygmt/tests/baseline/test_grdview_image_dpi.png.dvc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
outs:
- md5: d384910b17de5a2a842cd2625761c821
size: 224724
hash: md5
path: test_grdview_image_dpi.png
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
outs:
- md5: 9158bd6308a9bb59fdcaf56e406954b3
size: 55008
hash: md5
path: test_grdview_mesh_pen_and_mesh_fill.png
5 changes: 5 additions & 0 deletions pygmt/tests/baseline/test_grdview_monochrome.png.dvc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
outs:
- md5: 9fff6fa175e44085570cb61b6bd62f6e
size: 104557
hash: md5
path: test_grdview_monochrome.png
5 changes: 5 additions & 0 deletions pygmt/tests/baseline/test_grdview_surftype.png.dvc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
outs:
- md5: 6a8a38827078400854c972bd24b0d898
size: 215417
hash: md5
path: test_grdview_surftype.png

This file was deleted.

This file was deleted.

This file was deleted.

Loading
Loading