Skip to content

Commit 3dc7662

Browse files
Figure.histogram: Improved syntax for filling bars by position/value (#4886)
Co-authored-by: Yvonne Fröhlich <94163266+yvonnefroehlich@users.noreply.github.com>
1 parent 6b0ab0c commit 3dc7662

3 files changed

Lines changed: 110 additions & 7 deletions

File tree

‎pygmt/src/histogram.py‎

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
data_kind,
1515
deprecate_parameter,
1616
fmt_docstring,
17+
is_given,
1718
is_nonstr_iter,
1819
kwargs_to_strings,
1920
use_alias,
@@ -206,7 +207,7 @@ def histogram(
206207
bar_offset: float | str | None = None,
207208
cmap: str | bool = False,
208209
pen: str | None = None,
209-
fill: str | Pattern | None = None,
210+
fill: str | Pattern | Literal["position", "value"] | None = None,
210211
annot: bool = False,
211212
annot_position: Literal["start", "end"] = "end",
212213
annot_font: str | None = None,
@@ -240,7 +241,7 @@ def histogram(
240241
$aliases
241242
- A = horizontal
242243
- B = frame
243-
- C = cmap
244+
- C = cmap, **+b**: fill
244245
- D = annot, **+b**: annot_position, **+f**: annot_font, **+o**: annot_offset,
245246
**+r**: annot_orientation
246247
- E = bar_width, **+o**: bar_offset
@@ -271,12 +272,22 @@ def histogram(
271272
is a file name or a 2-D sequence.
272273
- A 1-D array of weights, one per data point, requiring that ``data`` is a 1-D
273274
sequence of values.
274-
$cmap
275275
pen
276276
Draw bar outline (or stair-case curve) using the specified pen thickness
277277
[Default is no outline].
278278
fill
279-
Set color or pattern for filling bars [Default is no fill].
279+
Set color or pattern for filling bars [Default is no fill]. Set it to one of the
280+
two special values to fill bars by looking up the color from a CPT instead of a
281+
constant color:
282+
283+
- ``"position"``: look up the color using the mid-coordinate of the bin. This is
284+
the default when ``cmap`` is set.
285+
- ``"value"``: look up the color using the bin value, i.e., the bar count or
286+
frequency.
287+
288+
The special values require a CPT (either the current CPT or explicitly set by
289+
``cmap``), and can't be used with ``fill``.
290+
$cmap
280291
annot
281292
If ``True``, annotate each bar with the value it represents. The remaining
282293
``annot_*`` parameters control how the annotations look and are ignored if
@@ -384,6 +395,20 @@ def histogram(
384395
required="bar_width", reason="Required when 'bar_offset' is set."
385396
)
386397

398+
# "position" and "value" are special values that fill bars by values and cmap.
399+
match fill:
400+
case "position":
401+
_fill_color, _fill_lookup = None, ""
402+
case "value":
403+
_fill_color, _fill_lookup = None, "+b"
404+
case _:
405+
_fill_color, _fill_lookup = fill, None # type: ignore[assignment]
406+
if _fill_color is not None and is_given(cmap):
407+
raise GMTParameterError(
408+
at_most_one=["cmap", "fill"],
409+
reason="Cannot use 'cmap' when 'fill' is a constant color or pattern.",
410+
)
411+
387412
# weights can be given as a 1-D array, or as a boolean to indicate that the second
388413
# column of data contains weights. If weights is an array, then data must be a 1-D
389414
# sequence of values.
@@ -396,7 +421,10 @@ def histogram(
396421

397422
aliasdict = AliasSystem(
398423
A=Alias(horizontal, name="horizontal"),
399-
C=Alias(cmap, name="cmap"),
424+
C=[
425+
Alias(cmap, name="cmap"),
426+
Alias(_fill_lookup, name="fill"),
427+
],
400428
D=_alias_option_D(
401429
annot=annot,
402430
annot_position=annot_position,
@@ -409,7 +437,7 @@ def histogram(
409437
Alias(bar_offset, name="bar_offset", prefix="+o"),
410438
],
411439
F=Alias(center, name="center"),
412-
G=Alias(fill, name="fill"),
440+
G=Alias(_fill_color, name="fill"),
413441
L=Alias(
414442
out_range,
415443
name="out_range",
Lines changed: 3 additions & 0 deletions
Loading

‎pygmt/tests/test_histogram.py‎

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import numpy as np
66
import pandas as pd
77
import pytest
8-
from pygmt import Figure
8+
from pygmt import Figure, makecpt
99
from pygmt.exceptions import GMTParameterError, GMTTypeError
1010
from pygmt.helpers import GMTTempFile
1111
from pygmt.params import Axis
@@ -84,6 +84,78 @@ def test_histogram_baroffset(data):
8484
)
8585

8686

87+
@pytest.mark.mpl_image_compare(filename="test_histogram_fill.png")
88+
def test_histogram_fill(data):
89+
"""
90+
Test filling bars with constant color and lookup table values.
91+
"""
92+
kwargs = {
93+
"data": data,
94+
"projection": "X5c/5c",
95+
"region": [0, 10, 0, 8],
96+
"series": 1,
97+
"frame": Axis(annot=True),
98+
}
99+
fig = Figure()
100+
# Constant fill
101+
fig.histogram(fill="green", **kwargs)
102+
fig.shift_origin(xshift=6)
103+
# Fill bars by bin position
104+
makecpt(cmap="viridis", series=[0, 9, 1])
105+
fig.histogram(fill="position", **kwargs)
106+
fig.colorbar(frame=True)
107+
# Fill bars by bin value
108+
fig.shift_origin(xshift=6)
109+
makecpt(cmap="viridis", series=[0, 6, 1])
110+
fig.histogram(fill="value", **kwargs)
111+
fig.colorbar(frame=True)
112+
return fig
113+
114+
115+
@pytest.mark.mpl_image_compare(filename="test_histogram_fill.png")
116+
def test_histogram_fill_old_cmap_syntax(data):
117+
"""
118+
Test filling bars with constant color and lookup table values.
119+
"""
120+
kwargs = {
121+
"data": data,
122+
"projection": "X5c/5c",
123+
"region": [0, 10, 0, 8],
124+
"series": 1,
125+
"frame": Axis(annot=True),
126+
}
127+
fig = Figure()
128+
# Constant fill
129+
fig.histogram(fill="green", **kwargs)
130+
fig.shift_origin(xshift=6)
131+
# Fill bars by bin position
132+
makecpt(cmap="viridis", series=[0, 9, 1])
133+
fig.histogram(cmap=True, **kwargs)
134+
fig.colorbar(frame=True)
135+
# Fill bars by bin value
136+
fig.shift_origin(xshift=6)
137+
makecpt(cmap="viridis", series=[0, 6, 1])
138+
fig.histogram(cmap="+b", **kwargs)
139+
fig.colorbar(frame=True)
140+
return fig
141+
142+
143+
def test_histogram_fill_color_with_cmap(data):
144+
"""
145+
Test that a constant fill color cannot be combined with cmap.
146+
"""
147+
fig = Figure()
148+
with pytest.raises(GMTParameterError):
149+
fig.histogram(
150+
data=data,
151+
projection="X10c/10c",
152+
region=[0, 9, 0, 8],
153+
series=1,
154+
cmap=True,
155+
fill="green",
156+
)
157+
158+
87159
@pytest.mark.mpl_image_compare(filename="test_histogram_weights.png")
88160
def test_histogram_weights_file(data, weights):
89161
"""

0 commit comments

Comments
 (0)