From 59f2b189ea32b7a146af2bf9c675c68277784f60 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 29 Jul 2025 15:40:06 +0800 Subject: [PATCH 01/11] Add Figure.directional_rose to plot a directional rose on map --- pygmt/figure.py | 1 + pygmt/src/__init__.py | 1 + pygmt/src/directional_rose.py | 72 +++++++++++++++++++++++++++++++++++ 3 files changed, 74 insertions(+) create mode 100644 pygmt/src/directional_rose.py diff --git a/pygmt/figure.py b/pygmt/figure.py index 474cd91179b..c9d7fd4f664 100644 --- a/pygmt/figure.py +++ b/pygmt/figure.py @@ -435,6 +435,7 @@ def _repr_html_(self) -> str: coast, colorbar, contour, + directional_rose, grdcontour, grdimage, grdview, diff --git a/pygmt/src/__init__.py b/pygmt/src/__init__.py index 8905124f917..1e34c3ba669 100644 --- a/pygmt/src/__init__.py +++ b/pygmt/src/__init__.py @@ -10,6 +10,7 @@ from pygmt.src.config import config from pygmt.src.contour import contour from pygmt.src.dimfilter import dimfilter +from pygmt.src.directional_rose import directional_rose from pygmt.src.filter1d import filter1d from pygmt.src.grd2cpt import grd2cpt from pygmt.src.grd2xyz import grd2xyz diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py new file mode 100644 index 00000000000..147cf1b4fcc --- /dev/null +++ b/pygmt/src/directional_rose.py @@ -0,0 +1,72 @@ +""" +directional_rose - Add a map directional 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.helpers import build_arg_list + + +def directional_rose( + self, + position, + position_type: Literal["user", "justify", "mirror", "normalize", "plot"] + | None = None, + width=None, + fancy: Literal[1, 2, 3] | bool = False, + justify: AnchorCode | None = None, + offset: Sequence[float | str] | None = None, + label: Sequence[str] | bool = False, +): + """ + Add a directional rose to the map. + + Parameters + ---------- + 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 10%]. + label + A sequence of four strings to label the cardinal points W,E,S,N. Use a empty + string to skip a specific label. If set to ``True``, use the default labels + ``["W", "E", "S", "N"]``. + + Examples + -------- + >>> import pygmt + >>> fig = pygmt.Figure() + >>> fig.basemap(region=[0, 80, -30, 30], projection="M10c", frame=True) + >>> fig.directional_rose(position=(10, 10), position_type="user") + >>> fig.show() + """ + self._activate_figure() + + aliasdict = AliasSystem( + Td=[ + Alias( + position_type, + name="position_type", + mapping={ + "user": "g", + "justify": "j", + "mirror": "J", + "normalize": "n", + "plot": "x", + }, + ), + Alias(position, name="position", separator="/"), + Alias(width, name="width", prefix="+w"), + Alias(fancy, name="fancy", prefix="+f"), + Alias(justify, name="justify", prefix="+j"), + Alias(label, name="label", prefix="+l", separator=",", size=4), + Alias(offset, name="offset", prefix="+o", separator="/", size=[1, 2]), + ] + ) + + with Session() as lib: + lib.call_module(module="basemap", args=build_arg_list(aliasdict)) From 07fc243ab61c412c607959915ae2ed8f7355d080 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 29 Jul 2025 16:40:40 +0800 Subject: [PATCH 02/11] Add to API doc --- doc/api/index.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/api/index.rst b/doc/api/index.rst index 7828a225652..e91f5bc5194 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -27,6 +27,7 @@ Plotting map elements Figure.basemap Figure.coast Figure.colorbar + Figure.directional_rose Figure.hlines Figure.inset Figure.legend @@ -36,6 +37,7 @@ Plotting map elements Figure.timestamp Figure.vlines + Plotting tabular data ~~~~~~~~~~~~~~~~~~~~~ From 29c28bc91bf7f7f7190343854201047cb42d08b4 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 29 Jul 2025 18:00:13 +0800 Subject: [PATCH 03/11] Add more docstrings --- pygmt/src/directional_rose.py | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py index 147cf1b4fcc..fa546d67370 100644 --- a/pygmt/src/directional_rose.py +++ b/pygmt/src/directional_rose.py @@ -16,17 +16,20 @@ def directional_rose( position, position_type: Literal["user", "justify", "mirror", "normalize", "plot"] | None = None, - width=None, - fancy: Literal[1, 2, 3] | bool = False, + width: float | str | None = None, justify: AnchorCode | None = None, offset: Sequence[float | str] | None = None, label: Sequence[str] | bool = False, + fancy: Literal[1, 2, 3] | bool = False, ): """ Add a directional rose to the map. Parameters ---------- + position + position_type + width Width of the rose in plot coordinates (append **i** (inch), **cm** (centimeters), or **p** (points)), or append % for a size in percentage @@ -35,6 +38,17 @@ def directional_rose( A sequence of four strings to label the cardinal points W,E,S,N. Use a empty string to skip a specific label. If set to ``True``, use the default labels ``["W", "E", "S", "N"]``. + fancy + Get a fancy rose. The fanciness level can be set to 1, 2, or 3: + + - Level 1 draws the two principal E-W, N-S orientations + - Level 2 adds the two intermediate NW-SE and NE-SW orientations + - Level 3 adds the eight minor orientations WNW-ESE, NNW-SSE, NNE-SSW, and + ENE-WSW + + If set to ``True``, it defaults to level 1. + offset + justify Examples -------- From 33398b55520ade527fd83a67a5dd2f6ab6b9e4aa Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 30 Jul 2025 13:48:03 +0800 Subject: [PATCH 04/11] Fix typos Co-authored-by: Michael Grund <23025878+michaelgrund@users.noreply.github.com> --- pygmt/src/directional_rose.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py index fa546d67370..ea1b9efdcd0 100644 --- a/pygmt/src/directional_rose.py +++ b/pygmt/src/directional_rose.py @@ -35,7 +35,7 @@ def directional_rose( **cm** (centimeters), or **p** (points)), or append % for a size in percentage of map width [default is 10%]. label - A sequence of four strings to label the cardinal points W,E,S,N. Use a empty + A sequence of four strings to label the cardinal points W,E,S,N. Use an empty string to skip a specific label. If set to ``True``, use the default labels ``["W", "E", "S", "N"]``. fancy @@ -43,7 +43,7 @@ def directional_rose( - Level 1 draws the two principal E-W, N-S orientations - Level 2 adds the two intermediate NW-SE and NE-SW orientations - - Level 3 adds the eight minor orientations WNW-ESE, NNW-SSE, NNE-SSW, and + - Level 3 adds the four minor orientations WNW-ESE, NNW-SSE, NNE-SSW, and ENE-WSW If set to ``True``, it defaults to level 1. From f325296ad06b2c6f3748e2bb818453408e911137 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 30 Jul 2025 14:36:49 +0800 Subject: [PATCH 05/11] Improve docstrings --- pygmt/src/directional_rose.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py index ea1b9efdcd0..faf2e6082e6 100644 --- a/pygmt/src/directional_rose.py +++ b/pygmt/src/directional_rose.py @@ -14,22 +14,32 @@ def directional_rose( self, position, - position_type: Literal["user", "justify", "mirror", "normalize", "plot"] - | None = None, + position_type: Literal["user", "justify", "mirror", "normalize", "plot"] = "user", width: float | str | None = None, justify: AnchorCode | None = None, offset: Sequence[float | str] | None = None, label: Sequence[str] | bool = False, fancy: Literal[1, 2, 3] | bool = False, ): - """ + r""" Add a directional rose to the map. Parameters ---------- - position - position_type + position/position_type + Location of the rose. The actual meaning of this parameter depends on the + ``position_type`` parameter. + - ``position_type="user"``: *position* is given as (x, y) in user coordinates. + - ``position_type="normalize"``: *position* is given as (nx, ny) in normalized + coordinates, where (0, 0) is the lower-left corner and (1, 1) is the + upper-right corner of the map. + - ``position_type="plot"``: *position* is given as (x, y) in plot coordinates. + - ``position_type="justify"``: *position* is given as a two-character + justification code, meaning the anchor point of the rose is inside the map + bounding box. + - ``position_type="mirror"``: *position* is given as a two-character + justification code, but the rose is outside the map bounding box. width Width of the rose in plot coordinates (append **i** (inch), **cm** (centimeters), or **p** (points)), or append % for a size in percentage @@ -48,7 +58,13 @@ def directional_rose( If set to ``True``, it defaults to level 1. offset + *offset* or (*offset_x*, *offset_y*). + Offset the anchor point by *offset_x* and *offset_y*. If a single value *offset* + is given, *offset_y* = *offset_x* = *offset*. justify + Set the anchor point. Specify a two-character (order independent) code. Choose + from vertical **T**\(op), **M**\(iddle), or **B**\(ottom) and horizontal + **L**\(eft), **C**\(entre), or **R**\(ight). Examples -------- From aac91ad30b4fdb31acf3565364034a03c4760350 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 30 Jul 2025 20:01:19 +0800 Subject: [PATCH 06/11] Improve docstring [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yvonne Fröhlich <94163266+yvonnefroehlich@users.noreply.github.com> --- pygmt/src/directional_rose.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py index faf2e6082e6..8eaede9bff1 100644 --- a/pygmt/src/directional_rose.py +++ b/pygmt/src/directional_rose.py @@ -43,7 +43,7 @@ def directional_rose( 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 10%]. + of map width [Default is 10 %]. label A sequence of four strings to label the cardinal points W,E,S,N. Use an empty string to skip a specific label. If set to ``True``, use the default labels From 607f4dbec44d99ac1bb1107c88ea5e444f7f3f81 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 3 Aug 2025 14:10:54 +0800 Subject: [PATCH 07/11] Better arguments for position_type --- pygmt/src/directional_rose.py | 36 +++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py index 8eaede9bff1..72fe16244aa 100644 --- a/pygmt/src/directional_rose.py +++ b/pygmt/src/directional_rose.py @@ -14,10 +14,12 @@ def directional_rose( self, position, - position_type: Literal["user", "justify", "mirror", "normalize", "plot"] = "user", + position_type: Literal[ + "mapcoords", "inside", "outside", "boxcoords", "plotcoords" + ] = "mapcoords", width: float | str | None = None, justify: AnchorCode | None = None, - offset: Sequence[float | str] | None = None, + anchor_offset: Sequence[float | str] | None = None, label: Sequence[str] | bool = False, fancy: Literal[1, 2, 3] | bool = False, ): @@ -30,15 +32,17 @@ def directional_rose( Location of the rose. The actual meaning of this parameter depends on the ``position_type`` parameter. - - ``position_type="user"``: *position* is given as (x, y) in user coordinates. - - ``position_type="normalize"``: *position* is given as (nx, ny) in normalized + - ``position_type="mapcoords"``: *position* is given as (x, y) in user + coordinates. + - ``position_type="boxcoords"``: *position* is given as (nx, ny) in normalized coordinates, where (0, 0) is the lower-left corner and (1, 1) is the upper-right corner of the map. - - ``position_type="plot"``: *position* is given as (x, y) in plot coordinates. - - ``position_type="justify"``: *position* is given as a two-character + - ``position_type="plotcoords"``: *position* is given as (x, y) in plot + coordinates. + - ``position_type="inside"``: *position* is given as a two-character justification code, meaning the anchor point of the rose is inside the map bounding box. - - ``position_type="mirror"``: *position* is given as a two-character + - ``position_type="outside"``: *position* is given as a two-character justification code, but the rose is outside the map bounding box. width Width of the rose in plot coordinates (append **i** (inch), @@ -57,7 +61,7 @@ def directional_rose( ENE-WSW If set to ``True``, it defaults to level 1. - offset + anchor_offset *offset* or (*offset_x*, *offset_y*). Offset the anchor point by *offset_x* and *offset_y*. If a single value *offset* is given, *offset_y* = *offset_x* = *offset*. @@ -82,19 +86,19 @@ def directional_rose( position_type, name="position_type", mapping={ - "user": "g", - "justify": "j", - "mirror": "J", - "normalize": "n", - "plot": "x", + "mapcoords": "g", + "inside": "j", + "outside": "J", + "boxcoords": "n", + "plotcoords": "x", }, ), - Alias(position, name="position", separator="/"), + Alias(position, name="position", sep="/"), Alias(width, name="width", prefix="+w"), Alias(fancy, name="fancy", prefix="+f"), Alias(justify, name="justify", prefix="+j"), - Alias(label, name="label", prefix="+l", separator=",", size=4), - Alias(offset, name="offset", prefix="+o", separator="/", size=[1, 2]), + Alias(label, name="label", prefix="+l", sep=",", size=4), + Alias(anchor_offset, name="anchor_offset", prefix="+o", sep="/", size=2), ] ) From a36b8af2de3661a67cac89144c0afb2666ad75f1 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 3 Aug 2025 19:50:35 +0800 Subject: [PATCH 08/11] Add more parameters --- doc/api/index.rst | 1 - pygmt/src/basemap.py | 16 ++++++++++++++-- pygmt/src/directional_rose.py | 12 ++++++++++-- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/doc/api/index.rst b/doc/api/index.rst index e91f5bc5194..de563b4d07c 100644 --- a/doc/api/index.rst +++ b/doc/api/index.rst @@ -37,7 +37,6 @@ Plotting map elements Figure.timestamp Figure.vlines - Plotting tabular data ~~~~~~~~~~~~~~~~~~~~~ diff --git a/pygmt/src/basemap.py b/pygmt/src/basemap.py index b28009ab55d..acb8aa7764d 100644 --- a/pygmt/src/basemap.py +++ b/pygmt/src/basemap.py @@ -2,6 +2,8 @@ basemap - Plot base maps and frames. """ +import warnings + from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.helpers import build_arg_list, fmt_docstring, kwargs_to_strings, use_alias @@ -72,8 +74,9 @@ def basemap(self, projection=None, **kwargs): [Default is ``"4p/-4p"``] and shade sets the fill style to use for shading [Default is ``"gray50"``]. rose : str - Draw a map directional rose on the map at the location defined by - the reference and anchor points. + Draw a map directional rose on the map. + + Deprecated. Use :py:func:`pygmt.Figure.directional_rose` instead. compass : str Draw a map magnetic rose on the map at the location defined by the reference and anchor points. @@ -87,5 +90,14 @@ def basemap(self, projection=None, **kwargs): aliasdict = AliasSystem( J=Alias(projection, name="projection"), ).merge(kwargs) + + if aliasdict.get("Td"): + warnings.warn( + "Parameter 'rose' is deprecated and will be removed in a future version. " + "Use 'Figure.directional_rose' instead.", + DeprecationWarning, + stacklevel=2, + ) + with Session() as lib: lib.call_module(module="basemap", args=build_arg_list(aliasdict)) diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py index 72fe16244aa..9694ca705b2 100644 --- a/pygmt/src/directional_rose.py +++ b/pygmt/src/directional_rose.py @@ -11,7 +11,7 @@ from pygmt.helpers import build_arg_list -def directional_rose( +def directional_rose( # noqa: PLR0913 self, position, position_type: Literal[ @@ -22,6 +22,10 @@ def directional_rose( anchor_offset: Sequence[float | str] | None = None, label: Sequence[str] | bool = False, fancy: Literal[1, 2, 3] | bool = False, + box=None, + perspective=None, + verbose=None, + transparency=None, ): r""" Add a directional rose to the map. @@ -81,6 +85,7 @@ def directional_rose( self._activate_figure() aliasdict = AliasSystem( + F=Alias(box, name="box"), Td=[ Alias( position_type, @@ -99,7 +104,10 @@ def directional_rose( Alias(justify, name="justify", prefix="+j"), Alias(label, name="label", prefix="+l", sep=",", size=4), Alias(anchor_offset, name="anchor_offset", prefix="+o", sep="/", size=2), - ] + ], + V=Alias(verbose, name="verbose"), + p=Alias(perspective, name="perspective"), + t=Alias(transparency, name="transparency"), ) with Session() as lib: From 6c890cff6224e18a1f4768ff866f308271792e9d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 7 Aug 2025 15:25:16 +0800 Subject: [PATCH 09/11] Add more type hints --- pygmt/src/directional_rose.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py index 9694ca705b2..e84c194f0c9 100644 --- a/pygmt/src/directional_rose.py +++ b/pygmt/src/directional_rose.py @@ -13,7 +13,7 @@ def directional_rose( # noqa: PLR0913 self, - position, + position: Sequence[str | float] | AnchorCode, position_type: Literal[ "mapcoords", "inside", "outside", "boxcoords", "plotcoords" ] = "mapcoords", @@ -98,7 +98,7 @@ def directional_rose( # noqa: PLR0913 "plotcoords": "x", }, ), - Alias(position, name="position", sep="/"), + Alias(position, name="position", sep="/", size=2), Alias(width, name="width", prefix="+w"), Alias(fancy, name="fancy", prefix="+f"), Alias(justify, name="justify", prefix="+j"), From 64bf23a97edc3b9c8ca070ca19441994fc5cc613 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Thu, 7 Aug 2025 15:25:54 +0800 Subject: [PATCH 10/11] Update to the new position type --- pygmt/src/directional_rose.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py index e84c194f0c9..5f5a26d016f 100644 --- a/pygmt/src/directional_rose.py +++ b/pygmt/src/directional_rose.py @@ -79,7 +79,7 @@ def directional_rose( # noqa: PLR0913 >>> import pygmt >>> fig = pygmt.Figure() >>> fig.basemap(region=[0, 80, -30, 30], projection="M10c", frame=True) - >>> fig.directional_rose(position=(10, 10), position_type="user") + >>> fig.directional_rose(position=(10, 10), position_type="mapcoords") >>> fig.show() """ self._activate_figure() From 50476ea1ae3114d110276baa09a0983b66d963e3 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Sun, 10 Aug 2025 20:32:27 +0800 Subject: [PATCH 11/11] Updates --- pygmt/src/basemap.py | 4 +++- pygmt/src/directional_rose.py | 23 ++++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/pygmt/src/basemap.py b/pygmt/src/basemap.py index acb8aa7764d..bd4e5cfa46b 100644 --- a/pygmt/src/basemap.py +++ b/pygmt/src/basemap.py @@ -76,7 +76,9 @@ def basemap(self, projection=None, **kwargs): rose : str Draw a map directional rose on the map. - Deprecated. Use :py:func:`pygmt.Figure.directional_rose` instead. + .. deprecated:: v0.17.0 + + Use :py:func:`pygmt.Figure.directional_rose` instead. compass : str Draw a map magnetic rose on the map at the location defined by the reference and anchor points. diff --git a/pygmt/src/directional_rose.py b/pygmt/src/directional_rose.py index 5f5a26d016f..c3588a27e20 100644 --- a/pygmt/src/directional_rose.py +++ b/pygmt/src/directional_rose.py @@ -15,7 +15,11 @@ def directional_rose( # noqa: PLR0913 self, position: Sequence[str | float] | AnchorCode, position_type: Literal[ - "mapcoords", "inside", "outside", "boxcoords", "plotcoords" + "mapcoords", + "boxcoords", + "plotcoords", + "inside", + "outside", ] = "mapcoords", width: float | str | None = None, justify: AnchorCode | None = None, @@ -33,21 +37,22 @@ def directional_rose( # noqa: PLR0913 Parameters ---------- position/position_type - Location of the rose. The actual meaning of this parameter depends on the - ``position_type`` parameter. + Location of the directional rose. The actual meaning of this parameter depends + on the ``position_type`` parameter. - ``position_type="mapcoords"``: *position* is given as (x, y) in user coordinates. - ``position_type="boxcoords"``: *position* is given as (nx, ny) in normalized coordinates, where (0, 0) is the lower-left corner and (1, 1) is the - upper-right corner of the map. + upper-right corner of the plot. - ``position_type="plotcoords"``: *position* is given as (x, y) in plot - coordinates. + coordinates, i.e., the distances in inches, centimeters, or points from the + lower left plot origin. - ``position_type="inside"``: *position* is given as a two-character - justification code, meaning the anchor point of the rose is inside the map + justification code, meaning the anchor point of the rose is inside the plot bounding box. - ``position_type="outside"``: *position* is given as a two-character - justification code, but the rose is outside the map bounding box. + justification code, but the rose is outside the plot bounding box. width Width of the rose in plot coordinates (append **i** (inch), **cm** (centimeters), or **p** (points)), or append % for a size in percentage @@ -92,10 +97,10 @@ def directional_rose( # noqa: PLR0913 name="position_type", mapping={ "mapcoords": "g", - "inside": "j", - "outside": "J", "boxcoords": "n", "plotcoords": "x", + "inside": "j", + "outside": "J", }, ), Alias(position, name="position", sep="/", size=2),