-
Notifications
You must be signed in to change notification settings - Fork 232
Add the Pattern class for specifying bit and hachure patterns to fill symbols and polygons #4020
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
Changes from 16 commits
1fd9d4a
30d6b92
db82469
3031c59
ed1ba89
57e9c4e
3ba2006
5dfa0d2
0ca48c6
43bf9ff
2a18366
5cda812
dcbcaa8
ff3419c
1b17ab0
994c3be
8e560c3
f627d28
28be123
a8af0e7
56bbf3c
74da7a8
e9eca8e
43036c5
4431649
1b453a9
938b5fb
b2b1250
6dfff08
e715fdb
806c912
61dedd2
5774b35
8131163
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -212,6 +212,7 @@ Class-style Parameters | |
:toctree: generated | ||
|
||
Box | ||
Pattern | ||
|
||
Enums | ||
----- | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
# Import the required packages | ||
import numpy as np | ||
import pygmt | ||
from pygmt.params import Pattern | ||
|
||
# %% | ||
# Generate random data from a normal distribution: | ||
|
@@ -204,10 +205,8 @@ | |
frame=["wSnE", "xaf10", "ya5f1+lCumulative counts"], | ||
data=data01, | ||
series=10, | ||
# Use pattern ("p") number 8 as fill for the bars | ||
# Set the background ("+b") to white [Default] | ||
# Set the foreground ("+f") to black [Default] | ||
fill="p8+bwhite+fblack", | ||
# Fill bars with GMT pattern 8, with white background and black foreground. | ||
fill=Pattern(8, bgcolor="white", fgcolor="black"), | ||
Comment on lines
+208
to
+209
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. At L149 above, could you add an intersphinx link to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You meant L179, right? Done in 5774b35. |
||
pen="1p,darkgray,solid", | ||
histtype=0, | ||
# Show cumulative counts | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
# %% | ||
import pandas as pd | ||
import pygmt | ||
from pygmt.params import Pattern | ||
|
||
# Set up arguments for basemap | ||
region = [-5, 5, -5, 5] | ||
|
@@ -99,10 +100,7 @@ | |
# --------------------- | ||
# | ||
# Use the parameters ``compressionfill`` and ``extensionfill`` to fill the quadrants | ||
# with different colors or patterns. Regarding patterns see the gallery example | ||
# :doc:`Bit and hachure patterns </gallery/symbols/patterns>` and the Technical | ||
# Reference :doc:`Bit and hachure patterns </techref/patterns>`. | ||
|
||
# with different colors or :class:`patterns <pygmt.params.Pattern>`. | ||
fig = pygmt.Figure() | ||
fig.basemap(region=region, projection=projection, frame=frame) | ||
|
||
|
@@ -122,8 +120,8 @@ | |
longitude=2, | ||
latitude=0, | ||
depth=0, | ||
compressionfill="p8", | ||
extensionfill="p31", | ||
compressionfill=Pattern(8), | ||
extensionfill=Pattern(31), | ||
Comment on lines
+123
to
+124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just want to flag that we need to remember to update the type-hints for various |
||
outline=True, | ||
) | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,3 +3,4 @@ | |
""" | ||
|
||
from pygmt.params.box import Box | ||
from pygmt.params.pattern import Pattern |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,111 @@ | ||||||
""" | ||||||
The Pattern class for specifying bit and hachure patterns. | ||||||
""" | ||||||
|
||||||
import dataclasses | ||||||
|
||||||
from pygmt._typing import PathLike | ||||||
from pygmt.alias import Alias | ||||||
from pygmt.exceptions import GMTValueError | ||||||
from pygmt.params.base import BaseParam | ||||||
|
||||||
__doctest_skip__ = ["Pattern"] | ||||||
|
||||||
|
||||||
@dataclasses.dataclass(repr=False) | ||||||
class Pattern(BaseParam): | ||||||
""" | ||||||
Class for specifying bit and hachure patterns. | ||||||
This class allows users to specify predefined bit-patterns or custom 1-, 8-, or | ||||||
24-bit image raster files to fill symbols and polygons in various PyGMT plotting | ||||||
methods. The patterns can be customized with different resolution and different | ||||||
foreground and background colors. The foreground and background colors can also be | ||||||
reversed. | ||||||
GMT provides 90 predefined patterns that can be used in PyGMT. The patterns are | ||||||
numbered from 1 to 90, and shown below: | ||||||
.. figure:: https://docs.generic-mapping-tools.org/6.5/_images/GMT_App_E.png | ||||||
:alt: The 90 predefined bit-patterns provided with GMT | ||||||
:width: 75% | ||||||
:align: center | ||||||
Parameters | ||||||
---------- | ||||||
id | ||||||
|
||||||
The pattern ID. It can be specified in two forms: | ||||||
- An integer in the range of 1-90, corresponding to one of 90 predefined 64x64 | ||||||
bit-patterns | ||||||
- Name of a 1-, 8-, or 24-bit image raster file, to create customized, repeating | ||||||
images using image raster files. | ||||||
dpi | ||||||
Resolution of the pattern in dots per inch (DPI) [Default is 1200]. | ||||||
bgcolor/fgcolor | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Type hints for these not showing in the docs. Does it matter? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried to make it work but was not successful. |
||||||
The background/foreground color for predefined bit-patterns or 1-bit images. | ||||||
[Default is white for background and black for foreground]. Setting either to | ||||||
an empty string will yield a transparent background/foreground where only the | ||||||
foreground or background pixels will be painted. | ||||||
reversed | ||||||
|
||||||
If ``True``, the pattern will be bit-reversed, i.e., white and black areas will | ||||||
be interchanged (only applies to predefined bit-patterns or 1-bit images). | ||||||
Examples | ||||||
-------- | ||||||
Draw a global map with land areas filled with pattern 15 in a light red background | ||||||
and 300 dpi resolution: | ||||||
>>> import pygmt | ||||||
>>> from pygmt.params import Pattern | ||||||
>>> fig = pygmt.Figure() | ||||||
>>> fig.coast( | ||||||
... region="g", | ||||||
... projection="H10c", | ||||||
... frame=True, | ||||||
... land=Pattern(15, bgcolor="lightred", dpi=300), | ||||||
... shorelines=True, | ||||||
... ) | ||||||
>>> fig.show() | ||||||
""" | ||||||
|
||||||
id: int | PathLike | ||||||
dpi: int | None = None | ||||||
bgcolor: str | None = None | ||||||
fgcolor: str | None = None | ||||||
reversed: bool = False | ||||||
|
||||||
def _validate(self): | ||||||
""" | ||||||
Validate the parameters. | ||||||
""" | ||||||
# Integer pattern id must be in the range 1-90. | ||||||
if isinstance(self.id, int) and not (1 <= self.id <= 90): | ||||||
raise GMTValueError( | ||||||
self.id, | ||||||
description="pattern id", | ||||||
reason=( | ||||||
"Pattern id must be an integer in the range 1-90 " | ||||||
"or the name of a 1-, 8-, or 24-bit image raster file." | ||||||
), | ||||||
) | ||||||
# fgcolor and bgcolor cannot both be empty. | ||||||
if self.fgcolor == "" and self.bgcolor == "": | ||||||
_value = f"{self.fgcolor=}, {self.bgcolor=}" | ||||||
raise GMTValueError( | ||||||
_value, | ||||||
description="fgcolor/", | ||||||
|
description="fgcolor/", | |
description="fgcolor/bgcolor", |
Copilot uses AI. Check for mistakes.
seisman marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
""" | ||
Test the Pattern class. | ||
""" | ||
|
||
import pytest | ||
from pygmt.exceptions import GMTValueError | ||
from pygmt.params import Pattern | ||
|
||
|
||
def test_pattern(): | ||
""" | ||
Test the Pattern class. | ||
""" | ||
assert str(Pattern(1)) == "p1" | ||
assert str(Pattern(id=1)) == "p1" | ||
|
||
assert str(Pattern("pattern.png")) == "ppattern.png" | ||
|
||
assert str(Pattern(10, bgcolor="red")) == "p10+bred" | ||
assert str(Pattern(20, fgcolor="blue")) == "p20+fblue" | ||
assert str(Pattern(30, bgcolor="red", fgcolor="blue")) == "p30+bred+fblue" | ||
assert str(Pattern(30, fgcolor="blue", bgcolor="")) == "p30+b+fblue" | ||
assert str(Pattern(30, fgcolor="", bgcolor="red")) == "p30+bred+f" | ||
|
||
assert str(Pattern(40, dpi=300)) == "p40+r300" | ||
|
||
assert str(Pattern(50, reversed=True)) == "P50" | ||
|
||
pattern = Pattern(90, reversed=True, bgcolor="red", fgcolor="blue", dpi=300) | ||
assert str(pattern) == "P90+bred+fblue+r300" | ||
|
||
pattern = Pattern("pattern.png", bgcolor="red", fgcolor="blue", dpi=300) | ||
assert str(pattern) == "ppattern.png+bred+fblue+r300" | ||
|
||
|
||
def test_pattern_invalid_id(): | ||
""" | ||
Test that an invalid pattern id raises a GMTValueError. | ||
""" | ||
with pytest.raises(GMTValueError): | ||
_ = str(Pattern(91)) | ||
with pytest.raises(GMTValueError): | ||
_ = str(Pattern(0)) | ||
|
||
|
||
def test_pattern_invalid_colors(): | ||
""" | ||
Test that both fgcolor and bgcolor cannot be empty strings. | ||
""" | ||
with pytest.raises(GMTValueError): | ||
_ = str(Pattern(10, fgcolor="", bgcolor="")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did the default change from 300 dpi to 1200 dpi? Or was 300 dpi wrong / a typo?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The upstream documentation says 1200, but the source code says 300. Actually it's a typo in the upstream documentation. See PR GenericMappingTools/gmt#8789 for details.
Fixed in e9eca8e.