Skip to content

Commit 0851a2e

Browse files
committed
Add Figure.directional_rose for adding directional rose on maps
1 parent 3dd7379 commit 0851a2e

File tree

9 files changed

+177
-1
lines changed

9 files changed

+177
-1
lines changed

doc/api/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Plotting map elements
2727
Figure.basemap
2828
Figure.coast
2929
Figure.colorbar
30+
Figure.directional_rose
3031
Figure.hlines
3132
Figure.inset
3233
Figure.legend

pygmt/figure.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,7 @@ def _repr_html_(self) -> str:
413413
coast,
414414
colorbar,
415415
contour,
416+
directional_rose,
416417
grdcontour,
417418
grdimage,
418419
grdview,

pygmt/src/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from pygmt.src.config import config
1111
from pygmt.src.contour import contour
1212
from pygmt.src.dimfilter import dimfilter
13+
from pygmt.src.directional_rose import directional_rose
1314
from pygmt.src.filter1d import filter1d
1415
from pygmt.src.grd2cpt import grd2cpt
1516
from pygmt.src.grd2xyz import grd2xyz

pygmt/src/directional_rose.py

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
"""
2+
directional_rose - Add a map directional rose.
3+
"""
4+
5+
from collections.abc import Sequence
6+
from typing import Literal
7+
8+
from pygmt._typing import AnchorCode
9+
from pygmt.alias import Alias, AliasSystem
10+
from pygmt.clib import Session
11+
from pygmt.helpers import build_arg_list, fmt_docstring
12+
from pygmt.params import Box, Position
13+
from pygmt.src._common import _parse_position
14+
15+
__doctest_skip__ = ["directional_rose"]
16+
17+
18+
@fmt_docstring
19+
def directional_rose(
20+
self,
21+
position: Position | Sequence[float | str] | AnchorCode | None = None,
22+
width: float | str | None = None,
23+
labels: Sequence[str] | bool = False,
24+
fancy: Literal[1, 2, 3] | bool = False,
25+
box: Box | bool = False,
26+
verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"]
27+
| bool = False,
28+
panel: int | Sequence[int] | bool = False,
29+
perspective: str | bool = False,
30+
transparency: float | None = None,
31+
):
32+
"""
33+
Add a directional rose on the map.
34+
35+
Parameters
36+
----------
37+
position
38+
Position of the directional rose on the plot. It can be specified in multiple
39+
ways:
40+
41+
- A :class:`pygmt.params.Position` object to fully control the reference point,
42+
anchor point, and offset.
43+
- A sequence of two values representing the x and y coordinates in plot
44+
coordinates, e.g., ``(1, 2)`` or ``("1c", "2c")``.
45+
- A :doc:`2-character justification code </techref/justification_codes>` for a
46+
position inside the plot, e.g., ``"TL"`` for Top Left corner inside the plot.
47+
48+
If not specified, defaults to the bottom-left corner of the plot.
49+
width
50+
Width of the rose in plot coordinates, or append % for a size in percentage of
51+
map width [Default is 10%].
52+
labels
53+
A sequence of four strings to label the cardinal points W,E,S,N. Use an empty
54+
string to skip a specific label. If set to ``True``, the default labels
55+
``["W", "E", "S", "N"]`` are used.
56+
fancy
57+
Get a fancy rose. The fanciness level can be set to 1, 2, or 3:
58+
59+
- Level 1 draws the two principal E-W, N-S orientations
60+
- Level 2 adds the two intermediate NW-SE and NE-SW orientations
61+
- Level 3 adds the four minor orientations WNW-ESE, NNW-SSE, NNE-SSW, and
62+
ENE-WSW
63+
64+
If set to ``True``, defaults to level 1.
65+
box
66+
Draw a background box behind the directional rose. If set to ``True``, a simple
67+
rectangular box is drawn using :gmt-term:`MAP_FRAME_PEN`. To customize the box
68+
appearance, pass a :class:`pygmt.params.Box` object to control style, fill, pen,
69+
and other box properties.
70+
$verbose
71+
$panel
72+
$perspective
73+
$transparency
74+
75+
Examples
76+
--------
77+
>>> import pygmt
78+
>>> fig = pygmt.Figure()
79+
>>> fig.basemap(region=[0, 80, 0, 30], projection="M10c", frame=True)
80+
>>> fig.directional_rose()
81+
>>> fig.show()
82+
"""
83+
self._activate_figure()
84+
85+
position = _parse_position(
86+
position,
87+
kwdict={"width": width, "fancy": fancy, "labels": labels},
88+
default=Position("BL", cstype="inside"), # Default to BL.
89+
)
90+
91+
# The GMT documentation says the default width is 10%, but in PyGMT, it crashes
92+
# if width is not provided. So we set it to 10% here.
93+
if not isinstance(position, str) and width is None:
94+
width = "10%"
95+
96+
aliasdict = AliasSystem(
97+
F=Alias(box, name="box"),
98+
Td=[
99+
Alias(position, name="position"),
100+
Alias(width, name="width", prefix="+w"),
101+
Alias(fancy, name="fancy", prefix="+f"), # +F is not supported yet.
102+
Alias(labels, name="labels", prefix="+l", sep=",", size=4),
103+
],
104+
).add_common(
105+
V=verbose,
106+
c=panel,
107+
p=perspective,
108+
t=transparency,
109+
)
110+
111+
with Session() as lib:
112+
lib.call_module(module="basemap", args=build_arg_list(aliasdict))
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
outs:
2+
- md5: c1c167a826132bcdabc3b032438db01e
3+
size: 8319
4+
hash: md5
5+
path: test_directional_rose.png
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
outs:
2+
- md5: 7a7eabd0036dc9b744e54dfbc398fc6e
3+
size: 9772
4+
hash: md5
5+
path: test_directional_rose_complex.png
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
outs:
2+
- md5: 7498ed12efd8b956a0fe13d18e0e3ea9
3+
size: 8648
4+
hash: md5
5+
path: test_directional_rose_fancy.png
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
"""
2+
Test Figure.directional_rose.
3+
"""
4+
5+
import pytest
6+
from pygmt import Figure
7+
from pygmt.params import Position
8+
9+
10+
@pytest.mark.mpl_image_compare
11+
def test_directional_rose():
12+
"""
13+
Test the Figure.directional_rose method with default position and width.
14+
"""
15+
fig = Figure()
16+
fig.basemap(region=[0, 80, 0, 30], projection="M10c", frame=True)
17+
fig.directional_rose()
18+
return fig
19+
20+
21+
@pytest.mark.mpl_image_compare
22+
def test_directional_rose_fancy():
23+
"""
24+
Test the Figure.directional_rose method with default position and width.
25+
"""
26+
fig = Figure()
27+
fig.basemap(region=[0, 80, 0, 30], projection="M10c", frame=True)
28+
fig.directional_rose(fancy=True)
29+
return fig
30+
31+
32+
@pytest.mark.mpl_image_compare
33+
def test_directional_rose_complex():
34+
"""
35+
Test the Figure.directional_rose method with more parameters.
36+
"""
37+
fig = Figure()
38+
fig.basemap(region=[0, 80, 0, 30], projection="M10c", frame=True)
39+
fig.directional_rose(
40+
position=Position((50, 0), cstype="mapcoords", anchor="MC", offset=(1, 1)),
41+
width="1c",
42+
labels=["", "", "", "N"],
43+
fancy=2,
44+
)
45+
return fig

pygmt/tests/test_inset.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,6 @@ def test_inset_context_manager():
3030
fig.basemap(region=[-74, -69.5, 41, 43], projection="M9c", frame=True)
3131
with fig.inset(position="jBL+w3c+o0.2c", clearance=0.2, box=True):
3232
fig.basemap(region="g", projection="G47/-20/?", frame="afg")
33-
fig.basemap(rose="jTR+w3c") # Pass rose argument with basemap after the inset
33+
# Plot an rose after the inset
34+
fig.directional_rose(position="TR", width="3c")
3435
return fig

0 commit comments

Comments
 (0)