From b69b470cd96025e1290c613e1db931f5c720f00b Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 8 Sep 2026 19:01:23 +0800 Subject: [PATCH 1/4] Figure.histogram: Improved syntax for filling bars by position/value --- pygmt/src/histogram.py | 39 +++++++++-- pygmt/tests/baseline/test_histogram_fill.png | 3 + pygmt/tests/test_histogram.py | 73 +++++++++++++++++++- 3 files changed, 108 insertions(+), 7 deletions(-) create mode 100644 pygmt/tests/baseline/test_histogram_fill.png diff --git a/pygmt/src/histogram.py b/pygmt/src/histogram.py index b06e4b15737..6dd898c92ca 100644 --- a/pygmt/src/histogram.py +++ b/pygmt/src/histogram.py @@ -12,6 +12,7 @@ from pygmt.helpers import ( build_arg_list, fmt_docstring, + is_given, kwargs_to_strings, use_alias, ) @@ -43,7 +44,7 @@ def histogram( bar_offset: float | str | None = None, cmap: str | bool = False, pen: str | None = None, - fill: str | None = None, + fill: str | Literal["position", "value"] | None = None, horizontal: bool = False, projection: str | None = None, region: Sequence[float | str] | str | None = None, @@ -64,7 +65,7 @@ def histogram( $aliases - A = horizontal - B = frame - - C = cmap + - C = cmap, **+b**: fill - E = bar_width, **+o**: bar_offset - G = fill - J = projection @@ -81,12 +82,21 @@ def histogram( data Pass in either a file name to an ASCII data table, a Python list, a 2-D $table_classes. - $cmap pen Draw bar outline (or stair-case curve) using the specified pen thickness [Default is no outline]. fill - Set color or pattern for filling bars [Default is no fill]. + Set color or pattern for filling bars [Default is no fill]. Set it to one of the + two special values to fill bars by looking up the color from ``cmap`` instead of + a constant color: + + - ``"position"``: look up the color using the mid-coordinate of the bin. This is + the default when ``cmap`` is set. + - ``"value"``: look up the color using the bin value, i.e., the bar count or + frequency. + + The special values require ``cmap``, and can't be used with ``fill``. + $cmap annotate : bool or str [**+b**][**+f**\ *font*][**+o**\ *off*][**+r**]. Annotate each bar with the count it represents. Append any of the @@ -168,14 +178,31 @@ def histogram( required="bar_width", reason="Required when 'bar_offset' is set." ) + # "position" and "value" are special values that fill bars by values and cmap. + match fill: + case "position": + _fill_color, _fill_lookup = None, "" + case "value": + _fill_color, _fill_lookup = None, "+b" + case _: + _fill_color, _fill_lookup = fill, None + if _fill_color is not None and is_given(cmap): + raise GMTParameterError( + at_most_one=["cmap", "fill"], + reason="Cannot use 'cmap' when 'fill' is a constant color or pattern.", + ) + aliasdict = AliasSystem( A=Alias(horizontal, name="horizontal"), - C=Alias(cmap, name="cmap"), + C=[ + Alias(cmap, name="cmap"), + Alias(_fill_lookup, name="fill"), + ], E=[ Alias(bar_width, name="bar_width"), Alias(bar_offset, name="bar_offset", prefix="+o"), ], - G=Alias(fill, name="fill"), + G=Alias(_fill_color, name="fill"), W=Alias(pen, name="pen"), ).add_common( B=frame, diff --git a/pygmt/tests/baseline/test_histogram_fill.png b/pygmt/tests/baseline/test_histogram_fill.png new file mode 100644 index 00000000000..33bdffce4e1 --- /dev/null +++ b/pygmt/tests/baseline/test_histogram_fill.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a82f632aba7a78db5bd880ab34fdeec8c7472b5e1257e79b61efd5ccd72aa813 +size 12900 diff --git a/pygmt/tests/test_histogram.py b/pygmt/tests/test_histogram.py index c839105f995..7d0308e2aa1 100644 --- a/pygmt/tests/test_histogram.py +++ b/pygmt/tests/test_histogram.py @@ -4,7 +4,7 @@ import pandas as pd import pytest -from pygmt import Figure +from pygmt import Figure, makecpt from pygmt.exceptions import GMTParameterError from pygmt.params import Axis @@ -51,3 +51,74 @@ def test_histogram_baroffset(data): fill="green", bar_offset=0.25, ) + + +@pytest.mark.mpl_image_compare(filename="test_histogram_fill.png") +def test_histogram_fill(data): + """ + Test filling bars with constant color and lookup table values. + """ + kwargs = { + "data": data, + "projection": "X5c/5c", + "region": [0, 10, 0, 8], + "series": 1, + "frame": Axis(annot=True), + } + fig = Figure() + # Constant fill + fig.histogram(fill="green", **kwargs) + fig.shift_origin(xshift=6) + # Fill bars by bin position + makecpt(cmap="viridis", series=[0, 9, 1]) + fig.histogram(fill="position", **kwargs) + fig.colorbar(frame=True) + # Fill bars by bin value + fig.shift_origin(xshift=6) + makecpt(cmap="viridis", series=[0, 6, 1]) + fig.histogram(fill="value", **kwargs) + fig.colorbar(frame=True) + return fig + +@pytest.mark.mpl_image_compare(filename="test_histogram_fill.png") +def test_histogram_fill_old_cmap_syntax(data): + """ + Test filling bars with constant color and lookup table values. + """ + kwargs = { + "data": data, + "projection": "X5c/5c", + "region": [0, 10, 0, 8], + "series": 1, + "frame": Axis(annot=True), + } + fig = Figure() + # Constant fill + fig.histogram(fill="green", **kwargs) + fig.shift_origin(xshift=6) + # Fill bars by bin position + makecpt(cmap="viridis", series=[0, 9, 1]) + fig.histogram(cmap=True, **kwargs) + fig.colorbar(frame=True) + # Fill bars by bin value + fig.shift_origin(xshift=6) + makecpt(cmap="viridis", series=[0, 6, 1]) + fig.histogram(cmap="+b", **kwargs) + fig.colorbar(frame=True) + return fig + + +def test_histogram_fill_color_with_cmap(data): + """ + Test that a constant fill color cannot be combined with cmap. + """ + fig = Figure() + with pytest.raises(GMTParameterError): + fig.histogram( + data=data, + projection="X10c/10c", + region=[0, 9, 0, 8], + series=1, + cmap=True, + fill="green", + ) From 75f3fc0dae3f052232b30b54fa1b56fb8103980b Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 9 Sep 2026 16:49:49 +0800 Subject: [PATCH 2/4] Fix styling and typing issues --- pygmt/src/histogram.py | 2 +- pygmt/tests/test_histogram.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/pygmt/src/histogram.py b/pygmt/src/histogram.py index 6dd898c92ca..c443092bee3 100644 --- a/pygmt/src/histogram.py +++ b/pygmt/src/histogram.py @@ -185,7 +185,7 @@ def histogram( case "value": _fill_color, _fill_lookup = None, "+b" case _: - _fill_color, _fill_lookup = fill, None + _fill_color, _fill_lookup = fill, None # type: ignore[assignment] if _fill_color is not None and is_given(cmap): raise GMTParameterError( at_most_one=["cmap", "fill"], diff --git a/pygmt/tests/test_histogram.py b/pygmt/tests/test_histogram.py index 7d0308e2aa1..bd6ef95983d 100644 --- a/pygmt/tests/test_histogram.py +++ b/pygmt/tests/test_histogram.py @@ -80,6 +80,7 @@ def test_histogram_fill(data): fig.colorbar(frame=True) return fig + @pytest.mark.mpl_image_compare(filename="test_histogram_fill.png") def test_histogram_fill_old_cmap_syntax(data): """ From b2efc131988a45662e20182aea6bf32f8405900d Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Wed, 9 Sep 2026 16:51:57 +0800 Subject: [PATCH 3/4] Improve docstrings --- pygmt/src/histogram.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/pygmt/src/histogram.py b/pygmt/src/histogram.py index c443092bee3..ebce1ca92f2 100644 --- a/pygmt/src/histogram.py +++ b/pygmt/src/histogram.py @@ -87,15 +87,16 @@ def histogram( [Default is no outline]. fill Set color or pattern for filling bars [Default is no fill]. Set it to one of the - two special values to fill bars by looking up the color from ``cmap`` instead of - a constant color: + two special values to fill bars by looking up the color from a CPT instead of a + constant color: - ``"position"``: look up the color using the mid-coordinate of the bin. This is the default when ``cmap`` is set. - ``"value"``: look up the color using the bin value, i.e., the bar count or frequency. - The special values require ``cmap``, and can't be used with ``fill``. + The special values require a CPT (either the current CPT or explicitely set by + ``cmap``), and can't be used with ``fill``. $cmap annotate : bool or str [**+b**][**+f**\ *font*][**+o**\ *off*][**+r**]. From 5971115f731d0ab08a1e78b4c7051b808c8156ce Mon Sep 17 00:00:00 2001 From: Dongdong Tian Date: Tue, 15 Sep 2026 19:01:01 +0800 Subject: [PATCH 4/4] Fix a typo [skip ci] MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yvonne Fröhlich <94163266+yvonnefroehlich@users.noreply.github.com> --- pygmt/src/histogram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/src/histogram.py b/pygmt/src/histogram.py index b9c986acc81..cfc6f4aa649 100644 --- a/pygmt/src/histogram.py +++ b/pygmt/src/histogram.py @@ -101,7 +101,7 @@ def histogram( - ``"value"``: look up the color using the bin value, i.e., the bar count or frequency. - The special values require a CPT (either the current CPT or explicitely set by + The special values require a CPT (either the current CPT or explicitly set by ``cmap``), and can't be used with ``fill``. $cmap annotate : bool or str