Skip to content

Commit 59ffd90

Browse files
authored
Merge pull request #4153 from stephenpardy/handle_spacing_with_spec
Adding some rounding and error messaging for subplots
2 parents 5b65329 + bf7f6de commit 59ffd90

File tree

3 files changed

+57
-9
lines changed

3 files changed

+57
-9
lines changed

Diff for: CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
66

77
### Fixed
88
- Fixed another compatibility issue with Pandas 2.0, just affecting `px.*(line_close=True)` [[#4190](https://github.com/plotly/plotly.py/pull/4190)]
9+
- Added some rounding to the `make_subplots` function to handle situations where the user-input specs cause the domain to exceed 1 by small amounts https://github.com/plotly/plotly.py/pull/4153
910

1011
## [5.14.1] - 2023-04-05
1112

Diff for: packages/python/plotly/plotly/_subplots.py

+40-7
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,6 @@ def _check_hv_spacing(dimsize, spacing, name, dimvarname, dimname):
671671
# Loop through specs -- (r, c) <-> (row, col)
672672
for r, spec_row in enumerate(specs):
673673
for c, spec in enumerate(spec_row):
674-
675674
if spec is None: # skip over None cells
676675
continue
677676

@@ -702,6 +701,46 @@ def _check_hv_spacing(dimsize, spacing, name, dimvarname, dimname):
702701
else:
703702
y_s = grid[r_spanned][c][1] + spec["b"]
704703
y_e = grid[r][c][1] + heights[-1 - r] - spec["t"]
704+
705+
if y_s < 0.0:
706+
# round for values very close to one
707+
# handles some floating point errors
708+
if y_s > -0.01:
709+
y_s = 0.0
710+
else:
711+
raise Exception(
712+
"A combination of the 'b' values, heights, and "
713+
"number of subplots too large for this subplot grid."
714+
)
715+
if y_s > 1.0:
716+
# round for values very close to one
717+
# handles some floating point errors
718+
if y_s < 1.01:
719+
y_s = 1.0
720+
else:
721+
raise Exception(
722+
"A combination of the 'b' values, heights, and "
723+
"number of subplots too large for this subplot grid."
724+
)
725+
726+
if y_e < 0.0:
727+
if y_e > -0.01:
728+
y_e = 0.0
729+
else:
730+
raise Exception(
731+
"A combination of the 't' values, heights, and "
732+
"number of subplots too large for this subplot grid."
733+
)
734+
735+
if y_e > 1.0:
736+
if y_e < 1.01:
737+
y_e = 1.0
738+
else:
739+
raise Exception(
740+
"A combination of the 't' values, heights, and "
741+
"number of subplots too large for this subplot grid."
742+
)
743+
705744
y_domain = [y_s, y_e]
706745

707746
list_of_domains.append(x_domain)
@@ -726,7 +765,6 @@ def _check_hv_spacing(dimsize, spacing, name, dimvarname, dimname):
726765
insets_ref = [None for inset in range(len(insets))] if insets else None
727766
if insets:
728767
for i_inset, inset in enumerate(insets):
729-
730768
r = inset["cell"][0] - 1
731769
c = inset["cell"][1] - 1
732770

@@ -1052,7 +1090,6 @@ def _subplot_type_for_trace_type(trace_type):
10521090

10531091

10541092
def _validate_coerce_subplot_type(subplot_type):
1055-
10561093
# Lowercase subplot_type
10571094
orig_subplot_type = subplot_type
10581095
subplot_type = subplot_type.lower()
@@ -1200,7 +1237,6 @@ def _build_subplot_title_annotations(
12001237

12011238

12021239
def _build_grid_str(specs, grid_ref, insets, insets_ref, row_seq):
1203-
12041240
# Compute rows and columns
12051241
rows = len(specs)
12061242
cols = len(specs[0])
@@ -1257,7 +1293,6 @@ def _pad(s, cell_len=cell_len):
12571293
# Loop through specs, fill in _tmp
12581294
for r, spec_row in enumerate(specs):
12591295
for c, spec in enumerate(spec_row):
1260-
12611296
ref = grid_ref[r][c]
12621297
if ref is None:
12631298
if _tmp[r][c] == "":
@@ -1339,7 +1374,6 @@ def _pad(s, cell_len=cell_len):
13391374

13401375

13411376
def _set_trace_grid_reference(trace, layout, grid_ref, row, col, secondary_y=False):
1342-
13431377
if row <= 0:
13441378
raise Exception(
13451379
"Row value is out of range. " "Note: the starting cell is (1, 1)"
@@ -1461,7 +1495,6 @@ def _get_grid_subplot(fig, row, col, secondary_y=False):
14611495

14621496

14631497
def _get_subplot_ref_for_trace(trace):
1464-
14651498
if "domain" in trace:
14661499
return SubplotRef(
14671500
subplot_type="domain",

Diff for: packages/python/plotly/plotly/tests/test_core/test_subplots/test_make_subplots.py

+16-2
Original file line numberDiff line numberDiff line change
@@ -660,6 +660,22 @@ def test_specs_padding(self):
660660
)
661661
self.assertEqual(fig.to_plotly_json(), expected.to_plotly_json())
662662

663+
def test_specs_rounding_rounds_down(self):
664+
n_subplots = 8
665+
padding_size = 0.2
666+
667+
specs = []
668+
for _ in range(n_subplots):
669+
specs.append([{"b": padding_size / 2.0, "t": padding_size / 2.0}])
670+
671+
fig = subplots.make_subplots(rows=n_subplots, specs=specs)
672+
self.assertTrue(
673+
all(
674+
fig.layout[f"yaxis{i if i > 1 else ''}"]["domain"][0] <= 1.0
675+
for i in range(1, n_subplots + 1)
676+
)
677+
)
678+
663679
def test_specs_padding_bottom_left(self):
664680
expected = Figure(
665681
data=Data(),
@@ -1592,7 +1608,6 @@ def test_large_columns_no_errors(self):
15921608
)
15931609

15941610
def test_row_width_and_column_width(self):
1595-
15961611
expected = Figure(
15971612
{
15981613
"data": [],
@@ -1680,7 +1695,6 @@ def test_row_width_and_column_width(self):
16801695
self.assertEqual(fig.to_plotly_json(), expected.to_plotly_json())
16811696

16821697
def test_row_width_and_shared_yaxes(self):
1683-
16841698
expected = Figure(
16851699
{
16861700
"data": [],

0 commit comments

Comments
 (0)