Skip to content

Commit ca91890

Browse files
authored
Merge branch 'master' into enable-windows
2 parents 4e6bf3b + 9a4c0a0 commit ca91890

9 files changed

+94
-20
lines changed

Makefile

+5-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ test:
2929
@echo ""
3030
@cd $(TESTDIR); python -c "import $(PROJECT); $(PROJECT).show_versions()"
3131
@echo ""
32-
cd $(TESTDIR); pytest $(PYTEST_ARGS) $(PROJECT)
32+
# There are two steps to the test here because `test_grdimage_over_dateline`
33+
# passes only when it runs before the other tests.
34+
# See also https://github.com/GenericMappingTools/pygmt/pull/476
35+
cd $(TESTDIR); pytest -m runfirst $(PYTEST_ARGS) $(PROJECT)
36+
cd $(TESTDIR); pytest -m 'not runfirst' $(PYTEST_ARGS) $(PROJECT)
3337
cp $(TESTDIR)/coverage.xml .
3438
cp -r $(TESTDIR)/htmlcov .
3539
rm -r $(TESTDIR)

pygmt/clib/conversion.py

+11-6
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def dataarray_to_matrix(grid):
5050
>>> grid = load_earth_relief(resolution='01d')
5151
>>> matrix, region, inc = dataarray_to_matrix(grid)
5252
>>> print(region)
53-
[-179.5, 179.5, -89.5, 89.5]
53+
[-180.0, 180.0, -90.0, 90.0]
5454
>>> print(inc)
5555
[1.0, 1.0]
5656
>>> type(matrix)
@@ -67,7 +67,7 @@ def dataarray_to_matrix(grid):
6767
>>> print(matrix.shape)
6868
(31, 71)
6969
>>> print(region)
70-
[-149.5, -79.5, -79.5, -49.5]
70+
[-150.0, -79.0, -80.0, -49.0]
7171
>>> print(inc)
7272
[1.0, 1.0]
7373
>>> # but not if only taking every other grid point.
@@ -77,7 +77,7 @@ def dataarray_to_matrix(grid):
7777
>>> print(matrix.shape)
7878
(16, 36)
7979
>>> print(region)
80-
[-149.5, -79.5, -79.5, -49.5]
80+
[-150.5, -78.5, -80.5, -48.5]
8181
>>> print(inc)
8282
[2.0, 2.0]
8383
@@ -102,14 +102,19 @@ def dataarray_to_matrix(grid):
102102
dim
103103
)
104104
)
105-
region.extend([coord.min(), coord.max()])
105+
region.extend(
106+
[
107+
coord.min() - coord_inc / 2 * grid.gmt.registration,
108+
coord.max() + coord_inc / 2 * grid.gmt.registration,
109+
]
110+
)
106111
inc.append(coord_inc)
107112

108-
if any([i < 0 for i in inc]): # Sort grid when there are negative increments
113+
if any(i < 0 for i in inc): # Sort grid when there are negative increments
109114
inc = [abs(i) for i in inc]
110115
grid = grid.sortby(variables=list(grid.dims), ascending=True)
111116

112-
matrix = as_c_contiguous(grid.values[::-1])
117+
matrix = as_c_contiguous(grid[::-1].values)
113118
return matrix, region, inc
114119

115120

pygmt/clib/session.py

+23-12
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
"GMT_IS_SURFACE",
4545
]
4646

47-
MODES = ["GMT_CONTAINER_ONLY", "GMT_OUTPUT"]
47+
MODES = ["GMT_CONTAINER_ONLY", "GMT_IS_OUTPUT"]
4848

4949
REGISTRATIONS = ["GMT_GRID_PIXEL_REG", "GMT_GRID_NODE_REG"]
5050

