Skip to content

Commit f819266

Browse files
authored
Merge branch 'main' into basemap/box
2 parents 50c5614 + a668235 commit f819266

File tree

5 files changed

+142
-55
lines changed

5 files changed

+142
-55
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
"""
2+
3-D bar plot
3+
============
4+
5+
A 3-D bar plot can be created from any collection of three-dimensional tabular data. The
6+
data points can lie on a regular grid or be irregularly scattered. A special case is
7+
creating such a 3-D bar plot based on a grid. This can be done in two steps:
8+
9+
1. Converting the grid into a table via :func:`pygmt.grd2xyz`, with columns "x", "y",
10+
and "z" for longitude, latitude, and the quantity displayed by the grid,
11+
respectively.
12+
2. Plotting this table as bars in 3-D using :meth:`pygmt.Figure.plot3d`.
13+
14+
The bars can be outlined, and the fill can be one color or based on a quantity using a
15+
colormap. For the latter, a fourth column needs to be added containing the values of the
16+
quantity for the color-coding.
17+
"""
18+
19+
# %%
20+
import pygmt
21+
from pygmt.params import Position
22+
23+
# Define a study area around northern Japan with large elevation changes
24+
region = [141, 147, 36, 43]
25+
26+
# Download a grid for the Earth relief with a resolution of 10 arc-minutes
27+
grid = pygmt.datasets.load_earth_relief(resolution="10m", region=region)
28+
29+
# Convert the grid into a pandas DataFrame, with columns for longitude ("x"), latitude
30+
# ("y") and elevation ("z")
31+
grd_df = pygmt.grd2xyz(grid=grid)
32+
zmin = grd_df["z"].min() - 50
33+
zmax = grd_df["z"].max() + 50
34+
35+
# Add a fourth column "color" for the quantity used for the color-coding of the bars,
36+
# here we use the elevation ("z")
37+
grd_df["color"] = grd_df["z"]
38+
39+
# Create a 3-D bar plot with color-coding
40+
fig = pygmt.Figure()
41+
42+
fig.basemap(
43+
region=[*region, zmin, zmax],
44+
projection="M10c",
45+
zsize="8c",
46+
frame=["WSneZ", "xaf", "yag", "za1000f500+lElevation / m"],
47+
perspective=(195, 30),
48+
)
49+
50+
pygmt.makecpt(cmap="SCM/oleron", series=(zmin, zmax))
51+
fig.plot3d(
52+
data=grd_df,
53+
# Use "o" to plot bars and give the desired size
54+
# The base of the bars is set via "+b"
55+
style=f"o0.34c+b{zmin}",
56+
cmap=True,
57+
pen="0.01p,gray30",
58+
perspective=True,
59+
)
60+
fig.colorbar(
61+
frame=["xa1000f500+lElevation", "y+lm"],
62+
position=Position("TR", cstype="inside", offset=1.4),
63+
orientation="vertical",
64+
length=7,
65+
move_text="label",
66+
label_as_column=True,
67+
)
68+
69+
fig.show()

pygmt/src/colorbar.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,59 @@ def _alias_option_D( # noqa: N802, PLR0913
3333
):
3434
"""
3535
Return a list of Alias objects for the -D option.
36+
37+
Examples
38+
--------
39+
>>> def parse(**kwargs):
40+
... return AliasSystem(D=_alias_option_D(**kwargs)).get("D")
41+
>>> parse(position=Position("TL", offset=0.2), length=4, width=0.5)
42+
'jTL+o0.2+w4/0.5'
43+
>>> parse(orientation="horizontal")
44+
'+h'
45+
>>> parse(orientation="vertical")
46+
'+v'
47+
>>> parse(reverse=True)
48+
'+r'
49+
>>> parse(nan=True)
50+
'+n'
51+
>>> parse(nan=True, nan_position="end")
52+
'+N'
53+
>>> parse(fg_triangle=True, bg_triangle=True)
54+
'+e'
55+
>>> parse(fg_triangle=True)
56+
'+ef'
57+
>>> parse(bg_triangle=True)
58+
'+eb'
59+
>>> parse(fg_triangle=True, triangle_height=0.4)
60+
'+ef0.4'
61+
>>> parse(fg_triangle=True, bg_triangle=True, triangle_height=0.3)
62+
'+e0.3'
63+
>>> parse(move_text="annotations")
64+
'+ma'
65+
>>> parse(move_text="label")
66+
'+ml'
67+
>>> parse(move_text="unit")
68+
'+mu'
69+
>>> parse(move_text=["annotations", "label", "unit"])
70+
'+malu'
71+
>>> parse(label_as_column=True)
72+
'+mc'
73+
>>> parse(move_text=["annotations", "label"], label_as_column=True)
74+
'+malc'
75+
>>> parse(
76+
... position=Position("BR", offset=(0.1, 0.2)),
77+
... length=5,
78+
... width=0.4,
79+
... orientation="vertical",
80+
... reverse=True,
81+
... nan=True,
82+
... nan_position="start",
83+
... bg_triangle=True,
84+
... triangle_height=0.2,
85+
... move_text=["annotations", "unit"],
86+
... label_as_column=True,
87+
... )
88+
'jBR+o0.1/0.2+w5/0.4+v+r+n+eb0.2+mauc'
3689
"""
3790
# Build the +e modifier from fg_triangle/bg_triangle/triangle_height
3891
if fg_triangle and bg_triangle:

