Skip to content

Commit 4660546

Browse files
Merge branch 'main' into copilot/update-figure-map-usage
2 parents 5613030 + 8489df6 commit 4660546

8 files changed

Lines changed: 162 additions & 42 deletions

File tree

examples/gallery/histograms/scatter_and_histograms.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
# %%
1212
import numpy as np
1313
import pygmt
14+
from pygmt.params import Axis, Frame
1415

1516
# Generate random x-, y-coordinates from a standard normal distribution.
1617
# x-values are centered on 0 with a standard deviation of 1, and y-values are centered
@@ -35,7 +36,7 @@
3536
fig.basemap(
3637
region=[xmin, xmax, ymin, ymax],
3738
projection=f"X{width}/{height}",
38-
frame=["WSrt", "af"],
39+
frame=Frame(axes="WSrt", axis=Axis(annot=True, tick=True)),
3940
)
4041

4142
# Plot data points as circles with a diameter of 0.15 centimeters and set transparency
@@ -46,7 +47,11 @@
4647
with fig.shift_origin(yshift=height + 0.25):
4748
fig.histogram(
4849
projection=f"X{width}/3",
49-
frame=["Wsrt", "xf", "yaf+lCounts"],
50+
frame=Frame(
51+
axes="Wsrt",
52+
xaxis=Axis(tick=True),
53+
yaxis=Axis(annot=True, tick=True, label="Counts"),
54+
),
5055
# Give the same value for ymin and ymax to have them calculated automatically.
5156
region=[xmin, xmax, 0, 0],
5257
data=x,
@@ -63,7 +68,11 @@
6368
horizontal=True,
6469
projection=f"X3/{height}",
6570
# Note that the x- and y-axes are flipped, with the y-axis plotted horizontally.
66-
frame=["wSrt", "xf", "yaf+lCounts"],
71+
frame=Frame(
72+
axes="wSrt",
73+
xaxis=Axis(tick=True),
74+
yaxis=Axis(annot=True, tick=True, label="Counts"),
75+
),
6776
region=[ymin, ymax, 0, 0],
6877
data=y,
6978
fill=fill,

pygmt/params/frame.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ class _Axes(BaseParam):
7979

8080
axes: str | None = None
8181
title: str | None = None
82+
fill: str | None = None
8283

8384
@property
8485
def _aliases(self):
8586
return [
8687
Alias(self.axes, name="axes"),
88+
Alias(self.fill, name="fill", prefix="+g"),
8789
Alias(self.title, name="title", prefix="+t"),
8890
]
8991

@@ -173,6 +175,10 @@ class Frame(BaseParam):
173175
#: The title string centered above the plot frame [Default is no title].
174176
title: str | None = None
175177

178+
#: Fill for the interior of the frame with a color or a pattern [Default is no
179+
#: fill].
180+
fill: str | None = None
181+
176182
#: Specify the attributes for axes by an :class:`Axis` object.
177183
#:
178184
#: The attributes for x and y axes can be specified in two ways: (1) specifying the
@@ -209,7 +215,7 @@ def _validate(self):
209215
def _aliases(self):
210216
# _Axes() maps to an empty string, which becomes '-B' without arguments and is
211217
# invalid when combined with individual axis settings (e.g., '-B -Bxaf -Byaf').
212-
frame_settings = _Axes(axes=self.axes, title=self.title)
218+
frame_settings = _Axes(axes=self.axes, title=self.title, fill=self.fill)
213219
return [
214220
Alias(frame_settings) if str(frame_settings) else Alias(None),
215221
Alias(self.axis, name="axis"),

pygmt/src/colorbar.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,26 @@ def _alias_option_D( # noqa: N802, PLR0913
210210
]
211211

212212

213+
def _alias_option_N(dpi=None): # noqa: N802
214+
"""
215+
Return an Alias object for the colorbar encoding setting.
216+
217+
The ``dpi`` parameter controls how the colorbar is encoded graphically. Passing
218+
``0`` preferentially draws color rectangles. Any positive integer is passed through
219+
as the rasterization resolution.
220+
221+
Examples
222+
--------
223+
>>> def parse(**kwargs):
224+
... return AliasSystem(N=_alias_option_N(**kwargs)).get("N")
225+
>>> parse(dpi=300)
226+
'300'
227+
>>> parse(dpi=0)
228+
'p'
229+
"""
230+
return Alias("p" if dpi == 0 else dpi, name="dpi")
231+
232+
213233
@fmt_docstring
214234
@use_alias(C="cmap", L="equalsize", Z="zfile")
215235
def colorbar( # noqa: PLR0913
@@ -240,6 +260,7 @@ def colorbar( # noqa: PLR0913
240260
log: bool = False,
241261
scale: float | None = None,
242262
monochrome: bool = False,
263+
dpi: int | None = None,
243264
projection: str | None = None,
244265
region: Sequence[float | str] | str | None = None,
245266
frame: str | Sequence[str] | Literal["none"] | bool = False,
@@ -280,6 +301,7 @@ def colorbar( # noqa: PLR0913
280301
- I = shading
281302
- J = projection
282303
- M = monochrome
304+
- N = dpi
283305
- Q = log
284306
- R = region
285307
- V = verbose
@@ -414,6 +436,17 @@ def colorbar( # noqa: PLR0913
414436
requested colorbar length.
415437
monochrome
416438
Force a monochrome graybar using the (television) YIQ transformation.
439+
dpi
440+
Control how the color scale should be encoded graphically.
441+
442+
- Use a positive integer to draw the color scale as image and set the effective
443+
dots-per-inch for rasterization of color scales, which is useful for
444+
continuous colormaps.
445+
- Use ``dpi=0`` to draw color rectangles, which is useful for discrete
446+
colormaps.
447+
448+
If not specified, GMT uses its default encoding behavior, and the default dpi
449+
is 600 if the colorbar is drawn as image.
417450
$projection
418451
$region
419452
$verbose
@@ -472,6 +505,7 @@ def colorbar( # noqa: PLR0913
472505
G=Alias(truncate, name="truncate", sep="/", size=2),
473506
I=Alias(shading, name="shading", sep="/", size=2),
474507
M=Alias(monochrome, name="monochrome"),
508+
N=_alias_option_N(dpi=dpi),
475509
Q=Alias(log, name="log"),
476510
W=Alias(scale, name="scale"),
477511
).add_common(

pygmt/tests/test_params_frame.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ def test_params_frame_only():
2323
assert str(Frame("WSen")) == "WSen"
2424
assert str(Frame(axes="WSEN", title="My Title")) == "WSEN+tMy Title"
2525

26+
frame = str(Frame(axes="WSEN", title="My Title", fill="red"))
27+
assert frame == "WSEN+gred+tMy Title"
28+
2629

2730
def test_params_frame_axis():
2831
"""

pygmt/tests/test_plot.py

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from pygmt import Figure, which
1313
from pygmt.exceptions import GMTInvalidInput, GMTParameterError, GMTTypeError
1414
from pygmt.helpers import GMTTempFile
15+
from pygmt.params import Axis, Frame
1516

1617
POINTS_DATA = Path(__file__).parent / "data" / "points.txt"
1718

@@ -45,7 +46,7 @@ def test_plot_red_circles(data, region):
4546
projection="X10c",
4647
style="c0.2c",
4748
fill="red",
48-
frame="afg",
49+
frame=Axis(annot=True, tick=True, grid=True),
4950
)
5051
return fig
5152

@@ -57,7 +58,11 @@ def test_plot_fail_no_data(data, region):
5758
fig = Figure()
5859
with pytest.raises(GMTInvalidInput):
5960
fig.plot(
60-
region=region, projection="X10c", style="c0.2c", fill="red", frame="afg"
61+
region=region,
62+
projection="X10c",
63+
style="c0.2c",
64+
fill="red",
65+
frame=Axis(annot=True, tick=True, grid=True),
6166
)
6267
with pytest.raises(GMTInvalidInput):
6368
fig.plot(
@@ -66,7 +71,7 @@ def test_plot_fail_no_data(data, region):
6671
projection="X10c",
6772
style="c0.2c",
6873
fill="red",
69-
frame="afg",
74+
frame=Axis(annot=True, tick=True, grid=True),
7075
)
7176
with pytest.raises(GMTInvalidInput):
7277
fig.plot(
@@ -75,7 +80,7 @@ def test_plot_fail_no_data(data, region):
7580
projection="X10c",
7681
style="c0.2c",
7782
fill="red",
78-
frame="afg",
83+
frame=Axis(annot=True, tick=True, grid=True),
7984
)
8085
# Should also fail if given too much data
8186
with pytest.raises(GMTParameterError):
@@ -87,7 +92,7 @@ def test_plot_fail_no_data(data, region):
8792
projection="X10c",
8893
style="c0.2c",
8994
fill="red",
90-
frame="afg",
95+
frame=Axis(annot=True, tick=True, grid=True),
9196
)
9297

9398

@@ -97,7 +102,12 @@ def test_plot_fail_1d_array_with_data(data, region):
97102
symbol are specified when data is given.
98103
"""
99104
fig = Figure()
100-
kwargs = {"data": data, "region": region, "projection": "X10c", "frame": "afg"}
105+
kwargs = {
106+
"data": data,
107+
"region": region,
108+
"projection": "X10c",
109+
"frame": Frame(axis=Axis(annot=True, tick=True, grid=True)),
110+
}
101111
with pytest.raises(GMTTypeError):
102112
fig.plot(style="c0.2c", fill=data[:, 2], **kwargs)
103113
with pytest.raises(GMTTypeError):
@@ -123,7 +133,7 @@ def test_plot_projection(data):
123133
projection="R270/10c",
124134
style="s0.2c",
125135
fill="green",
126-
frame="ag",
136+
frame=Axis(annot=True, grid=True),
127137
)
128138
return fig
129139

@@ -142,7 +152,7 @@ def test_plot_colors(data, region):
142152
projection="X10c",
143153
style="c0.5c",
144154
cmap="cpt-city/cubhelix",
145-
frame="af",
155+
frame=Axis(annot=True, tick=True),
146156
)
147157
return fig
148158

@@ -161,7 +171,7 @@ def test_plot_sizes(data, region):
161171
projection="X10c",
162172
style="cc",
163173
fill="blue",
164-
frame="af",
174+
frame=Axis(annot=True, tick=True),
165175
)
166176
return fig
167177

@@ -181,7 +191,7 @@ def test_plot_colors_sizes(data, region):
181191
projection="X10c",
182192
style="cc",
183193
cmap="matlab/copper",
184-
frame="af",
194+
frame=Axis(annot=True, tick=True),
185195
)
186196
return fig
187197

@@ -192,7 +202,12 @@ def test_plot_colors_sizes_proj(data, region):
192202
Plot the data using z as sizes and fills with a projection.
193203
"""
194204
fig = Figure()
195-
fig.coast(region=region, projection="M15c", frame="af", water="skyblue")
205+
fig.coast(
206+
region=region,
207+
projection="M15c",
208+
frame=Axis(annot=True, tick=True),
209+
water="skyblue",
210+
)
196211
fig.plot(
197212
x=data[:, 0],
198213
y=data[:, 1],
@@ -219,7 +234,7 @@ def test_plot_varying_intensity():
219234
y=y,
220235
region=[-1.1, 1.1, -0.5, 0.5],
221236
projection="X10c/2c",
222-
frame=["S", "xaf+lIntensity"],
237+
frame=Frame(axes="S", xaxis=Axis(annot=True, tick=True, label="Intensity")),
223238
style="c0.25c",
224239
fill="blue",
225240
intensity=intensity,
@@ -313,7 +328,7 @@ def test_plot_symbol():
313328
fill="blue",
314329
size=[0.1, 0.2, 0.3, 0.4],
315330
symbol=["c", "t", "i", "s"],
316-
frame="af",
331+
frame=Axis(annot=True, tick=True),
317332
)
318333
return fig
319334

@@ -331,7 +346,7 @@ def test_plot_matrix(data, fill):
331346
projection="M15c",
332347
style="cc",
333348
fill=fill,
334-
frame="a",
349+
frame=Axis(annot=True),
335350
incols="0,1,2+s0.5",
336351
)
337352
return fig
@@ -349,7 +364,7 @@ def test_plot_matrix_color(data):
349364
projection="X10c",
350365
style="c0.5c",
351366
cmap="gmt/rainbow",
352-
frame="a",
367+
frame=Axis(annot=True),
353368
)
354369
return fig
355370

@@ -391,7 +406,7 @@ def test_plot_vectors():
391406
projection="X10c",
392407
style="V0.2c+e+n",
393408
fill="black",
394-
frame="af",
409+
frame=Axis(annot=True, tick=True),
395410
)
396411
return fig
397412

@@ -488,7 +503,11 @@ def test_plot_timedelta64():
488503
fig.basemap(
489504
projection="X8c/5c",
490505
region=[tmin, tmax, 0, 10],
491-
frame=["WSne", "xaf+lForecast Days", "yaf+lRMSE"],
506+
frame=Frame(
507+
axes="WSne",
508+
xaxis=Axis(annot=True, tick=True, label="Forecast Days"),
509+
yaxis=Axis(annot=True, tick=True, label="RMSE"),
510+
),
492511
)
493512
fig.plot(
494513
x=np.arange(tmin, tmax),

0 commit comments

Comments
 (0)