Skip to content

Commit f9f0bce

Browse files
committed
Raise a clear error for unsupported marginal plot types
Closes #4654. Passing an unsupported value to marginal_x, marginal_y or marginal in Plotly Express (for example marginal_x="density") left trace_spec as None in make_trace_spec, which later failed deep inside make_figure with a confusing "'NoneType' object has no attribute 'constructor'". make_trace_spec now raises a ValueError naming the offending value and listing the supported marginal plot types: rug, box, violin and histogram. The singular `marginal` argument is normalised to marginal_x or marginal_y before this point, so the single check covers all three parameters. Adds a regression test in tests/test_optional/test_px/test_marginals.py.
1 parent 2a91b77 commit f9f0bce

3 files changed

Lines changed: 21 additions & 0 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
44

55
## Unreleased
66

7+
### Fixed
8+
- 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 [[#4654](https://github.com/plotly/plotly.py/issues/4654)]
9+
710

811
## [6.8.0] - 2026-06-03
912

plotly/express/_core.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,12 @@ def make_trace_spec(args, constructor, attrs, trace_patch):
971971
),
972972
marginal=letter,
973973
)
974+
else:
975+
raise ValueError(
976+
"Invalid value '%s' for `marginal_%s`. Supported marginal "
977+
"plot types are: 'rug', 'box', 'violin', 'histogram'."
978+
% (args["marginal_" + letter], letter)
979+
)
974980
if "color" in attrs or "color" not in args:
975981
if "marker" not in trace_spec.trace_patch:
976982
trace_spec.trace_patch["marker"] = dict()

tests/test_optional/test_px/test_marginals.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,15 @@ def test_single_marginals(backend, px_fn, marginal, orientation):
2424
df, x="total_bill", y="total_bill", marginal=marginal, orientation=orientation
2525
)
2626
assert len(fig.data) == 1 + (marginal is not None)
27+
28+
29+
def test_unsupported_marginal_raises_clear_error(): # issue 4654
30+
# An unsupported marginal type used to fail deep inside make_figure with a
31+
# cryptic "'NoneType' object has no attribute 'constructor'". It should
32+
# instead raise a clear error naming the supported values.
33+
with pytest.raises(ValueError, match="Supported marginal plot types"):
34+
px.scatter(x=[1, 2, 3], y=[2, 3, 4], marginal_x="density")
35+
with pytest.raises(ValueError, match="Supported marginal plot types"):
36+
px.scatter(x=[1, 2, 3], y=[2, 3, 4], marginal_y="density")
37+
with pytest.raises(ValueError, match="Supported marginal plot types"):
38+
px.histogram(x=[1, 2, 3], marginal="density")

0 commit comments

Comments
 (0)