diff --git a/CHANGELOG.md b/CHANGELOG.md index f281cbf453..3bbad0d2c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Fixed +- Raise a clear `ValueError` when an unsupported marginal plot type is passed to Plotly Express, instead of failing later with a cryptic `'NoneType' object has no attribute 'constructor'` message [[#5625](https://github.com/plotly/plotly.py/pull/5625)] + ## [6.8.0] - 2026-06-03 diff --git a/plotly/express/_core.py b/plotly/express/_core.py index bcd5a40c03..3b8ff3e693 100644 --- a/plotly/express/_core.py +++ b/plotly/express/_core.py @@ -971,6 +971,12 @@ def make_trace_spec(args, constructor, attrs, trace_patch): ), marginal=letter, ) + else: + raise ValueError( + "Invalid value '%s' for `marginal_%s`. Supported marginal " + "plot types are: 'rug', 'box', 'violin', 'histogram'." + % (args["marginal_" + letter], letter) + ) if "color" in attrs or "color" not in args: if "marker" not in trace_spec.trace_patch: trace_spec.trace_patch["marker"] = dict() diff --git a/tests/test_optional/test_px/test_marginals.py b/tests/test_optional/test_px/test_marginals.py index 9a7ec64d12..40d3019f2d 100644 --- a/tests/test_optional/test_px/test_marginals.py +++ b/tests/test_optional/test_px/test_marginals.py @@ -24,3 +24,15 @@ def test_single_marginals(backend, px_fn, marginal, orientation): df, x="total_bill", y="total_bill", marginal=marginal, orientation=orientation ) assert len(fig.data) == 1 + (marginal is not None) + + +def test_unsupported_marginal_raises_clear_error(): # issue 4654 + # An unsupported marginal type used to fail deep inside make_figure with a + # cryptic "'NoneType' object has no attribute 'constructor'". It should + # instead raise a clear error naming the supported values. + with pytest.raises(ValueError, match="Supported marginal plot types"): + px.scatter(x=[1, 2, 3], y=[2, 3, 4], marginal_x="density") + with pytest.raises(ValueError, match="Supported marginal plot types"): + px.scatter(x=[1, 2, 3], y=[2, 3, 4], marginal_y="density") + with pytest.raises(ValueError, match="Supported marginal plot types"): + px.histogram(x=[1, 2, 3], marginal="density")