Skip to content

Commit

Permalink
Basic support for grdimage with file input (#183)
Browse files Browse the repository at this point in the history
Enable grdimage for file input. Passing in `xarray.DataArray` isn't working
because of some bugs in the GMT C API. This will require some work
on the GMT side before we can use it. 
Implement basic support for grdinfo as well for testing.

Starts to implement #124
  • Loading branch information
leouieda authored Jun 3, 2018
1 parent 26c4849 commit 42625c0
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 7 deletions.
3 changes: 2 additions & 1 deletion gmt/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
# Import modules to make the high-level GMT Python API
from .session_management import begin as _begin, end as _end
from .figure import Figure
from .modules import info, which
from .modules import info, grdinfo, which
from . import datasets


# Get the version number through versioneer
Expand Down
34 changes: 34 additions & 0 deletions gmt/base_plotting.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,40 @@ def coast(self, **kwargs):
with LibGMT() as lib:
lib.call_module('coast', build_arg_string(kwargs))

@fmt_docstring
@use_alias(R='region', J='projection', B='frame', I='shading', C='cmap')
@kwargs_to_strings(R='sequence')
def grdimage(self, grid, **kwargs):
"""
Project grids or images and plot them on maps.
Takes a grid file name or an xarray.DataArray object as input.
{gmt_module_docs}
{aliases}
Parameters
----------
grid : str or xarray.DataArray
The file name of the input grid or the grid loaded as a DataArray.
"""
kwargs = self._preprocess(**kwargs)
kind = data_kind(grid, None, None)
with LibGMT() as lib:
if kind == 'file':
file_context = dummy_context(grid)
elif kind == 'grid':
raise NotImplementedError(
"Sorry, DataArray support is not yet functional.")
else:
raise GMTInvalidInput("Unrecognized data type: {}"
.format(type(grid)))
with file_context as fname:
arg_str = ' '.join([fname, build_arg_string(kwargs)])
lib.call_module('grdimage', arg_str)

@fmt_docstring
@use_alias(R='region', J='projection', B='frame', S='style', G='color',
W='pen', i='columns', C='cmap')
Expand Down
5 changes: 3 additions & 2 deletions gmt/clib/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,8 @@ def create_data(self, family, geometry, mode, **kwargs):

family_int = self._parse_constant(family, valid=self.data_families,
valid_modifiers=self.data_vias)
mode_int = self._parse_constant(mode, valid=self.data_modes)
mode_int = self._parse_constant(mode, valid=self.data_modes,
valid_modifiers=["GMT_GRID_IS_GEO"])
geometry_int = self._parse_constant(
geometry, valid=self.data_geometries)
registration_int = self._parse_constant(
Expand Down Expand Up @@ -939,7 +940,7 @@ def open_virtual_file(self, family, geometry, direction, data):
valid=self.data_geometries)
direction_int = self._parse_constant(
direction, valid=['GMT_IN', 'GMT_OUT'],
valid_modifiers=['GMT_IS_REFERENCE'])
valid_modifiers=['GMT_IS_REFERENCE', 'GMT_IS_DUPLICATE'])

buff = ctypes.create_string_buffer(self.get_constant('GMT_STR16'))

Expand Down
2 changes: 1 addition & 1 deletion gmt/clib/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ def dataarray_to_matrix(grid):
.format(dim))
region.extend([coord.min(), coord.max()])
inc.append(coord_inc)
matrix = as_c_contiguous(grid.values[:])
matrix = as_c_contiguous(grid.values[::-1])
return matrix, region, inc


Expand Down
6 changes: 5 additions & 1 deletion gmt/helpers/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@
import webbrowser
from contextlib import contextmanager

import xarray as xr

from ..exceptions import GMTInvalidInput


def data_kind(data, x, y):
def data_kind(data, x=None, y=None):
"""
Check what kind of data is provided to a module.
Expand Down Expand Up @@ -72,6 +74,8 @@ def data_kind(data, x, y):

if isinstance(data, str):
kind = 'file'
elif isinstance(data, xr.DataArray):
kind = 'grid'
elif data is not None:
kind = 'matrix'
else:
Expand Down
41 changes: 40 additions & 1 deletion gmt/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,49 @@
Non-plot GMT modules.
"""
from .clib import LibGMT
from .helpers import build_arg_string, fmt_docstring, GMTTempFile, use_alias
from .helpers import build_arg_string, fmt_docstring, GMTTempFile, use_alias, \
data_kind, dummy_context
from .exceptions import GMTInvalidInput


@fmt_docstring
def grdinfo(grid, **kwargs):
"""
Get information about a grid.
Can read the grid from a file or given as an xarray.DataArray grid.
{gmt_module_docs}
Parameters
----------
grid : str or xarray.DataArray
The file name of the input grid or the grid loaded as a DataArray.
Returns
-------
info : str
A string with information about the grid.
"""
kind = data_kind(grid, None, None)
with GMTTempFile() as outfile:
with LibGMT() as lib:
if kind == 'file':
file_context = dummy_context(grid)
elif kind == 'grid':
file_context = lib.grid_to_vfile(grid)
else:
raise GMTInvalidInput("Unrecognized data type: {}"
.format(type(grid)))
with file_context as infile:
arg_str = ' '.join([infile, build_arg_string(kwargs),
"->" + outfile.name])
lib.call_module('grdinfo', arg_str)
result = outfile.read()
return result


@fmt_docstring
def info(fname, **kwargs):
"""
Expand Down
Binary file added gmt/tests/baseline/test_grdimage_file.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 28 additions & 0 deletions gmt/tests/test_grdimage.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
"""
Test Figure.grdimage
"""
import pytest
import numpy as np

from .. import Figure
from ..exceptions import GMTInvalidInput
from ..datasets import load_earth_relief


@pytest.mark.mpl_image_compare
def test_grdimage_file():
"Plot an image using file input"
fig = Figure()
fig.grdimage("@earth_relief_60m", cmap='ocean', region='-180/180/-70/70',
projection='W0/10i', shading=True)
return fig


def test_grdimage_fails():
"Should fail for unrecognized input"
fig = Figure()
with pytest.raises(GMTInvalidInput):
fig.grdimage(np.arange(20).reshape((4, 5)))
grid = load_earth_relief()
with pytest.raises(NotImplementedError):
fig.grdimage(grid)
22 changes: 21 additions & 1 deletion gmt/tests/test_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
import pytest
import numpy as np

from .. import info
from .. import info, grdinfo
from ..exceptions import GMTInvalidInput
from ..datasets import load_earth_relief

TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), 'data')
POINTS_DATA = os.path.join(TEST_DATA_DIR, 'points.txt')
Expand Down Expand Up @@ -53,3 +54,22 @@ def test_info_fails():
info(fname=21)
with pytest.raises(GMTInvalidInput):
info(fname=np.arange(20))


def test_grdinfo():
"Make sure grd info works as expected"
grid = load_earth_relief()
result = grdinfo(grid, L=0, C='n')
assert result.strip() == "-180 180 -90 90 -8425 5551 1 1 361 181"


def test_grdinfo_file():
"Test grdinfo with file input"
result = grdinfo("@earth_relief_60m", L=0, C='n')
assert result.strip() == "-180 180 -90 90 -8425 5551 1 1 361 181"


def test_grdinfo_fails():
"Check that grdinfo fails correctly"
with pytest.raises(GMTInvalidInput):
grdinfo(np.arange(10).reshape((5, 2)))

0 comments on commit 42625c0

Please sign in to comment.