Skip to content

Commit 5790923

Browse files
committed
Merge branch 'main' into refactor/data_kind
2 parents 7c104a9 + dd26601 commit 5790923

File tree

7 files changed

+105
-112
lines changed

7 files changed

+105
-112
lines changed

.github/workflows/ci_tests_dev.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
strategy:
3737
fail-fast: false
3838
matrix:
39-
os: [ubuntu-24.04, macos-14, windows-2022]
39+
os: [ubuntu-24.04, macos-15, windows-2022]
4040
gmt_git_ref: [master]
4141
timeout-minutes: 30
4242
defaults:

doc/_templates/footer.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
{%- block extrafooter %}
55
<p>
6-
Built with <a href="https://sphinx-doc.org/">Sphinx</a>
6+
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a>
77
using a <a href="https://github.com/rtfd/sphinx_rtd_theme">theme</a>
88
provided by <a href="https://readthedocs.org">Read the Docs</a>
99
</p>

doc/techref/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ visit the {gmt-docs}`GMT Technical Reference <reference.html>`.
1010
1111
projections.md
1212
fonts.md
13+
patterns.md
1314
encodings.md
1415
environment_variables
1516
```

doc/techref/patterns.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Bit and hachure patterns
2+
3+
PyGMT supports a variety of bit and hachure patterns that can be used to fill polygons.
4+
5+
These patterns can be defined using the following syntax:
6+
7+
**P**|**p**_pattern_[**+b**_color_][**+f**_color_][**+r**_dpi_]
8+
9+
*pattern* can either be a number in the range 1-90 or the name of a 1-, 8-, or 24-bit
10+
image raster file. The former will result in one of the 90 predefined 64x64 bit-patterns
11+
provided by GMT (see the figure below). The latter allows the user to create customized,
12+
repeating images using image raster files.
13+
14+
By specifying upper case **P** instead of **p** the image will be bit-reversed, i.e.,
15+
white and black areas will be interchanged (only applies to 1-bit images or predefined
16+
bit-image patterns). For these patterns and other 1-bit images one may specify
17+
alternative **b**ackground and **f**oreground colors (by appending **+b**_color_ and/or
18+
**+f**_color_) that will replace the default white and black pixels, respectively.
19+
Excluding *color* from a fore- or background specification yields a transparent image
20+
where only the back- or foreground pixels will be painted. The **+r**_dpi_ modifier sets
21+
the resolution in dpi.
22+
23+
The image below shows the 90 predefined bit patterns that can be used in PyGMT.
24+
25+
![](https://docs.generic-mapping-tools.org/6.5/_images/GMT_App_E.png)
Lines changed: 38 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,44 @@
1-
r"""
1+
"""
22
Bit and hachure patterns
33
========================
44
5-
PyGMT allows using bit or hachure patterns via the ``fill`` parameter
6-
or similar parameters:
5+
In addition to colors, PyGMT also allows using bit and hachure patterns to fill
6+
symbols, polygons, and other areas, via the ``fill`` parameter or similar parameters.
7+
8+
Example method parameters that support bit and hachure patterns include:
79
8-
- :meth:`pygmt.Figure.coast`: Land and water masses via ``land`` and
9-
``water``, respectively
10+
- :meth:`pygmt.Figure.coast`: Land and water masses via ``land`` and ``water``
1011
- :meth:`pygmt.Figure.histogram`: Histogram bars via ``fill``
11-
- :meth:`pygmt.Figure.meca`: Focal mechanisms via ``compressionfill``
12-
and ``extensionfill``
12+
- :meth:`pygmt.Figure.meca`: Focal mechanisms via ``compressionfill`` and
13+
``extensionfill``
1314
- :meth:`pygmt.Figure.plot`: Symbols and polygons via ``fill``
1415
- :meth:`pygmt.Figure.rose`: Histogram sectors via ``fill``
1516
- :meth:`pygmt.Figure.solar`: Day-light terminators via ``fill``
1617
- :meth:`pygmt.Figure.ternary`: Symbols via ``fill``
17-
- :meth:`pygmt.Figure.velo`: Uncertainty wedges and velocity error
18-
ellipses via ``uncertaintyfill``
19-
- :meth:`pygmt.Figure.wiggle`: Anomalies via ``fillpositive``
20-
and ``fillnegative``
21-
22-
The required argument has the following form:
18+
- :meth:`pygmt.Figure.velo`: Uncertainty wedges and velocity error ellipses via
19+
``uncertaintyfill``
20+
- :meth:`pygmt.Figure.wiggle`: Anomalies via ``fillpositive`` and ``fillnegative``
2321
24-
**P**\|\ **p**\ *pattern*\ [**+b**\ *color*][**+f**\ *color*][**+r**\ *dpi*]
25-
26-
*pattern* can either be a number in the range 1-90 or the name of a
27-
1-, 8-, or 24-bit image raster file. The former will result in one of the 90
28-
predefined 64 x 64 bit-patterns provided by GMT; an overview can by found at
29-
:gmt-docs:`reference/predefined-patterns.html`.
30-
The latter allows the user to create customized, repeating images using image
31-
raster files.
32-
By specifying upper case **P** instead of **p** the image will be
33-
bit-reversed, i.e., white and black areas will be interchanged (only applies
34-
to 1-bit images or predefined bit-image patterns).
35-
For these patterns and other 1-bit images one may specify alternative
36-
**b**\ ackground and **f**\ oreground colors (by appending **+b**\ *color*
37-
and/or **+f**\ *color*) that will replace the default white and black pixels,
38-
respectively. Excluding *color* from a fore- or background specification yields
39-
a transparent image where only the back- or foreground pixels will be painted.
40-
The **+r**\ *dpi* modifier sets the resolution in dpi.
22+
GMT provides 90 predefined patterns that can be used in PyGMT. The patterns are numbered
23+
from 1 to 90, and can be colored and inverted. The resolution of the pattern
24+
can be changed, and the background and foreground colors can be set. For a complete list
25+
of available patterns and the full syntax to specify a pattern, refer to the
26+
:doc:`/techref/patterns`.
4127
"""
4228

4329
# %%
4430
import pygmt
4531

46-
y = 11
47-
48-
fig = pygmt.Figure()
49-
fig.basemap(
50-
region=[0, 10, 0, 12],
51-
projection="X10c",
52-
frame="rlbt+glightgray+tBit and Hachure Patterns",
53-
)
54-
55-
# To use a pattern as fill append "p" and the number of the desired
56-
# pattern. By default, the pattern is plotted in black and white
57-
# with a resolution of 300 dpi
58-
for pattern in [
32+
# A list of patterns that will be demonstrated.
33+
# To use a pattern as fill append "p" and the number of the desired pattern.
34+
# By default, the pattern is plotted in black and white with a resolution of 300 dpi.
35+
patterns = [
5936
# Plot a hachted pattern via pattern number 8
6037
"p8",
6138
# Plot a dotted pattern via pattern number 19
6239
"p19",
63-
# Set the background color ("+b") to "red3"
64-
# and the foreground color ("+f") to "lightgray"
40+
# Set the background color ("+b") to "red3" and the foreground color ("+f") to
41+
# "lightgray"
6542
"p19+bred3+flightbrown",
6643
# Invert the pattern by using a capitalized "P"
6744
"P19+bred3+flightbrown",
@@ -70,23 +47,21 @@
7047
# Make the background transparent by not giving a color after "+b";
7148
# works analogous for the foreground
7249
"p19+b+flightbrown+r100",
73-
]:
74-
# Plot a square with the pattern as fill
75-
fig.plot(
76-
x=2,
77-
y=y,
78-
style="s2c", # square with a width of 2 centimeters
79-
pen="1p,black", # 1 point thick, black outline
80-
fill=pattern,
81-
)
82-
# Add a description of the pattern
83-
fig.text(
84-
x=4,
85-
y=y,
86-
text=pattern,
87-
font="Courier-Bold",
88-
justify="ML", # justification of the text is Middle Left
89-
)
90-
y -= 2
50+
]
9151

52+
fig = pygmt.Figure()
53+
fig.basemap(
54+
region=[0, 10, 0, 12],
55+
projection="X10c",
56+
frame="rlbt+glightgray+tBit and Hachure Patterns",
57+
)
58+
59+
y = 11
60+
for pattern in patterns:
61+
# Plot a square with the pattern as fill.
62+
# The square has a size of 2 centimeters with a 1 point thick, black outline.
63+
fig.plot(x=2, y=y, style="s2c", pen="1p,black", fill=pattern)
64+
# Add a description of the pattern.
65+
fig.text(x=4, y=y, text=pattern, font="Courier-Bold", justify="ML")
66+
y -= 2
9267
fig.show()

pygmt/accessors.py

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
GMT accessor for :class:`xarray.DataArray`.
33
"""
44

5+
import contextlib
56
from pathlib import Path
67

78
import xarray as xr
@@ -115,22 +116,17 @@ class GMTDataArrayAccessor:
115116

116117
def __init__(self, xarray_obj):
117118
self._obj = xarray_obj
118-
119-
self._source = self._obj.encoding.get("source")
120-
if self._source is not None and Path(self._source).exists():
121-
try:
122-
# Get grid registration and grid type from the last two columns
123-
# of the shortened summary information of `grdinfo`.
119+
# Default to Gridline registration and Cartesian grid type
120+
self._registration = 0
121+
self._gtype = 0
122+
123+
# If the source file exists, get grid registration and grid type from the last
124+
# two columns of the shortened summary information of grdinfo.
125+
if (_source := self._obj.encoding.get("source")) and Path(_source).exists():
126+
with contextlib.suppress(ValueError):
124127
self._registration, self._gtype = map(
125-
int, grdinfo(self._source, per_column="n").split()[-2:]
128+
int, grdinfo(_source, per_column="n").split()[-2:]
126129
)
127-
except ValueError:
128-
self._registration = 0 # Default to Gridline registration
129-
self._gtype = 0 # Default to Cartesian grid type
130-
else:
131-
self._registration = 0 # Default to Gridline registration
132-
self._gtype = 0 # Default to Cartesian grid type
133-
del self._source
134130

135131
@property
136132
def registration(self):

pygmt/helpers/utils.py

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -188,17 +188,18 @@ def _check_encoding(
188188
return "ISOLatin1+"
189189

190190

191-
def data_kind( # noqa: PLR0911
191+
def data_kind(
192192
data: Any, required: bool = True
193193
) -> Literal[
194194
"arg", "file", "geojson", "grid", "image", "matrix", "stringio", "vectors"
195195
]:
196196
r"""
197197
Check the kind of data that is provided to a module.
198198
199-
The ``data`` argument can be in any types. Following data kinds are recognized:
199+
The argument passed to the ``data`` parameter can have any data type. The
200+
following data kinds are recognized and returned as ``kind``:
200201
201-
- ``"arg"``: data is ``None`` and ``required=False``, or bool, int, float,
202+
- ``"arg"``: ``data`` is ``None`` and ``required=False``, or bool, int, float,
202203
representing an optional argument, used for dealing with optional virtual files
203204
- ``"file"``: a string or a :class:`pathlib.PurePath` object or a sequence of them,
204205
representing one or more file names
@@ -294,36 +295,31 @@ def data_kind( # noqa: PLR0911
294295
>>> data_kind(data=None)
295296
'vectors'
296297
"""
297-
# One file or a list/tuple of files.
298-
if isinstance(data, str | pathlib.PurePath) or (
299-
isinstance(data, list | tuple)
300-
and all(isinstance(_file, str | pathlib.PurePath) for _file in data)
301-
):
302-
return "file"
303-
304-
# A StringIO object.
305-
if isinstance(data, io.StringIO):
306-
return "stringio"
307-
308-
# An option argument, mainly for dealing optional virtual files.
309-
if isinstance(data, bool | int | float) or (data is None and not required):
310-
return "arg"
311-
312-
# An xarray.DataArray object, representing a grid or an image.
313-
if isinstance(data, xr.DataArray):
314-
return "image" if len(data.dims) == 3 else "grid"
315-
316-
# Geo-like Python object that implements ``__geo_interface__`` (e.g.,
317-
# geopandas.GeoDataFrame or shapely.geometry).
318-
# Reference: https://gist.github.com/sgillies/2217756
319-
if hasattr(data, "__geo_interface__"):
320-
return "geojson"
321-
322-
# A 2-D numpy.ndarray.
323-
if isinstance(data, np.ndarray) and data.ndim == 2:
324-
return "matrix"
325-
326-
return "vectors"
298+
match data:
299+
case str() | pathlib.PurePath(): # One file.
300+
kind = "file"
301+
case list() | tuple() if all(
302+
isinstance(_file, str | pathlib.PurePath) for _file in data
303+
): # A list/tuple of files.
304+
kind = "file"
305+
case io.StringIO():
306+
kind = "stringio"
307+
case (bool() | int() | float()) | None if not required:
308+
# An option argument, mainly for dealing with optional virtual files.
309+
kind = "arg"
310+
case xr.DataArray():
311+
# An xarray.DataArray object, representing either a grid or an image.
312+
kind = "image" if len(data.dims) == 3 else "grid"
313+
case x if hasattr(x, "__geo_interface__"):
314+
# Geo-like Python object that implements ``__geo_interface__`` (e.g.,
315+
# geopandas.GeoDataFrame or shapely.geometry).
316+
# Reference: https://gist.github.com/sgillies/2217756
317+
kind = "geojson"
318+
case np.ndarray() if data.ndim == 2: # A 2-D numpy.ndarray object.
319+
kind = "matrix"
320+
case _: # Fall back to "vectors" if data is None and required=True.
321+
kind = "vectors"
322+
return kind # type: ignore[return-value]
327323

328324

329325
def non_ascii_to_octal(

0 commit comments

Comments
 (0)