Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions doc/api/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Plotting map elements
Figure.inset
Figure.legend
Figure.logo
Figure.magnetic_rose
Figure.solar
Figure.text
Figure.timestamp
Expand Down
1 change: 1 addition & 0 deletions pygmt/figure.py
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,7 @@ def _repr_html_(self) -> str:
inset,
legend,
logo,
magnetic_rose,
meca,
plot,
plot3d,
Expand Down
1 change: 1 addition & 0 deletions pygmt/src/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from pygmt.src.inset import inset
from pygmt.src.legend import legend
from pygmt.src.logo import logo
from pygmt.src.magnetic_rose import magnetic_rose
from pygmt.src.makecpt import makecpt
from pygmt.src.meca import meca
from pygmt.src.nearneighbor import nearneighbor
Expand Down
149 changes: 149 additions & 0 deletions pygmt/src/magnetic_rose.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
"""
magnetic_rose - Add a map magnetic rose.
"""

from collections.abc import Sequence
from typing import Literal

from pygmt._typing import AnchorCode
from pygmt.alias import Alias, AliasSystem
from pygmt.clib import Session
from pygmt.exceptions import GMTInvalidInput
from pygmt.helpers import build_arg_list, fmt_docstring
from pygmt.params import Box, Position
from pygmt.src._common import _parse_position

__doctest_skip__ = ["magnetic_rose"]


@fmt_docstring
def magnetic_rose( # noqa: PLR0913
self,
position: Position | Sequence[float | str] | AnchorCode | None = None,
width: float | str | None = None,
labels: Sequence[str] | bool = False,
outer_pen: str | bool = False,
inner_pen: str | bool = False,
declination: float | None = None,
declination_label: str | None = None,
intervals: Sequence[float] | None = None,
box: Box | bool = False,
verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"]
| bool = False,
panel: int | Sequence[int] | bool = False,
perspective: str | bool = False,
transparency: float | None = None,
):
"""
Add a magnetic rose to the map.

Parameters
----------
position
Position of the magnetic rose on the plot. It can be specified in multiple ways:

- A :class:`pygmt.params.Position` object to fully control the reference point,
anchor point, and offset.
- A sequence of two values representing the x- and y-coordinates in plot
coordinates, e.g., ``(1, 2)`` or ``("1c", "2c")``.
- A :doc:`2-character justification code </techref/justification_codes>` for a
position inside the plot, e.g., ``"TL"`` for Top Left corner inside the plot.

If not specified, defaults to the Bottom Left corner of the plot (position
``(0, 0)`` with anchor ``"BL"``).
width
Width of the rose in plot coordinates, or append unit ``%`` for a size in
percentage of plot width [Default is 15%].
labels
A sequence of four strings to label the cardinal points W, E, S, N. Use an empty
string to skip a specific label. If the north label is ``"*"``, then a north
star is plotted instead of the north label. If set to ``True``, use the default
labels ``["W", "E", "S", "N"]``.
outer_pen
Draw the outer circle of the magnetic rose, using the given pen attributes.
inner_pen
Draw the inner circle of the magnetic rose, using the given pen attributes.
declination
Magnetic declination in degrees. By default, only a geographic north is plotted.
With this parameter set, a magnetic north is also plotted. A magnetic compass
needle is drawn inside the rose to indicate the direction to magnetic north.
declination_label
Label for the magnetic compass needle. Default is to format a label based on
``declination``. To bypass the label, set to ``"-"``.
intervals
Specify the annotation and tick intervals for the geographic and magnetic
directions. It can be a sequence of three or six values. If three values are
given, they are used for both geographic and magnetic directions. If six values
are given, the first three are used for geographic directions and the last three
for magnetic directions. [Default is ``(30, 5, 1)``].
**Note**: If :gmt-term:`MAP_EMBELLISHMENT_MODE` is ``"auto"`` and the compass
size is smaller than 2.5 cm then the interval defaults are reset to
``(90,30, 3, 45, 15, 3)``.
box
Draw a background box behind the magnetic rose. If set to ``True``, a simple
rectangular box is drawn using :gmt-term:`MAP_FRAME_PEN`. To customize the box
appearance, pass a :class:`pygmt.params.Box` object to control style, fill, pen,
and other box properties.
$perspective
$verbose
$transparency

Examples
--------
>>> import pygmt
>>> from pygmt.params import Position
>>> fig = pygmt.Figure()
>>> fig.basemap(region=[-10, 10, -10, 10], projection="M15c", frame=True)
>>> fig.magnetic_rose(
... position=Position((-5, -5), cstype="mapcoords"),
... width="4c",
... labels=["W", "E", "S", "*"],
... intervals=(45, 15, 3, 60, 20, 4),
... outer_pen="1p,red",
... inner_pen="1p,blue",
... declination=11.5,
... declination_label="11.5°E",
... )
>>> fig.show()
"""
self._activate_figure()