pygmt/src/grdproject.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ def grdproject( # noqa: PLR0913
120120
msg = "Parameter 'projection' must be specified."
121121
raise GMTInvalidInput(msg)
122122

123+
if kwargs.get("M", unit) is not None and kwargs.get("F", scaling) is not False:
124+
msg = "Cannot use both 'unit' and 'scaling'."
125+
raise GMTInvalidInput(msg)
126+
123127
aliasdict = AliasSystem(
124128
C=Alias(center, name="center", sep="/", size=2),
125129
D=Alias(spacing, name="spacing", sep="/", size=2),

pygmt/tests/test_colorbar.py

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44

55
import pytest
66
from pygmt import Figure
7-
from pygmt.alias import AliasSystem
87
from pygmt.exceptions import GMTInvalidInput
98
from pygmt.params.position import Position
10-
from pygmt.src.colorbar import _alias_option_D
119

1210

1311
@pytest.mark.benchmark
@@ -37,59 +35,6 @@ def test_colorbar_shading_list():
3735
return fig
3836

3937

40-
def test_colorbar_alias_D(): # noqa: N802
41-
"""
42-
Test the parameters for the -D option.
43-
"""
44-
45-
def alias_wrapper(**kwargs):
46-
"""
47-
A wrapper function for testing the parameters of -D option.
48-
"""
49-
return AliasSystem(D=_alias_option_D(**kwargs)).get("D")
50-
51-
argstr = alias_wrapper(position=Position("TL", offset=0.2), length=4, width=0.5)
52-
assert argstr == "jTL+o0.2+w4/0.5"
53-
54-
assert alias_wrapper(orientation="horizontal") == "+h"
55-
assert alias_wrapper(orientation="vertical") == "+v"
56-
57-
assert alias_wrapper(reverse=True) == "+r"
58-
59-
assert alias_wrapper(nan=True) == "+n"
60-
assert alias_wrapper(nan=True, nan_position="end") == "+N"
61-
62-
assert alias_wrapper(fg_triangle=True, bg_triangle=True) == "+e"
63-
assert alias_wrapper(fg_triangle=True) == "+ef"
64-
assert alias_wrapper(bg_triangle=True) == "+eb"
65-
assert alias_wrapper(fg_triangle=True, triangle_height=0.4) == "+ef0.4"
66-
argstr = alias_wrapper(fg_triangle=True, bg_triangle=True, triangle_height=0.3)
67-
assert argstr == "+e0.3"
68-
69-
assert alias_wrapper(move_text="annotations") == "+ma"
70-
assert alias_wrapper(move_text="label") == "+ml"
71-
assert alias_wrapper(move_text="unit") == "+mu"
72-
assert alias_wrapper(move_text=["annotations", "label", "unit"]) == "+malu"
73-
assert alias_wrapper(label_as_column=True) == "+mc"
74-
argstr = alias_wrapper(move_text=["annotations", "label"], label_as_column=True)
75-
assert argstr == "+malc"
76-
77-
argstr = alias_wrapper(
78-
position=Position("BR", offset=(0.1, 0.2)),
79-
length=5,
80-
width=0.4,
81-
orientation="vertical",
82-
reverse=True,
83-
nan=True,
84-
nan_position="start",
85-
bg_triangle=True,
86-
triangle_height=0.2,
87-
move_text=["annotations", "unit"],
88-
label_as_column=True,
89-
)
90-
assert argstr == "jBR+o0.1/0.2+w5/0.4+v+r+n+eb0.2+mauc"
91-
92-
9338
@pytest.mark.mpl_image_compare(filename="test_colorbar.png")
9439
def test_colorbar_position_deprecated_syntax():
9540
"""

pygmt/tests/test_grdproject.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,22 @@ def test_grdproject_no_outgrid(grid, projection, expected_grid):
8181
xr.testing.assert_allclose(a=result, b=expected_grid)
8282

8383

84+
def test_grdproject_unit_scaling(grid):
85+
"""
86+
Test that the input validation to prevent passing both 'unit' and
87+
'scaling' is performed.
88+
"""
89+
with pytest.raises(GMTInvalidInput):
90+
grdproject(
91+
grid=grid,
92+
projection="M10c",
93+
spacing=3,
94+
unit="i",
95+
scaling="k",
96+
region=[-53, -51, -20, -17],
97+
)
98+
99+
84100
def test_grdproject_fails(grid):
85101
"""
86102
Check that grdproject fails correctly.

0 commit comments

Comments
 (0)