diff --git a/doc/api/index.rst b/doc/api/index.rst index 264f5a9175a..119f204f13d 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -31,6 +31,7 @@ Plotting map elements Figure.inset Figure.legend Figure.logo + Figure.magnetic_rose Figure.solar Figure.text Figure.timestamp diff --git a/pygmt/figure.py b/pygmt/figure.py index 56ad2c3d5cf..348614b1e27 100644 --- a/pygmt/figure.py +++ b/pygmt/figure.py @@ -422,6 +422,7 @@ def _repr_html_(self) -> str: inset, legend, logo, + magnetic_rose, meca, plot, plot3d, diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py index 8905124f917..61eebccb6a4 100644 --- a/pygmt/src/__init__.py +++ b/pygmt/src/__init__.py @@ -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 diff --git a/pygmt/src/magnetic_rose.py b/pygmt/src/magnetic_rose.py new file mode 100644 index 00000000000..3dba6e1dabc --- /dev/null +++ b/pygmt/src/magnetic_rose.py @@ -0,0 +1,120 @@ +""" +magnetic_rose - Add a map magnetic rose. +""" + +from collections.abc import Sequence +from typing import Literal + +from pygmt.alias import Alias, AliasSystem +from pygmt.clib import Session +from pygmt.exceptions import GMTInvalidInput +from pygmt.helpers import build_arg_list, fmt_docstrings +from pygmt.params import Box, Position + + +@fmt_docstrings +def magnetic_rose( # noqa: PLR0913 + self, + position: Position | 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, + perspective: str | bool = False, + verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] + | bool = False, + transparency: float | None = None, +): + """ + Add a magnetic rose to the map. + + Parameters + ---------- + position + Specify the location of the magnetic rose on a map. See + :class:`pygmt.params.Position` for details. + width + Width of the rose in plot coordinates (append **i** (inch), **cm** + (centimeters), or **p** (points)), or append % for a size in percentage of map + 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 seqeunce 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() + + 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, + p=perspective, + t=transparency, + ) + + with Session() as lib: + lib.call_module(module="basemap", args=build_arg_list(aliasdict)) diff --git a/pygmt/tests/test_magnetic_rose.py b/pygmt/tests/test_magnetic_rose.py new file mode 100644 index 00000000000..922fd156f1b --- /dev/null +++ b/pygmt/tests/test_magnetic_rose.py @@ -0,0 +1,19 @@ +""" +Test Figure.magnetic_rose. +""" + +import pytest +from pygmt import Figure + + +@pytest.mark.mpl_image_compare(filename="test_basemap_compass.png") +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="H15c", frame=True) + fig.magnetic_rose( + position_type="inside", position="MC", width="5c", declination=11.5 + ) + return fig