Source code for pygmt.src.magnetic_rose

"""
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 GMTParameterError
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, default=Position("BL", cstype="inside"))

    if declination_label is not None and declination is None:
        raise GMTParameterError(
            required="declination",
            reason="Required when 'declination_label' is set.",
        )

    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))