From 0449a92f8db1e3e3a930b8c7f46d501b38a16979 Mon Sep 17 00:00:00 2001 From: Bhaskar Gurram Date: Sun, 11 Oct 2026 15:58:41 +0000 Subject: [PATCH] Add custom_data argument to px.histogram Every other Plotly Express function that builds a trace from rows of the data frame accepts custom_data, but histogram() never did. The core already handles the argument generically (it is how hover_data columns reach customdata for the other functions), so adding the parameter is enough: the selected columns are stored per input row in the trace's customdata and are available in the events the figure emits, which is what Dash callbacks and selection handlers need. Closes #3859 --- CHANGELOG.md | 3 +++ plotly/express/_chart_types.py | 1 + tests/test_optional/test_px/test_px.py | 22 ++++++++++++++++++++++ 3 files changed, 26 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c92c3ea6d64..d82248011d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Added +- Add the `custom_data` argument to `px.histogram`, so extra columns can be attached to histogram traces for use in Dash callbacks and selection events, as in the other Plotly Express functions [[#3859](https://github.com/plotly/plotly.py/issues/3859)] + ### Fixed - Fix `mpl_to_plotly` tick marker mirroring, axis positioning, and trace visibility for twinned and overlaid subplots (such as `twinx` and `twiny`) [[#5310](https://github.com/plotly/plotly.py/pull/5310)], with thanks to @robertoffmoura for the contribution! - Fix `mpl_to_plotly` losing matplotlib axis line colors by exporting the color of each axis's displayed spine to the plotly x and y axis `linecolor` [[#5311](https://github.com/plotly/plotly.py/pull/5311)], with thanks to @robertoffmoura for the contribution! diff --git a/plotly/express/_chart_types.py b/plotly/express/_chart_types.py index f78a257cabb..d9115745cc4 100644 --- a/plotly/express/_chart_types.py +++ b/plotly/express/_chart_types.py @@ -462,6 +462,7 @@ def histogram( facet_col_spacing=None, hover_name=None, hover_data=None, + custom_data=None, animation_frame=None, animation_group=None, category_orders=None, diff --git a/tests/test_optional/test_px/test_px.py b/tests/test_optional/test_px/test_px.py index d4773de66f8..88f20b6feda 100644 --- a/tests/test_optional/test_px/test_px.py +++ b/tests/test_optional/test_px/test_px.py @@ -68,6 +68,28 @@ def test_custom_data_scatter(backend): ) +def test_custom_data_histogram(backend): + tips = nw.from_native(px.data.tips(return_type=backend)) + # No custom data + fig = px.histogram(tips.to_native(), x="total_bill") + assert fig.data[0].customdata is None + # Custom data is carried per row of the input, not per bin + fig = px.histogram(tips.to_native(), x="total_bill", custom_data=["tip", "day"]) + assert fig.data[0].customdata.shape == (len(tips), 2) + assert np.all(fig.data[0].customdata[:, 0] == tips.get_column("tip").to_numpy()) + assert np.all(fig.data[0].customdata[:, 1] == tips.get_column("day").to_numpy()) + # Bins are aggregates, so custom data does not show up in the hover label + assert fig.data[0].hovertemplate == "total_bill=%{x}
count=%{y}" + # Each colored trace carries the custom data of its own rows + fig = px.histogram( + tips.to_native(), x="total_bill", color="sex", custom_data=["tip"] + ) + for trace in fig.data: + group = tips.filter(nw.col("sex") == trace.name) + assert trace.customdata.shape == (len(group), 1) + assert np.all(trace.customdata[:, 0] == group.get_column("tip").to_numpy()) + + def test_labels(backend): tips = nw.from_native(px.data.tips(return_type=backend)) fig = px.scatter(