position = _parse_position(
position,
kwdict={
"width": width,
"labels": labels,
"outer_pen": outer_pen,
"inner_pen": inner_pen,
"declination": declination,
"declination_label": declination_label,
"intervals": intervals,
},
default=Position("BL", cstype="inside"), # Default to BL.
)

if declination_label is not None and declination is None:
msg = "Parameter 'declination' must be set when 'declination_label' is set."
raise GMTInvalidInput(msg)

aliasdict = AliasSystem(
F=Alias(box, name="box"),
Tm=[
Alias(position, name="position"),
Alias(width, name="width", prefix="+w"),
Alias(labels, name="labels", prefix="+l", sep=",", size=4),
Alias(outer_pen, name="outer_pen", prefix="+p"),
Alias(inner_pen, name="inner_pen", prefix="+i"),
Alias(declination, name="declination", prefix="+d"),
Alias(declination_label, name="declination_label", prefix="/"),
Alias(intervals, name="intervals", prefix="+t", sep="/", size=(3, 6)),
],
).add_common(
V=verbose,
c=panel,
p=perspective,
t=transparency,
)

with Session() as lib:
lib.call_module(module="basemap", args=build_arg_list(aliasdict))
5 changes: 5 additions & 0 deletions pygmt/tests/baseline/test_magnetic_rose.png.dvc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
outs:
- md5: 5af8ffee19917b1fbc3371cd3aed53cd
size: 27013
hash: md5
path: test_magnetic_rose.png
5 changes: 5 additions & 0 deletions pygmt/tests/baseline/test_magnetic_rose_complete.png.dvc
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
outs:
- md5: 78c53322b2514fbcd56483b793d47ebe
size: 28831
hash: md5
path: test_magnetic_rose_complete.png
50 changes: 50 additions & 0 deletions pygmt/tests/test_magnetic_rose.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
"""
Test Figure.magnetic_rose.
"""

import pytest
from pygmt import Figure
from pygmt.exceptions import GMTInvalidInput
from pygmt.params import Position


@pytest.mark.mpl_image_compare
def test_magnetic_rose():
"""
Create a map with a compass. Modified from the test_basemap_compass test.
"""
fig = Figure()
fig.basemap(region=[127.5, 128.5, 26, 27], projection="M10c", frame=True)
fig.magnetic_rose()
return fig


@pytest.mark.mpl_image_compare
def test_magnetic_rose_complete():
"""
Test all parameters of Figure.magnetic_rose.
"""
fig = Figure()
fig.basemap(region=[-10, 10, -10, 10], projection="M10c", frame=True)
fig.magnetic_rose(
position=Position("BL"),
width="2c",
labels=["W", "E", "S", "*"],
intervals=(45, 15, 3, 60, 20, 4),
outer_pen="1p,red",
inner_pen="1p,blue",
declination=11.5,
declination_label="11.5°E",
)
return fig


def test_magnetic_rose_invalid_declination_label():
"""
Test that an exception is raised when declination_label is set but declination is
not set.
"""
fig = Figure()
fig.basemap(region=[-10, 10, -10, 10], projection="M10c", frame=True)
with pytest.raises(GMTInvalidInput):
fig.magnetic_rose(declination_label="11.5°E")
Loading