Skip to content

Commit 088b0d1

Browse files
authored
Wrap grdview (#330)
Wrapping the grdview function raised at #328, to be implemented under base_plotting.py. Original GMT `grdview` documentation can be found at https://docs.generic-mapping-tools.org/latest/grdview.html. Storing sample test cases under test_grdview.py.
1 parent d29a1a6 commit 088b0d1

18 files changed

+328
-0
lines changed

doc/api/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ Plotting data and laying out the map:
2929
Figure.contour
3030
Figure.grdcontour
3131
Figure.grdimage
32+
Figure.grdview
3233
Figure.legend
3334
Figure.logo
3435
Figure.image

pygmt/base_plotting.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Base class with plot generating commands.
33
Does not define any special non-GMT methods (savefig, show, etc).
44
"""
5+
import contextlib
56
import csv
67
import os
78
import numpy as np
@@ -318,6 +319,114 @@ def grdimage(self, grid, **kwargs):
318319
arg_str = " ".join([fname, build_arg_string(kwargs)])
319320
lib.call_module("grdimage", arg_str)
320321

322+
@fmt_docstring
323+
@use_alias(
324+
R="region",
325+
J="projection",
326+
Jz="zscale",
327+
JZ="zsize",
328+
B="frame",
329+
C="cmap",
330+
G="drapegrid",
331+
N="plane",
332+
Q="surftype",
333+
Wc="contourpen",
334+
Wm="meshpen",
335+
Wf="facadepen",
336+
p="perspective",
337+
)
338+
@kwargs_to_strings(R="sequence", p="sequence")
339+
def grdview(self, grid, **kwargs):
340+
"""
341+
Create 3-D perspective image or surface mesh from a grid.
342+
343+
Reads a 2-D grid file and produces a 3-D perspective plot by drawing a
344+
mesh, painting a colored/gray-shaded surface made up of polygons, or by
345+
scanline conversion of these polygons to a raster image. Options
346+
include draping a data set on top of a surface, plotting of contours on
347+
top of the surface, and apply artificial illumination based on
348+
intensities provided in a separate grid file.
349+
350+
Full option list at :gmt-docs:`grdview.html`
351+
352+
Parameters
353+
----------
354+
grid : str or xarray.DataArray
355+
The file name of the input relief grid or the grid loaded as a
356+
DataArray.
357+
358+
zscale/zsize : float or str
359+
Set z-axis scaling or z-axis size.
360+
361+
cmap : str
362+
The name of the color palette table to use.
363+
364+
drapegrid : str or xarray.DataArray
365+
The file name or a DataArray of the image grid to be draped on top
366+
of the relief provided by grid. [Default determines colors from
367+
grid]. Note that -Jz and -N always refers to the grid. The
368+
drapegrid only provides the information pertaining to colors, which
369+
(if drapegrid is a grid) will be looked-up via the CPT (see -C).
370+
371+
plane : float or str
372+
``level[+gfill]``.
373+
Draws a plane at this z-level. If the optional color is provided
374+
via the +g modifier, and the projection is not oblique, the frontal
375+
facade between the plane and the data perimeter is colored.
376+
377+
surftype : str
378+
Specifies cover type of the grid.
379+
Select one of following settings:
380+
1. 'm' for mesh plot [Default].
381+
2. 'mx' or 'my' for waterfall plots (row or column profiles).
382+
3. 's' for surface plot.
383+
4. 'i' for image plot.
384+
5. 'c'. Same as 'i' but will make nodes with z = NaN transparent.
385+
For any of these choices, you may force a monochrome image by
386+
appending the modifier +m.
387+
388+
contourpen : str
389+
Draw contour lines on top of surface or mesh (not image). Append
390+
pen attributes used for the contours.
391+
meshpen : str
392+
Sets the pen attributes used for the mesh. You must also select -Qm
393+
or -Qsm for meshlines to be drawn.
394+
facadepen :str
395+
Sets the pen attributes used for the facade. You must also select
396+
-N for the facade outline to be drawn.
397+
398+
perspective : list or str
399+
``'[x|y|z]azim[/elev[/zlevel]][+wlon0/lat0[/z0]][+vx0/y0]'``.
400+
Select perspective view.
401+
402+
{aliases}
403+
"""
404+
kwargs = self._preprocess(**kwargs)
405+
kind = data_kind(grid, None, None)
406+
with Session() as lib:
407+
if kind == "file":
408+
file_context = dummy_context(grid)
409+
elif kind == "grid":
410+
file_context = lib.virtualfile_from_grid(grid)
411+
else:
412+
raise GMTInvalidInput(f"Unrecognized data type for grid: {type(grid)}")
413+
414+
with contextlib.ExitStack() as stack:
415+
fname = stack.enter_context(file_context)
416+
if "G" in kwargs:
417+
drapegrid = kwargs["G"]
418+
if data_kind(drapegrid) in ("file", "grid"):
419+
if data_kind(drapegrid) == "grid":
420+
drape_context = lib.virtualfile_from_grid(drapegrid)
421+
drapefile = stack.enter_context(drape_context)
422+
kwargs["G"] = drapefile
423+
else:
424+
raise GMTInvalidInput(
425+
f"Unrecognized data type for drapegrid: {type(drapegrid)}"
426+
)
427+
arg_str = " ".join([fname, build_arg_string(kwargs)])
428+
lib.call_module("grdview", arg_str)
429+
321430
@fmt_docstring
322431
@use_alias(
323432
R="region",
Loading
Loading
Loading
96.5 KB
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading
Loading

pygmt/tests/test_grdview.py

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
# pylint: disable=redefined-outer-name
2+
"""
3+
Tests grdview
4+
"""
5+
import pytest
6+
7+
from .. import Figure, which
8+
from ..datasets import load_earth_relief
9+
from ..exceptions import GMTInvalidInput
10+
from ..helpers import data_kind
11+
12+
13+
@pytest.fixture(scope="module")
14+
def grid():
15+
"Load the grid data from the sample earth_relief file"
16+
return load_earth_relief().sel(lat=slice(-49, -42), lon=slice(-118, -107))
17+
18+
19+
@pytest.mark.mpl_image_compare
20+
def test_grdview_grid_dataarray(grid):
21+
"""
22+
Run grdview by passing in a grid as an xarray.DataArray.
23+
"""
24+
fig = Figure()
25+
fig.grdview(grid=grid)
26+
return fig
27+
28+
29+
@pytest.mark.mpl_image_compare
30+
def test_grdview_grid_file_with_region_subset():
31+
"""
32+
Run grdview by passing in a grid filename, and cropping it to a region.
33+
"""
34+
gridfile = which("@earth_relief_60m", download="c")
35+
36+
fig = Figure()
37+
fig.grdview(grid=gridfile, region=[-116, -109, -47, -44])
38+
return fig
39+
40+
41+
def test_grdview_wrong_kind_of_grid(grid):
42+
"""
43+
Run grdview using grid input that is not an xarray.DataArray or file.
44+
"""
45+
dataset = grid.to_dataset() # convert xarray.DataArray to xarray.Dataset
46+
assert data_kind(dataset) == "matrix"
47+
48+
fig = Figure()
49+
with pytest.raises(GMTInvalidInput):
50+
fig.grdview(grid=dataset)
51+
52+
53+
@pytest.mark.mpl_image_compare
54+
def test_grdview_with_perspective(grid):
55+
"""
56+
Run grdview by passing in a grid and setting a perspective viewpoint with
57+
an azimuth from the SouthEast and an elevation angle 15 degrees from the
58+
z-plane.
59+
"""
60+
fig = Figure()
61+
fig.grdview(grid=grid, perspective=[135, 15])
62+
return fig
63+
64+
65+
@pytest.mark.mpl_image_compare
66+
def test_grdview_with_perspective_and_zscale(grid):
67+
"""
68+
Run grdview by passing in a grid and setting a perspective viewpoint with
69+
an azimuth from the SouthWest and an elevation angle 30 degrees from the
70+
z-plane, plus a z-axis scaling factor of 0.005.
71+
"""
72+
fig = Figure()
73+
fig.grdview(grid=grid, perspective=[225, 30], zscale=0.005)
74+
return fig
75+
76+
77+
@pytest.mark.mpl_image_compare
78+
def test_grdview_with_perspective_and_zsize(grid):
79+
"""
80+
Run grdview by passing in a grid and setting a perspective viewpoint with
81+
an azimuth from the SouthWest and an elevation angle 30 degrees from the
82+
z-plane, plus a z-axis size of 10cm.
83+
"""
84+
fig = Figure()
85+
fig.grdview(grid=grid, perspective=[225, 30], zsize="10c")
86+
return fig
87+
88+
89+
@pytest.mark.mpl_image_compare
90+
def test_grdview_with_cmap_for_image_plot(grid):
91+
"""
92+
Run grdview by passing in a grid and setting a colormap for producing an
93+
image plot.
94+
"""
95+
fig = Figure()
96+
fig.grdview(grid=grid, cmap="oleron", surftype="i")
97+
return fig
98+
99+
100+
@pytest.mark.mpl_image_compare
101+
def test_grdview_with_cmap_for_surface_monochrome_plot(grid):
102+
"""
103+
Run grdview by passing in a grid and setting a colormap for producing a
104+
surface monochrome plot.
105+
"""
106+
fig = Figure()
107+
fig.grdview(grid=grid, cmap="oleron", surftype="s+m")
108+
return fig
109+
110+
111+
@pytest.mark.mpl_image_compare
112+
def test_grdview_with_cmap_for_perspective_surface_plot(grid):
113+
"""
114+
Run grdview by passing in a grid and setting a colormap for producing a
115+
surface plot with a 3D perspective viewpoint.
116+
"""
117+
fig = Figure()
118+
fig.grdview(
119+
grid=grid, cmap="oleron", surftype="s", perspective=[225, 30], zscale=0.005,
120+
)
121+
return fig
122+
123+
124+
@pytest.mark.mpl_image_compare
125+
def test_grdview_on_a_plane(grid):
126+
"""
127+
Run grdview by passing in a grid and plotting it on a z-plane, while
128+
setting a 3D perspective viewpoint.
129+
"""
130+
fig = Figure()
131+
fig.grdview(grid=grid, plane=-4000, perspective=[225, 30], zscale=0.005)
132+
return fig
133+
134+
135+
@pytest.mark.mpl_image_compare
136+
def test_grdview_on_a_plane_with_colored_frontal_facade(grid):
137+
"""
138+
Run grdview by passing in a grid and plotting it on a z-plane whose frontal
139+
facade is colored gray, while setting a 3D perspective viewpoint.
140+
"""
141+
fig = Figure()
142+
fig.grdview(grid=grid, plane="-4000+ggray", perspective=[225, 30], zscale=0.005)
143+
return fig
144+
145+
146+
@pytest.mark.mpl_image_compare
147+
def test_grdview_with_perspective_and_zaxis_frame(grid):
148+
"""
149+
Run grdview by passing in a grid and plotting an annotated vertical
150+
z-axis frame.
151+
"""
152+
fig = Figure()
153+
fig.grdview(grid=grid, perspective=[225, 30], zscale=0.005, frame="zaf")
154+
return fig
155+
156+
157+
@pytest.mark.mpl_image_compare
158+
def test_grdview_surface_plot_styled_with_contourpen(grid):
159+
"""
160+
Run grdview by passing in a grid with styled contour lines plotted on top
161+
of a surface plot.
162+
"""
163+
fig = Figure()
164+
fig.grdview(grid=grid, cmap="relief", surftype="s", contourpen="0.5p,black,dash")
165+
return fig
166+
167+
168+
@pytest.mark.mpl_image_compare
169+
def test_grdview_surface_mesh_plot_styled_with_meshpen(grid):
170+
"""
171+
Run grdview by passing in a grid with styled mesh lines plotted on top of a
172+
surface mesh plot.
173+
"""
174+
fig = Figure()
175+
fig.grdview(grid=grid, cmap="relief", surftype="sm", meshpen="0.5p,black,dash")
176+
return fig
177+
178+
179+
@pytest.mark.mpl_image_compare
180+
def test_grdview_on_a_plane_styled_with_facadepen(grid):
181+
"""
182+
Run grdview by passing in a grid and plotting it on a z-plane with styled
183+
lines for the frontal facade.
184+
"""
185+
fig = Figure()
186+
fig.grdview(
187+
grid=grid,
188+
plane=-4000,
189+
perspective=[225, 30],
190+
zscale=0.005,
191+
facadepen="0.5p,blue,dash",
192+
)
193+
return fig
194+
195+
196+
@pytest.mark.mpl_image_compare
197+
def test_grdview_drapegrid_dataarray(grid):
198+
"""
199+
Run grdview by passing in both a grid and drapegrid as an xarray.DataArray,
200+
setting a colormap for producing an image plot.
201+
"""
202+
drapegrid = 1.1 * grid
203+
204+
fig = Figure()
205+
fig.grdview(grid=grid, drapegrid=drapegrid, cmap="oleron", surftype="c")
206+
return fig
207+
208+
209+
def test_grdview_wrong_kind_of_drapegrid(grid):
210+
"""
211+
Run grdview using drapegrid input that is not an xarray.DataArray or file.
212+
"""
213+
dataset = grid.to_dataset() # convert xarray.DataArray to xarray.Dataset
214+
assert data_kind(dataset) == "matrix"
215+
216+
fig = Figure()
217+
with pytest.raises(GMTInvalidInput):
218+
fig.grdview(grid=grid, drapegrid=dataset)

0 commit comments

Comments
 (0)