From 5375cdc808d15716c9ac1a89fbf2d0a7ced36515 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= Date: Sat, 20 Dec 2025 20:07:50 +0100 Subject: [PATCH 01/12] Split bar_width into bar_width and bar_offset --- pygmt/src/histogram.py | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/pygmt/src/histogram.py b/pygmt/src/histogram.py index f1aa068a484..bc9ed8dc12e 100644 --- a/pygmt/src/histogram.py +++ b/pygmt/src/histogram.py @@ -6,7 +6,7 @@ from typing import Literal from pygmt._typing import PathLike, TableLike -from pygmt.alias import AliasSystem +from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session from pygmt.helpers import ( build_arg_list, @@ -23,7 +23,6 @@ A="horizontal", C="cmap", D="annotate", - E="bar_width", F="center", G="fill", L="extreme", @@ -41,10 +40,12 @@ w="wrap", ) @kwargs_to_strings(T="sequence") -def histogram( +def histogram( # noqa: PLR0913 self, data: PathLike | TableLike, projection: str | None = None, + bar_width: float | str | None = None, + bar_offset: float | str | None = None, frame: str | Sequence[str] | bool = False, region: Sequence[float | str] | str | None = None, verbose: Literal["quiet", "error", "warning", "timing", "info", "compat", "debug"] @@ -62,6 +63,7 @@ def histogram( $aliases - B = frame + - E = bar_width, bar_offset - J = projection - R = region - V = verbose @@ -91,15 +93,14 @@ def histogram( annotation font; use **+o** to change the offset between bar and label [Default is ``"6p"``]; use **+r** to rotate the labels from horizontal to vertical. - bar_width : float or str - *width*\ [**+o**\ *offset*]. + bar_width Use an alternative histogram bar width than the default set via - ``series``, and optionally shift all bars by an *offset*. Here - *width* is either an alternative width in data units, or the user may - append a valid plot dimension unit (**c**\|\ **i**\|\ **p**) for a - fixed dimension instead. Optionally, all bins may be shifted along the - axis by *offset*. As for *width*, it may be given in data units of - plot dimension units by appending the relevant unit. + ``series``. Give either an alternative width in data units, or the user + may append a valid plot dimension unit (**c**\|\ **i**\|\ **p**) for a + fixed dimension instead. + bar_offset + Shift all bars along the axis by *offset*. It may be given in data units + of plot dimension units by appending the relevant unit. center : bool Center bin on each value. [Default is left edge]. distribution : bool, float, or str @@ -159,7 +160,14 @@ def histogram( """ self._activate_figure() - aliasdict = AliasSystem().add_common( + # bar_offset requires bar_width + + aliasdict = AliasSystem( + E=[ + Alias(bar_width, name="bar_width"), + Alias(bar_offset, name="bar_offset", prefix="+o"), + ], + ).add_common( B=frame, J=projection, R=region, From ec0e8a4826c7d56d518dec9561d6fb6186a8a205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= Date: Sat, 20 Dec 2025 20:08:10 +0100 Subject: [PATCH 02/12] Update advanced tutorial --- examples/tutorials/advanced/cartesian_histograms.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/examples/tutorials/advanced/cartesian_histograms.py b/examples/tutorials/advanced/cartesian_histograms.py index b97881f6c37..0c2965a8f11 100644 --- a/examples/tutorials/advanced/cartesian_histograms.py +++ b/examples/tutorials/advanced/cartesian_histograms.py @@ -345,9 +345,9 @@ histtype=0, # Calculate the bar width in respect to the bin width, here for two data sets half # of the bin width - # Offset ("+o") the bars to align each bar with the left limit of the corresponding - # bin - bar_width=f"{binwidth / 2}+o-{binwidth / 4}", + bar_width=binwidth / 2, + # Offset the bars to align each bar with the left limit of the corresponding bin + bar_offset=binwidth / 4, label="data01", ) @@ -358,7 +358,8 @@ fill="orange", pen="1p,darkgray,solid", histtype=0, - bar_width=f"{binwidth / 2}+o{binwidth / 4}", + bar_width=binwidth / 2, + bar_offset=binwidth / 4, label="data02", ) From ad19b4b65a4dc0cfbb9856a7da85b3b71a1af083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= Date: Sun, 21 Dec 2025 14:03:29 +0100 Subject: [PATCH 03/12] Add tests --- pygmt/tests/test_histogram.py | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/pygmt/tests/test_histogram.py b/pygmt/tests/test_histogram.py index 8a85ffd4666..bf1106da380 100644 --- a/pygmt/tests/test_histogram.py +++ b/pygmt/tests/test_histogram.py @@ -5,6 +5,7 @@ import pandas as pd import pytest from pygmt import Figure +from pygmt.exceptions import GMTInvalidInput @pytest.fixture(scope="module", name="data", params=[list, pd.Series]) @@ -32,3 +33,38 @@ def test_histogram(data): fill="green", ) return fig + + +def test_histogram_barwidth_baroffset(data): + """ + Test plotting a histogram specifying bar_with and bar_offset. + """ + fig = Figure() + fig.histogram( + data=data, + projection="X10c/10c", + region=[0, 9, 0, 6], + series=1, + frame="a", + fill="green", + bar_width=0.5, + bar_offset=0.25, + ) + return fig + + +def test_histogram_baroffset(data): + """ + Test passing bar_offset requires bar_width. + """ + fig = Figure() + with pytest.raises(GMTInvalidInput): + fig.histogram( + data=data, + projection="X10c/10c", + region=[0, 9, 0, 6], + series=1, + frame="a", + fill="green", + bar_offset=0.25, + ) From 6c14592f48dee0faa563b674f957f167009bcfc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= Date: Sun, 21 Dec 2025 14:03:53 +0100 Subject: [PATCH 04/12] Add error when bar_offset is given without bar_width --- pygmt/src/histogram.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/pygmt/src/histogram.py b/pygmt/src/histogram.py index bc9ed8dc12e..97a482dcf87 100644 --- a/pygmt/src/histogram.py +++ b/pygmt/src/histogram.py @@ -8,6 +8,7 @@ from pygmt._typing import PathLike, TableLike from pygmt.alias import Alias, AliasSystem from pygmt.clib import Session +from pygmt.exceptions import GMTInvalidInput from pygmt.helpers import ( build_arg_list, deprecate_parameter, @@ -160,7 +161,9 @@ def histogram( # noqa: PLR0913 """ self._activate_figure() - # bar_offset requires bar_width + if bar_offset is not None and bar_width is None: + msg = "Setting bar_offset requires setting bar_width." + raise GMTInvalidInput(msg) aliasdict = AliasSystem( E=[ From f6c8f0f2d2c50e8738afa9cc98131cc803ff82d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= Date: Sun, 21 Dec 2025 14:04:38 +0100 Subject: [PATCH 05/12] Add minus sign back --- examples/tutorials/advanced/cartesian_histograms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/tutorials/advanced/cartesian_histograms.py b/examples/tutorials/advanced/cartesian_histograms.py index 0c2965a8f11..5b66707befd 100644 --- a/examples/tutorials/advanced/cartesian_histograms.py +++ b/examples/tutorials/advanced/cartesian_histograms.py @@ -347,7 +347,7 @@ # of the bin width bar_width=binwidth / 2, # Offset the bars to align each bar with the left limit of the corresponding bin - bar_offset=binwidth / 4, + bar_offset=-binwidth / 4, label="data01", ) From f9b9d90b50fae85e4f9a895fb9748d7ab8819d89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= <94163266+yvonnefroehlich@users.noreply.github.com> Date: Fri, 26 Dec 2025 20:54:08 +0100 Subject: [PATCH 06/12] Use quotation marks in error message Co-authored-by: Dongdong Tian --- 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 97a482dcf87..5b52ddac0eb 100644 --- a/pygmt/src/histogram.py +++ b/pygmt/src/histogram.py @@ -162,7 +162,7 @@ def histogram( # noqa: PLR0913 self._activate_figure() if bar_offset is not None and bar_width is None: - msg = "Setting bar_offset requires setting bar_width." + msg = "Setting 'bar_offset' requires setting 'bar_width'." raise GMTInvalidInput(msg) aliasdict = AliasSystem( From a52e00a7b37f56283953b264b160e93ae1fe9dc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= Date: Fri, 26 Dec 2025 21:46:44 +0100 Subject: [PATCH 07/12] Add image comparison --- pygmt/tests/test_histogram.py | 1 + 1 file changed, 1 insertion(+) diff --git a/pygmt/tests/test_histogram.py b/pygmt/tests/test_histogram.py index bf1106da380..8518d56e7d2 100644 --- a/pygmt/tests/test_histogram.py +++ b/pygmt/tests/test_histogram.py @@ -35,6 +35,7 @@ def test_histogram(data): return fig +@pytest.mark.mpl_image_compare(filename="test_histogram_barwidth_baroffset.png") def test_histogram_barwidth_baroffset(data): """ Test plotting a histogram specifying bar_with and bar_offset. From 6efb9e41aacedda199e377bb4743b88806d06d1c Mon Sep 17 00:00:00 2001 From: Yvonne Date: Fri, 26 Dec 2025 21:15:58 +0000 Subject: [PATCH 08/12] Add test_histogram_barwidth_baroffset.png into DVC --- .../baseline/test_histogram_barwidth_baroffset.png.dvc | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100755 pygmt/tests/baseline/test_histogram_barwidth_baroffset.png.dvc diff --git a/pygmt/tests/baseline/test_histogram_barwidth_baroffset.png.dvc b/pygmt/tests/baseline/test_histogram_barwidth_baroffset.png.dvc new file mode 100755 index 00000000000..f238ba1e484 --- /dev/null +++ b/pygmt/tests/baseline/test_histogram_barwidth_baroffset.png.dvc @@ -0,0 +1,6 @@ +outs: +- md5: 9bcab5655f53bfef48ffe0c0c9e41273 + size: 10755 + isexec: true + hash: md5 + path: test_histogram_barwidth_baroffset.png From da861bfa50cb77d3b01b5397d1c7687bc5693c75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= Date: Sat, 27 Dec 2025 11:36:34 +0100 Subject: [PATCH 09/12] Remove test --- pygmt/tests/test_histogram.py | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/pygmt/tests/test_histogram.py b/pygmt/tests/test_histogram.py index 8518d56e7d2..3f1a78f04b0 100644 --- a/pygmt/tests/test_histogram.py +++ b/pygmt/tests/test_histogram.py @@ -35,25 +35,6 @@ def test_histogram(data): return fig -@pytest.mark.mpl_image_compare(filename="test_histogram_barwidth_baroffset.png") -def test_histogram_barwidth_baroffset(data): - """ - Test plotting a histogram specifying bar_with and bar_offset. - """ - fig = Figure() - fig.histogram( - data=data, - projection="X10c/10c", - region=[0, 9, 0, 6], - series=1, - frame="a", - fill="green", - bar_width=0.5, - bar_offset=0.25, - ) - return fig - - def test_histogram_baroffset(data): """ Test passing bar_offset requires bar_width. From 6910ab30c5ce12a87bfbd6374a27b688ba468b4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= Date: Sat, 27 Dec 2025 11:37:49 +0100 Subject: [PATCH 10/12] Remove DVC file for test image PNG --- .../baseline/test_histogram_barwidth_baroffset.png.dvc | 6 ------ 1 file changed, 6 deletions(-) delete mode 100755 pygmt/tests/baseline/test_histogram_barwidth_baroffset.png.dvc diff --git a/pygmt/tests/baseline/test_histogram_barwidth_baroffset.png.dvc b/pygmt/tests/baseline/test_histogram_barwidth_baroffset.png.dvc deleted file mode 100755 index f238ba1e484..00000000000 --- a/pygmt/tests/baseline/test_histogram_barwidth_baroffset.png.dvc +++ /dev/null @@ -1,6 +0,0 @@ -outs: -- md5: 9bcab5655f53bfef48ffe0c0c9e41273 - size: 10755 - isexec: true - hash: md5 - path: test_histogram_barwidth_baroffset.png From 888dd5c4be2a633061caf4495a4068883ac4ae3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= Date: Sat, 27 Dec 2025 11:42:30 +0100 Subject: [PATCH 11/12] Remove default test image name --- pygmt/tests/test_histogram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_histogram.py b/pygmt/tests/test_histogram.py index 3f1a78f04b0..c655a05d230 100644 --- a/pygmt/tests/test_histogram.py +++ b/pygmt/tests/test_histogram.py @@ -18,7 +18,7 @@ def fixture_data(request): @pytest.mark.benchmark -@pytest.mark.mpl_image_compare(filename="test_histogram.png") +@pytest.mark.mpl_image_compare def test_histogram(data): """ Test plotting a histogram using a sequence of integers from a table. From 03dd11e08e583c2fd52d9b72492bba9f150cb189 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yvonne=20Fr=C3=B6hlich?= Date: Sat, 27 Dec 2025 12:17:13 +0100 Subject: [PATCH 12/12] Add test image name --- pygmt/tests/test_histogram.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pygmt/tests/test_histogram.py b/pygmt/tests/test_histogram.py index c655a05d230..3f1a78f04b0 100644 --- a/pygmt/tests/test_histogram.py +++ b/pygmt/tests/test_histogram.py @@ -18,7 +18,7 @@ def fixture_data(request): @pytest.mark.benchmark -@pytest.mark.mpl_image_compare +@pytest.mark.mpl_image_compare(filename="test_histogram.png") def test_histogram(data): """ Test plotting a histogram using a sequence of integers from a table.