@@ -113,7 +113,7 @@ class Session:
113113
... )
114114
... # Read the contents of the temp file before it's deleted.
115115
... print(fout.read().strip())
116-
-179.5 179.5 -89.5 89.5 -8182 5651.5 1 1 360 180 0 0
116+
-180 180 -90 90 -8182 5651.5 1 1 360 180 1 1
117117
"""
118118

119119
# The minimum version of GMT required
@@ -511,13 +511,13 @@ def create_data(self, family, geometry, mode, **kwargs):
511511
----------
512512
family : str
513513
A valid GMT data family name (e.g., ``'GMT_IS_DATASET'``). See the
514-
``data_families`` attribute for valid names.
514+
``FAMILIES`` attribute for valid names.
515515
geometry : str
516516
A valid GMT data geometry name (e.g., ``'GMT_IS_POINT'``). See the
517-
``data_geometries`` attribute for valid names.
517+
``GEOMETRIES`` attribute for valid names.
518518
mode : str
519-
A valid GMT data mode (e.g., ``'GMT_OUTPUT'``). See the
520-
``data_modes`` attribute for valid names.
519+
A valid GMT data mode (e.g., ``'GMT_IS_OUTPUT'``). See the
520+
``MODES`` attribute for valid names.
521521
dim : list of 4 integers
522522
The dimensions of the dataset. See the documentation for the GMT C
523523
API function ``GMT_Create_Data`` (``src/gmt_api.c``) for the full
@@ -530,7 +530,7 @@ def create_data(self, family, geometry, mode, **kwargs):
530530
inc : list of 2 floats
531531
The increments between points of the dataset. See the C function
532532
documentation.
533-
registration : int
533+
registration : str
534534
The node registration (what the coordinates mean). Can be
535535
``'GMT_GRID_PIXEL_REG'`` or ``'GMT_GRID_NODE_REG'``. Defaults to
536536
``'GMT_GRID_NODE_REG'``.
@@ -563,7 +563,9 @@ def create_data(self, family, geometry, mode, **kwargs):
563563

564564
family_int = self._parse_constant(family, valid=FAMILIES, valid_modifiers=VIAS)
565565
mode_int = self._parse_constant(
566-
mode, valid=MODES, valid_modifiers=["GMT_GRID_IS_GEO"]
566+
mode,
567+
valid=MODES,
568+
valid_modifiers=["GMT_GRID_IS_CARTESIAN", "GMT_GRID_IS_GEO"],
567569
)
568570
geometry_int = self._parse_constant(geometry, valid=GEOMETRIES)
569571
registration_int = self._parse_constant(
@@ -856,12 +858,12 @@ def write_data(self, family, geometry, mode, wesn, output, data):
856858
----------
857859
family : str
858860
A valid GMT data family name (e.g., ``'GMT_IS_DATASET'``). See the
859-
``data_families`` attribute for valid names. Don't use the
861+
``FAMILIES`` attribute for valid names. Don't use the
860862
``GMT_VIA_VECTOR`` or ``GMT_VIA_MATRIX`` constructs for this. Use
861863
``GMT_IS_VECTOR`` and ``GMT_IS_MATRIX`` instead.
862864
geometry : str
863865
A valid GMT data geometry name (e.g., ``'GMT_IS_POINT'``). See the
864-
``data_geometries`` attribute for valid names.
866+
``GEOMETRIES`` attribute for valid names.
865867
mode : str
866868
How the data is to be written to the file. This option varies
867869
depending on the given family. See the GMT API documentation for
@@ -1243,21 +1245,30 @@ def virtualfile_from_grid(self, grid):
12431245
... args = '{} -L0 -Cn ->{}'.format(fin, fout.name)
12441246
... ses.call_module('grdinfo', args)
12451247
... print(fout.read().strip())
1246-
-179.5 179.5 -89.5 89.5 -8182 5651.5 1 1 360 180 0 0
1248+
-180 180 -90 90 -8182 5651.5 1 1 360 180 1 1
12471249
>>> # The output is: w e s n z0 z1 dx dy n_columns n_rows reg gtype
12481250
12491251
"""
1252+
_gtype = {0: "GMT_GRID_IS_CARTESIAN", 1: "GMT_GRID_IS_GEO"}[grid.gmt.gtype]
1253+
_reg = {0: "GMT_GRID_NODE_REG", 1: "GMT_GRID_PIXEL_REG"}[grid.gmt.registration]
1254+
12501255
# Conversion to a C-contiguous array needs to be done here and not in
12511256
# put_matrix because we need to maintain a reference to the copy while
12521257
# it is being used by the C API. Otherwise, the array would be garbage
12531258
# collected and the memory freed. Creating it in this context manager
12541259
# guarantees that the copy will be around until the virtual file is
12551260
# closed. The conversion is implicit in dataarray_to_matrix.
12561261
matrix, region, inc = dataarray_to_matrix(grid)
1262+
12571263
family = "GMT_IS_GRID|GMT_VIA_MATRIX"
12581264
geometry = "GMT_IS_SURFACE"
12591265
gmt_grid = self.create_data(
1260-
family, geometry, mode="GMT_CONTAINER_ONLY", ranges=region, inc=inc
1266+
family,
1267+
geometry,
1268+
mode=f"GMT_CONTAINER_ONLY|{_gtype}",
1269+
ranges=region,
1270+
inc=inc,
1271+
registration=_reg,
12611272
)
12621273
self.put_matrix(gmt_grid, matrix)
12631274
args = (family, geometry, "GMT_IN|GMT_IS_REFERENCE", gmt_grid)

