Skip to content

Wrap clip #1779

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Plotting tabular data
Figure.contour
Figure.histogram
Figure.meca
Figure.clip
Figure.plot
Figure.plot3d
Figure.rose
Expand Down
1 change: 1 addition & 0 deletions pygmt/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,7 @@ def _repr_html_(self) -> str:

from pygmt.src import ( # type: ignore[misc]
basemap,
clip,
coast,
colorbar,
contour,
Expand Down
1 change: 1 addition & 0 deletions pygmt/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from pygmt.src.basemap import basemap
from pygmt.src.binstats import binstats
from pygmt.src.blockm import blockmean, blockmedian, blockmode
from pygmt.src.clip import clip
from pygmt.src.coast import coast
from pygmt.src.colorbar import colorbar
from pygmt.src.config import config
Expand Down
107 changes: 107 additions & 0 deletions pygmt/src/clip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
"""
clip - Create a polygonal clip path.
"""

import contextlib

from pygmt.clib import Session
from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias


@fmt_docstring
@contextlib.contextmanager
@use_alias(
A="straight_line",
B="frame",
J="projection",
N="invert",
R="region",
W="pen",
V="verbose",
)
@kwargs_to_strings(R="sequence")
def clip(self, data=None, x=None, y=None, **kwargs):
r"""
Create a polygonal clip path.

This function sets a clip path for the figure. The clip path is applied
to plotting functions that are called within the context manager.

Full option list at :gmt-docs:`clip.html`

{aliases}

Parameters
----------
data : str or {table-like}
Pass in either a file name to an ASCII data table, a 2D {table-classes}.
x/y : 1d arrays
The x and y coordinates of the clip path.
{frame}
{projection}
{region}
straight_line
By default, line segments are drawn as straight lines in the Cartesian and polar
coordinate systems, and as great circle arcs (by resampling coarse input data
along such arcs) in the geographic coordinate system. The ``straight_line``
parameter can control the drawing of line segments. Valid values are:

- ``True``: Draw line segments as straight lines in geographic coordinate
systems.
- ``"x"``: Draw line segments by first along *x*, then along *y*.
- ``"y"``: Draw line segments by first along *y*, then along *x*.

Here, *x* and *y* have different meanings depending on the coordinate system:

- **Cartesian** coordinate system: *x* and *y* are the X- and Y-axes.
- **Polar** coordinate system: *x* and *y* are theta and radius.
- **Geographic** coordinate system: *x* and *y* are parallels and meridians.

.. attention::

There exits a bug in GMT<=6.5.0 that, in geographic coordinate systems, the
meaning of *x* and *y* is reversed, i.e., *x* means meridians and *y* means
parallels. The bug is fixed by upstream
`PR #8648 <https://github.com/GenericMappingTools/gmt/pull/8648>`__.
invert : bool
Invert the sense of what is inside and outside. For example, when using a single
path, ``invert=True`` means only plot points outside that path will be shown.
Cannot be used together with ``frame``.
{verbose}
pen : str
Draw outline of clip path using given pen attributes before clipping is
initiated [Default is no outline].

Examples
--------
>>> import pygmt
>>>
>>> # Create x,y data for the clip path
>>> x = [-60, 60, 60, -60]
>>> y = [-30, -30, 30, 30]
>>>
>>> # Load the 1 degree global earth relief
>>> grid = pygmt.datasets.load_earth_relief()
>>>
>>> # Create a figure and draw the map frame
>>> fig = pygmt.Figure()
>>> fig.basemap(region="d", projection="W15c", frame=True)
>>>
>>> # Use a "with" statement to initialize the clip context manager
>>> with fig.clip(x=x, y=y):
... # Map elements under the "with" statement are clipped
... fig.grdimage(grid=grid)
>>> fig.show() # doctest: +SKIP
<IPython.core.display.Image object>
"""
kwargs = self._preprocess(**kwargs) # pylint: disable=protected-access
with Session() as lib:
try:
with lib.virtualfile_in(check_kind="vector", data=data, x=x, y=y) as vintbl:
lib.call_module(
module="clip", args=build_arg_list(kwargs, infile=vintbl)
)
yield
finally:
# End the top most clipping path
lib.call_module(module="clip", args="-C1")
4 changes: 4 additions & 0 deletions pygmt/tests/baseline/test_clip.png.dvc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
outs:
- md5: 449fec4d58132742abb615931e6e240a
size: 7968
path: test_clip.png
80 changes: 80 additions & 0 deletions pygmt/tests/test_clip.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""
Tests for fig.clip.
"""

import numpy as np
import pandas as pd
import pytest
import xarray as xr
from pygmt import Figure
from pygmt.helpers.testing import load_static_earth_relief


@pytest.fixture(scope="module", name="grid")
def fixture_grid():
"""
Load the grid data from the static_earth_relief file.
"""
return load_static_earth_relief()


@pytest.fixture(scope="module", name="dataframe")
def fixture_dataframe():
"""
Load the table data from the sample bathymetry dataset.
"""
return pd.DataFrame(data={"x": [-52, -50, -50, -52], "y": [-20, -20, -16, -16]})


@pytest.fixture(scope="module", name="region")
def fixture_region():
"""
Load the table data from the sample bathymetry dataset.
"""
return [-55, -47, -24, -10]


@pytest.fixture(scope="module", name="projection")
def fixture_projection():
"""
Load the table data from the sample bathymetry dataset.
"""
return "M4c"


@pytest.mark.mpl_image_compare(filename="test_clip.png")
def test_clip_xy(grid, dataframe, region, projection):
"""
Test clip with x,y input.
"""
fig = Figure()
fig.basemap(region=region, frame=True, projection=projection)
with fig.clip(x=dataframe["x"], y=dataframe["y"]):
fig.grdimage(grid=grid)
return fig


@pytest.mark.parametrize("array_func", [np.array, xr.Dataset])
@pytest.mark.mpl_image_compare(filename="test_clip.png")
def test_clip_matrix(array_func, dataframe, grid, region, projection):
"""
Test clip with matrix input for the clip path.
"""
table = array_func(dataframe)
fig = Figure()
fig.basemap(region=region, frame=True, projection=projection)
with fig.clip(data=table):
fig.grdimage(grid=grid, region=region)
return fig


@pytest.mark.mpl_image_compare(filename="test_clip.png")
def test_clip_dataframe(grid, dataframe, region, projection):
"""
Test clip with dataframe input for the clip path.
"""
fig = Figure()
fig.basemap(region=region, frame=True, projection=projection)
with fig.clip(data=dataframe):
fig.grdimage(grid=grid, region=region)
return fig
Loading