Skip to content

Commit c9d18aa

Browse files
authored
Figure.wiggle: Add parameters position/length/label/label_alignment for the scalebar position and properties (#4049)
1 parent f948ee4 commit c9d18aa

File tree

4 files changed

+163
-41
lines changed

4 files changed

+163
-41
lines changed

examples/gallery/lines/wiggle.py

Lines changed: 14 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22
Wiggle along tracks
33
===================
44
5-
The :meth:`pygmt.Figure.wiggle` method can plot z = f(x,y) anomalies along
6-
tracks. ``x``, ``y``, ``z`` can be specified as 1-D arrays or within a
7-
specified file. The ``scale`` parameter can be used to set the scale of the
8-
anomaly in data/distance units. The positive and/or negative areas can be
9-
filled with color by setting the ``positive_fill`` and/or ``negative_fill``
10-
parameters.
5+
The :meth:`pygmt.Figure.wiggle` method can plot z = f(x,y) anomalies along tracks.
6+
``x``, ``y``, ``z`` can be specified as 1-D arrays or within a specified file. The
7+
``scale`` parameter can be used to set the scale of the anomaly in data/distance units.
8+
The positive and/or negative areas can be filled with color by setting the
9+
``positive_fill`` and/or ``negative_fill`` parameters.
1110
"""
1211

1312
# %%
1413
import numpy as np
1514
import pygmt
15+
from pygmt.params import Position
1616

1717
# Create (x, y, z) triplets
1818
x = np.arange(-7, 7, 0.1)
@@ -25,18 +25,13 @@
2525
x=x,
2626
y=y,
2727
z=z,
28-
# Set anomaly scale to 20 centimeters
29-
scale="20c",
30-
# Fill positive areas red
31-
positive_fill="red",
32-
# Fill negative areas gray
33-
negative_fill="gray",
34-
# Set the outline width to 1.0 point
35-
pen="1.0p",
36-
# Draw a blue track with a width of 0.5 points
37-
track="0.5p,blue",
38-
# Plot a vertical scale bar at Middle Right (MR). The bar length (+w)
39-
# is 100 in data (z) units. Set the z unit label (+l) to "nT".
40-
position="jMR+w100+lnT",
28+
scale="20c", # Set anomaly scale to 20 centimeters
29+
positive_fill="red", # Fill positive areas red
30+
negative_fill="gray", # Fill negative areas gray
31+
pen="1.0p", # Set the outline width to 1.0 point
32+
track="0.5p,blue", # Draw a blue track with a width of 0.5 points
33+
position=Position("MR"), # Plot a vertical scale bar at Middle Right (MR).
34+
length=100, # Bar length is 100 in data (z) units.
35+
label="nT", # Set the z unit label to "nT".
4136
)
4237
fig.show()

pygmt/src/wiggle.py

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
from collections.abc import Sequence
66
from typing import Literal
77

8-
from pygmt._typing import PathLike, TableLike
8+
from pygmt._typing import AnchorCode, PathLike, TableLike
99
from pygmt.alias import Alias, AliasSystem
1010
from pygmt.clib import Session
1111
from pygmt.helpers import build_arg_list, deprecate_parameter, fmt_docstring, use_alias
12+
from pygmt.params import Position
13+
from pygmt.src._common import _parse_position
1214

1315

1416
def _parse_fills(positive_fill, negative_fill):
@@ -46,7 +48,6 @@ def _parse_fills(positive_fill, negative_fill):
4648
"fillnegative", "negative_fill", "v0.18.0", remove_version="v0.20.0"
4749
)
4850
@use_alias(
49-
D="position",
5051
T="track",
5152
W="pen",
5253
Z="scale",
@@ -64,6 +65,10 @@ def wiggle( # noqa: PLR0913
6465
x=None,
6566
y=None,
6667
z=None,
68+
position: Position | Sequence[float | str] | AnchorCode | None = None,
69+
length: float | str | None = None,
70+
label: str | None = None,
71+
label_alignment: Literal["left", "right"] | None = None,
6772
positive_fill=None,
6873
negative_fill=None,
6974
projection: str | None = None,
@@ -72,8 +77,8 @@ def wiggle( # noqa: PLR0913
7277
verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"]
7378
| bool = False,
7479
panel: int | Sequence[int] | bool = False,
75-
transparency: float | None = None,
7680
perspective: float | Sequence[float] | str | bool = False,
81+
transparency: float | None = None,
7782
incols: int | str | Sequence[int | str] | None = None,
7883
**kwargs,
7984
):
@@ -89,6 +94,7 @@ def wiggle( # noqa: PLR0913
8994
9095
$aliases
9196
- B = frame
97+
- D = **+w**: length, **+l**: label, **+a**: label_alignment
9298
- G = **+p**: positive_fill, **+n**: negative_fill
9399
- J = projection
94100
- R = region
@@ -107,29 +113,45 @@ def wiggle( # noqa: PLR0913
107113
$table_classes.
108114
Use parameter ``incols`` to choose which columns are x, y, z,
109115
respectively.
110-
$projection
111-
$region
116+
117+
position
118+
Position of the vertical scale on the plot. It can be specified in multiple
119+
ways:
120+
121+
- A :class:`pygmt.params.Position` object to fully control the reference point,
122+
anchor point, and offset.
123+
- A sequence of two values representing the x- and y- coordinates in plot
124+
coordinates, e.g., ``(1, 2)`` or ``("1c", "2c")``.
125+
- A :doc:`2-character justification code </techref/justification_codes>` for a
126+
position inside the plot, e.g., ``"TL"`` for Top Left corner inside the plot.
127+
128+
If not specified, defaults to the Bottom Left corner of the plot with a 0.2-cm
129+
offset.
130+
length
131+
Length of the vertical scale bar in data (z) units.
132+
label
133+
Set the z unit label that is used in the scale label [Default is no unit].
134+
label_alignment
135+
Set the alignment of the scale label. Choose from ``"left"`` or ``"right"``
136+
[Default is ``"left"``].
112137
scale : str or float
113138
Give anomaly scale in data-units/distance-unit. Append **c**, **i**,
114139
or **p** to indicate the distance unit (centimeters, inches, or
115140
points); if no unit is given we use the default unit that is
116141
controlled by :gmt-term:`PROJ_LENGTH_UNIT`.
117-
$frame
118-
position : str
119-
[**g**\|\ **j**\|\ **J**\|\ **n**\|\ **x**]\ *refpoint*\
120-
**+w**\ *length*\ [**+j**\ *justify*]\ [**+al**\|\ **r**]\
121-
[**+o**\ *dx*\ [/*dy*]][**+l**\ [*label*]].
122-
Define the reference point on the map for the vertical scale bar.
123142
positive_fill : str
124143
Set color or pattern for filling positive wiggles [Default is no fill].
125144
negative_fill : str
126145
Set color or pattern for filling negative wiggles [Default is no fill].
127146
track : str
128147
Draw track [Default is no track]. Append pen attributes to use
129148
[Default is ``"0.25p,black,solid"``].
130-
$verbose
131149
pen : str
132150
Specify outline pen attributes [Default is no outline].
151+
$projection
152+
$region
153+
$frame
154+
$verbose
133155
$binary
134156
$panel
135157
$nodata
@@ -144,9 +166,26 @@ def wiggle( # noqa: PLR0913
144166
"""
145167
self._activate_figure()
146168

169+
position = _parse_position(
170+
position,
171+
kwdict={"length": length, "label": label, "label_alignment": label_alignment},
172+
default=Position("BL", offset=0.2), # Default to BL with 0.2-cm offset.
173+
)
174+
147175
_fills = _parse_fills(positive_fill, negative_fill)
148176

149177
aliasdict = AliasSystem(
178+
D=[
179+
Alias(position, name="position"),
180+
Alias(length, name="length", prefix="+w"),
181+
Alias(
182+
label_alignment,
183+
name="label_alignment",
184+
prefix="+a",
185+
mapping={"left": "l", "right": "r"},
186+
),
187+
Alias(label, name="label", prefix="+l"),
188+
],
150189
G=Alias(_fills, name="positive_fill/negative_fill"),
151190
).add_common(
152191
B=frame,
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
outs:
2+
- md5: 362640b4554c7e5097340c578a672988
3+
size: 16058
4+
hash: md5
5+
path: test_wiggle_default_position.png

pygmt/tests/test_wiggle.py

Lines changed: 93 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,73 @@
55
import numpy as np
66
import pytest
77
from pygmt import Figure
8+
from pygmt.exceptions import GMTInvalidInput
9+
from pygmt.params import Position
810

911

10-
@pytest.mark.mpl_image_compare
11-
def test_wiggle():
12+
@pytest.fixture(scope="module", name="data")
13+
def fixture_xyz():
1214
"""
13-
Plot the z=f(x,y) anomalies along tracks.
15+
Create sample (x, y, z) data for testing.
1416
"""
1517
x = np.arange(-2, 2, 0.02)
1618
y = np.zeros(x.size)
1719
z = np.cos(2 * np.pi * x)
20+
return (x, y, z)
21+
22+
23+
@pytest.mark.mpl_image_compare
24+
def test_wiggle(data):
25+
"""
26+
Plot the z=f(x,y) anomalies along tracks.
27+
"""
28+
x, y, z = data
29+
fig = Figure()
30+
fig.wiggle(
31+
region=[-4, 4, -1, 1],
32+
projection="X8c",
33+
x=x,
34+
y=y,
35+
z=z,
36+
scale="0.5c",
37+
positive_fill="red",
38+
negative_fill="gray",
39+
pen="1.0p",
40+
track="0.5p",
41+
position=Position("MR"),
42+
length=2,
43+
label="nT",
44+
)
45+
return fig
46+
47+
48+
@pytest.mark.mpl_image_compare
49+
def test_wiggle_default_position(data):
50+
"""
51+
Test that wiggle works when position is not provided.
52+
"""
53+
x, y, z = data
54+
fig = Figure()
55+
fig.wiggle(
56+
region=[-4, 4, -1, 1],
57+
projection="X8c",
58+
frame=True,
59+
x=x,
60+
y=y,
61+
z=z,
62+
pen="1p",
63+
scale="0.5c",
64+
length=1,
65+
)
66+
return fig
67+
1868

69+
@pytest.mark.mpl_image_compare(filename="test_wiggle.png")
70+
def test_wiggle_deprecated_position_syntax(data):
71+
"""
72+
Test the deprecated position syntax for wiggle.
73+
"""
74+
x, y, z = data
1975
fig = Figure()
2076
fig.wiggle(
2177
region=[-4, 4, -1, 1],
@@ -28,23 +84,20 @@ def test_wiggle():
2884
negative_fill="gray",
2985
pen="1.0p",
3086
track="0.5p",
31-
position="jRM+w2+lnT",
87+
position="jMR+w2+lnT",
3288
)
3389
return fig
3490

3591

3692
@pytest.mark.benchmark
3793
@pytest.mark.mpl_image_compare(filename="test_wiggle.png")
38-
def test_wiggle_data_incols():
94+
def test_wiggle_data_incols(data):
3995
"""
4096
Make sure that incols parameter works with input data array.
4197
"""
42-
4398
# put data into numpy array and swap x and y columns
4499
# as the use of the 'incols' parameter will reverse this action
45-
x = np.arange(-2, 2, 0.02)
46-
y = np.zeros(x.size)
47-
z = np.cos(2 * np.pi * x)
100+
x, y, z = data
48101
data = np.array([y, x, z]).T
49102

50103
fig = Figure()
@@ -58,6 +111,36 @@ def test_wiggle_data_incols():
58111
negative_fill="gray",
59112
pen="1.0p",
60113
track="0.5p",
61-
position="jRM+w2+lnT",
114+
position=Position("MR"),
115+
length=2,
116+
label="nT",
62117
)
63118
return fig
119+
120+
121+
def test_wiggle_mixed_syntax(data):
122+
"""
123+
Test that an error is raised when mixing new and deprecated syntax in 'position'.
124+
"""
125+
x, y, z = data
126+
fig = Figure()
127+
kwargs = {
128+
"region": [-4, 4, -1, 1],
129+
"projection": "X8c",
130+
"x": x,
131+
"y": y,
132+
"z": z,
133+
"scale": "0.5c",
134+
"positive_fill": "red",
135+
"negative_fill": "gray",
136+
"pen": "1.0p",
137+
"track": "0.5p",
138+
}
139+
with pytest.raises(GMTInvalidInput):
140+
fig.wiggle(position="jMR+w2+lnT", length=2, **kwargs)
141+
142+
with pytest.raises(GMTInvalidInput):
143+
fig.wiggle(position="jMR+w2+lnT", label="nT", **kwargs)
144+
145+
with pytest.raises(GMTInvalidInput):
146+
fig.wiggle(position="jMR+w2+lnT", length_alignment="left", **kwargs)

0 commit comments

Comments
 (0)