pygmt/helpers/decorators.py

+5
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@
4949
- 'c' for bicubic [Default]
5050
- 'l' for bilinear
5151
- 'n' for nearest-neighbor""",
52+
"registration": """\
53+
registration : str
54+
``[g|p]``
55+
Force output grid to be gridline (g) or pixel (p) node registered.
56+
Default is gridline (g).""",
5257
}
5358

5459

Loading

pygmt/tests/test_grdimage.py

+42
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Test Figure.grdimage
33
"""
44
import numpy as np
5+
import xarray as xr
56
import pytest
67

78
from .. import Figure
@@ -15,6 +16,27 @@ def fixture_grid():
1516
return load_earth_relief(registration="gridline")
1617

1718

19+
@pytest.fixture(scope="module", name="xrgrid")
20+
def fixture_xrgrid():
21+
"""
22+
Create a sample xarray.DataArray grid for testing
23+
"""
24+
longitude = np.arange(0, 360, 1)
25+
latitude = np.arange(-89, 90, 1)
26+
x = np.sin(np.deg2rad(longitude))
27+
y = np.linspace(start=0, stop=1, num=179)
28+
data = y[:, np.newaxis] * x
29+
30+
return xr.DataArray(
31+
data,
32+
coords=[
33+
("latitude", latitude, {"units": "degrees_north"}),
34+
("longitude", longitude, {"units": "degrees_east"}),
35+
],
36+
attrs={"actual_range": [-1, 1]},
37+
)
38+
39+
1840
@pytest.mark.mpl_image_compare
1941
def test_grdimage(grid):
2042
"Plot an image using an xarray grid"
@@ -51,3 +73,23 @@ def test_grdimage_fails():
5173
fig = Figure()
5274
with pytest.raises(GMTInvalidInput):
5375
fig.grdimage(np.arange(20).reshape((4, 5)))
76+
77+
78+
# This test needs to run first before the other tests (on Linux at least) so
79+
# that a black image isn't plotted due to an `inf` value when resampling.
80+
# See also https://github.com/GenericMappingTools/pygmt/pull/476
81+
@pytest.mark.runfirst
82+
@pytest.mark.mpl_image_compare
83+
def test_grdimage_over_dateline(xrgrid):
84+
"""
85+
Ensure no gaps are plotted over the 180 degree international dateline.
86+
Specifically checking that `xrgrid.gmt.gtype = 1` sets `GMT_GRID_IS_GEO`,
87+
and that `xrgrid.gmt.registration = 0` sets `GMT_GRID_NODE_REG`. Note that
88+
there would be a gap over the dateline if a pixel registered grid is used.
89+
See also https://github.com/GenericMappingTools/pygmt/issues/375.
90+
"""
91+
fig = Figure()
92+
assert xrgrid.gmt.registration == 0 # gridline registration
93+
xrgrid.gmt.gtype = 1 # geographic coordinate system
94+
fig.grdimage(grid=xrgrid, region="g", projection="A0/0/1c", V="i")
95+
return fig

pygmt/tests/test_grdinfo.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ def test_grdinfo():
1313
"Make sure grd info works as expected"
1414
grid = load_earth_relief(registration="gridline")
1515
result = grdinfo(grid, L=0, C="n")
16-
assert result.strip() == "-180 180 -90 90 -8592.5 5559 1 1 361 181 0 0"
16+
assert result.strip() == "-180 180 -90 90 -8592.5 5559 1 1 361 181 0 1"
1717

1818

1919
def test_grdinfo_file():

pygmt/tests/test_grdview.py

+6
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ def fixture_grid():
1717
)
1818

1919

20+
@pytest.mark.xfail(
21+
reason="Baseline image generated using Cartesian instead of Geographic coordinates"
22+
)
2023
@pytest.mark.mpl_image_compare
2124
def test_grdview_grid_dataarray(grid):
2225
"""
@@ -54,6 +57,9 @@ def test_grdview_wrong_kind_of_grid(grid):
5457
fig.grdview(grid=dataset)
5558

5659

60+
@pytest.mark.xfail(
61+
reason="Baseline image generated using Cartesian instead of Geographic coordinates"
62+
)
5763
@pytest.mark.mpl_image_compare
5864
def test_grdview_with_perspective(grid):
5965
"""

setup.cfg

+1
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ exclude =
1616
[tool:pytest]
1717
markers =
1818
mpl_image_compare: compare generated plots with correct baseline version
19+
runfirst: runs the test(s) first before the other ones

0 commit comments

Comments
 (0)