From a5b275584213f3d31065bdf2835367d6e84b6bf2 Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Mon, 11 Aug 2025 00:29:07 +0800 Subject: [PATCH] Figure.wiggle: Refactor using the new alias system --- examples/gallery/lines/wiggle.py | 33 +++++++--------- pygmt/src/wiggle.py | 50 ++++++++++++++++++----- pygmt/tests/test_wiggle.py | 68 ++++++++++++++++++++++++++++++-- 3 files changed, 119 insertions(+), 32 deletions(-) diff --git a/examples/gallery/lines/wiggle.py b/examples/gallery/lines/wiggle.py index ad2b37e68f5..22393499c02 100644 --- a/examples/gallery/lines/wiggle.py +++ b/examples/gallery/lines/wiggle.py @@ -2,17 +2,17 @@ Wiggle along tracks =================== -The :meth:`pygmt.Figure.wiggle` method can plot z = f(x,y) anomalies along -tracks. ``x``, ``y``, ``z`` can be specified as 1-D arrays or within a -specified file. The ``scale`` parameter can be used to set the scale of the -anomaly in data/distance units. The positive and/or negative areas can be -filled with color by setting the ``positive_fill`` and/or ``negative_fill`` -parameters. +The :meth:`pygmt.Figure.wiggle` method can plot z = f(x,y) anomalies along tracks. +``x``, ``y``, ``z`` can be specified as 1-D arrays or within a specified file. The +``scale`` parameter can be used to set the scale of the anomaly in data/distance units. +The positive and/or negative areas can be filled with color by setting the +``positive_fill`` and/or ``negative_fill`` parameters. """ # %% import numpy as np import pygmt +from pygmt.params import Position # Create (x, y, z) triplets x = np.arange(-7, 7, 0.1) @@ -25,18 +25,13 @@ x=x, y=y, z=z, - # Set anomaly scale to 20 centimeters - scale="20c", - # Fill positive areas red - positive_fill="red", - # Fill negative areas gray - negative_fill="gray", - # Set the outline width to 1.0 point - pen="1.0p", - # Draw a blue track with a width of 0.5 points - track="0.5p,blue", - # Plot a vertical scale bar at Middle Right (MR). The bar length (+w) - # is 100 in data (z) units. Set the z unit label (+l) to "nT". - position="jMR+w100+lnT", + scale="20c", # Set anomaly scale to 20 centimeters + positive_fill="red", # Fill positive areas red + negative_fill="gray", # Fill negative areas gray + pen="1.0p", # Set the outline width to 1.0 point + track="0.5p,blue", # Draw a blue track with a width of 0.5 points + position=Position("MR"), # Plot a vertical scale bar at Middle Right (MR). + length=100, # Bar length is 100 in data (z) units. + label="nT", # Set the z unit label to "nT". ) fig.show() diff --git a/pygmt/src/wiggle.py b/pygmt/src/wiggle.py index 66007fe5de5..e7c99c81e65 100644 --- a/pygmt/src/wiggle.py +++ b/pygmt/src/wiggle.py @@ -8,7 +8,9 @@ from pygmt._typing import PathLike, TableLike from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session +from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import build_arg_list, deprecate_parameter, fmt_docstring, use_alias +from pygmt.params import Position def _parse_fills(positive_fill, negative_fill): @@ -46,7 +48,6 @@ def _parse_fills(positive_fill, negative_fill): "fillnegative", "negative_fill", "v0.18.0", remove_version="v0.20.0" ) @use_alias( - D="position", T="track", W="pen", Z="scale", @@ -64,6 +65,10 @@ def wiggle( # noqa: PLR0913 x=None, y=None, z=None, + position: Position | None = None, + length: float | str | None = None, + label: str | None = None, + label_alignment: Literal["left", "right"] | None = None, positive_fill=None, negative_fill=None, projection: str | None = None, @@ -107,19 +112,21 @@ def wiggle( # noqa: PLR0913 $table_classes. Use parameter ``incols`` to choose which columns are x, y, z, respectively. - $projection - $region + position + Specify the position of the vertical scale bar on the plot. See + :class:`pygmt.params.Position` for more details. + length + Length of the vertical scale bar in data (z) units. + label + Set the z unit label that is used in the scale label [Default is no unit]. + label_alignment + Set the alignment of the scale label. Choose from ``"left"`` or ``"right"`` + [Default is ``"left"``]. scale : str or float Give anomaly scale in data-units/distance-unit. Append **c**, **i**, or **p** to indicate the distance unit (centimeters, inches, or points); if no unit is given we use the default unit that is controlled by :gmt-term:`PROJ_LENGTH_UNIT`. - $frame - position : str - [**g**\|\ **j**\|\ **J**\|\ **n**\|\ **x**]\ *refpoint*\ - **+w**\ *length*\ [**+j**\ *justify*]\ [**+al**\|\ **r**]\ - [**+o**\ *dx*\ [/*dy*]][**+l**\ [*label*]]. - Define the reference point on the map for the vertical scale bar. positive_fill : str Set color or pattern for filling positive wiggles [Default is no fill]. negative_fill : str @@ -127,9 +134,12 @@ def wiggle( # noqa: PLR0913 track : str Draw track [Default is no track]. Append pen attributes to use [Default is ``"0.25p,black,solid"``]. - $verbose pen : str Specify outline pen attributes [Default is no outline]. + $projection + $region + $frame + $verbose $binary $panel $nodata @@ -144,9 +154,29 @@ def wiggle( # noqa: PLR0913 """ self._activate_figure() + if isinstance(position, str) and any( + v is not None for v in (length, label, label_alignment) + ): + msg = ( + "Parameter 'position' is given with a raw GMT command string, and conflicts " + "with parameters 'length', 'label', and 'label_alignment'." + ) + raise GMTInvalidInput(msg) + _fills = _parse_fills(positive_fill, negative_fill) aliasdict = AliasSystem( + D=[ + Alias(position, name="position"), + Alias(length, name="length", prefix="+w"), + Alias( + label_alignment, + name="label_alignment", + prefix="+a", + mapping={"left": "l", "right": "r"}, + ), + Alias(label, name="label", prefix="+l"), + ], G=Alias(_fills, name="positive_fill/negative_fill"), ).add_common( B=frame, diff --git a/pygmt/tests/test_wiggle.py b/pygmt/tests/test_wiggle.py index 76d2304496b..4ddf219c55d 100644 --- a/pygmt/tests/test_wiggle.py +++ b/pygmt/tests/test_wiggle.py @@ -5,6 +5,8 @@ import numpy as np import pytest from pygmt import Figure +from pygmt.exceptions import GMTInvalidInput +from pygmt.params import Position @pytest.mark.mpl_image_compare @@ -28,7 +30,35 @@ def test_wiggle(): negative_fill="gray", pen="1.0p", track="0.5p", - position="jRM+w2+lnT", + position=Position("MR"), + length=2, + label="nT", + ) + return fig + + +@pytest.mark.mpl_image_compare(filename="test_wiggle.png") +def test_wiggle_deprecated_position_syntax(): + """ + Test the deprecated position syntax for wiggle. + """ + x = np.arange(-2, 2, 0.02) + y = np.zeros(x.size) + z = np.cos(2 * np.pi * x) + + fig = Figure() + fig.wiggle( + region=[-4, 4, -1, 1], + projection="X8c", + x=x, + y=y, + z=z, + scale="0.5c", + positive_fill="red", + negative_fill="gray", + pen="1.0p", + track="0.5p", + position="jMR+w2+lnT", ) return fig @@ -39,7 +69,6 @@ def test_wiggle_data_incols(): """ Make sure that incols parameter works with input data array. """ - # put data into numpy array and swap x and y columns # as the use of the 'incols' parameter will reverse this action x = np.arange(-2, 2, 0.02) @@ -58,6 +87,39 @@ def test_wiggle_data_incols(): negative_fill="gray", pen="1.0p", track="0.5p", - position="jRM+w2+lnT", + position=Position("MR"), + length=2, + label="nT", ) return fig + + +def test_wiggle_mixed_syntax(): + """ + Test that an error is raised when mixing new and deprecated syntax in 'position'. + """ + fig = Figure() + x = np.arange(-2, 2, 0.02) + y = np.zeros(x.size) + z = np.cos(2 * np.pi * x) + + kwargs = { + "region": [-4, 4, -1, 1], + "projection": "X8c", + "x": x, + "y": y, + "z": z, + "scale": "0.5c", + "positive_fill": "red", + "negative_fill": "gray", + "pen": "1.0p", + "track": "0.5p", + } + with pytest.raises(GMTInvalidInput): + fig.wiggle(position="jMR+w2+lnT", length=2, **kwargs) + + with pytest.raises(GMTInvalidInput): + fig.wiggle(position="jMR+w2+lnT", label="nT", **kwargs) + + with pytest.raises(GMTInvalidInput): + fig.wiggle(position="jMR+w2+lnT", length_alignment="left", **kwargs)