From 6c62eb9fcd0ac6e5c8f7264e7b3b70f1a7bd7ea8 Mon Sep 17 00:00:00 2001 From: Luke J Date: Sat, 31 Oct 2026 17:53:41 +1300 Subject: [PATCH 1/2] Raise an error when a make_subplots span overlaps another subplot --- CHANGELOG.md | 1 + plotly/_subplots.py | 9 +++++++++ tests/test_core/test_subplots/test_make_subplots.py | 10 ++++++++++ 3 files changed, 20 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1632f922032..0eafe92aa2c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Fix `mpl_to_plotly` conversion of matplotlib contour lines and line collections: close contour rings ending with `Z` codes, support dash styles, convert date x-axes, separate disjoint subpaths with `None` separators, hide line collection traces from the legend by default, and group consecutive same-style lines into single traces [[#5770](https://github.com/plotly/plotly.py/pull/5770)], with thanks to @robertoffmoura for the contribution! - Fix `plotly.io.write_images` ignoring `layout.width`/`layout.height` (and the template's) and exporting every figure at the default 700x500 size; it now uses the same width/height priority as `write_image` and `to_image` [[#5784](https://github.com/plotly/plotly.py/pull/5784)], with thanks to @breken-ai for the contribution! - Fix color utilities mutating the list of colors passed to them [[#5836](https://github.com/plotly/plotly.py/pull/5836)], with thanks to @Enesuygurs for the contribution! +- Fix `make_subplots` silently overlapping subplots when a cell covered by a `colspan` or `rowspan` also holds a subplot in `specs`; a `ValueError` naming the cell is now raised instead [[#XXXX](https://github.com/plotly/plotly.py/pull/XXXX)], with thanks to @LukeTheoJohnson for the contribution! ## [7.1.0] - 2026-09-15 diff --git a/plotly/_subplots.py b/plotly/_subplots.py index 7f9b79ebf51..1fa85fd1c93 100644 --- a/plotly/_subplots.py +++ b/plotly/_subplots.py @@ -681,6 +681,15 @@ def _check_hv_spacing(dimsize, spacing, name, dimvarname, dimname): "Some 'rowspan' value is too large for this subplot grid." ) + for rr in range(r, r_spanned + 1): + for cc in range(c, c_spanned + 1): + if (rr, cc) != (r, c) and specs[rr][cc] is not None: + raise ValueError( + f"The subplot at grid position ({r + 1}, {c + 1}) " + f"spans the cell at ({rr + 1}, {cc + 1}), so " + f"specs[{rr}][{cc}] must be None." + ) + # Get x domain using grid and colspan x_s = grid[r][c][0] + spec["l"] diff --git a/tests/test_core/test_subplots/test_make_subplots.py b/tests/test_core/test_subplots/test_make_subplots.py index 52503b0ddef..0bb5b866400 100644 --- a/tests/test_core/test_subplots/test_make_subplots.py +++ b/tests/test_core/test_subplots/test_make_subplots.py @@ -81,6 +81,16 @@ def test_specs_rowspan_too_big(self): with self.assertRaises(Exception): tls.make_subplots(rows=3, specs=[[{}], [None], [{"rowspan": 2}]]) + def test_specs_colspan_overlaps_subplot(self): + with pytest.raises(ValueError, match=r"specs\[0\]\[1\] must be None"): + subplots.make_subplots(cols=3, specs=[[{"colspan": 2}, {}, None]]) + + def test_specs_rowspan_overlaps_subplot(self): + with pytest.raises(ValueError, match=r"specs\[1\]\[0\] must be None"): + subplots.make_subplots( + rows=2, cols=2, specs=[[{"rowspan": 2}, {}], [{}, {}]] + ) + def test_insets_wrong_type(self): with self.assertRaises(Exception): tls.make_subplots(insets="not going to work") From 8133e4c332b1c392220f7d3dd90fafc9cf1d2111 Mon Sep 17 00:00:00 2001 From: Luke J Date: Sat, 31 Oct 2026 22:28:06 +1300 Subject: [PATCH 2/2] Add PR number to changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eafe92aa2c..677b518b5b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Fix `mpl_to_plotly` conversion of matplotlib contour lines and line collections: close contour rings ending with `Z` codes, support dash styles, convert date x-axes, separate disjoint subpaths with `None` separators, hide line collection traces from the legend by default, and group consecutive same-style lines into single traces [[#5770](https://github.com/plotly/plotly.py/pull/5770)], with thanks to @robertoffmoura for the contribution! - Fix `plotly.io.write_images` ignoring `layout.width`/`layout.height` (and the template's) and exporting every figure at the default 700x500 size; it now uses the same width/height priority as `write_image` and `to_image` [[#5784](https://github.com/plotly/plotly.py/pull/5784)], with thanks to @breken-ai for the contribution! - Fix color utilities mutating the list of colors passed to them [[#5836](https://github.com/plotly/plotly.py/pull/5836)], with thanks to @Enesuygurs for the contribution! -- Fix `make_subplots` silently overlapping subplots when a cell covered by a `colspan` or `rowspan` also holds a subplot in `specs`; a `ValueError` naming the cell is now raised instead [[#XXXX](https://github.com/plotly/plotly.py/pull/XXXX)], with thanks to @LukeTheoJohnson for the contribution! +- Fix `make_subplots` silently overlapping subplots when a cell covered by a `colspan` or `rowspan` also holds a subplot in `specs`; a `ValueError` naming the cell is now raised instead [[#5858](https://github.com/plotly/plotly.py/pull/5858)], with thanks to @LukeTheoJohnson for the contribution! ## [7.1.0] - 2026-09-15