Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding some rounding and error messaging for subplots #4153

Merged
merged 8 commits into from
May 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Fixed
- Fixed another compatibility issue with Pandas 2.0, just affecting `px.*(line_close=True)` [[#4190](https://github.com/plotly/plotly.py/pull/4190)]
- 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

## [5.14.1] - 2023-04-05

Expand Down
47 changes: 40 additions & 7 deletions packages/python/plotly/plotly/_subplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -671,7 +671,6 @@ def _check_hv_spacing(dimsize, spacing, name, dimvarname, dimname):
# Loop through specs -- (r, c) <-> (row, col)
for r, spec_row in enumerate(specs):
for c, spec in enumerate(spec_row):

if spec is None: # skip over None cells
continue

Expand Down Expand Up @@ -702,6 +701,46 @@ def _check_hv_spacing(dimsize, spacing, name, dimvarname, dimname):
else:
y_s = grid[r_spanned][c][1] + spec["b"]
y_e = grid[r][c][1] + heights[-1 - r] - spec["t"]

if y_s < 0.0:
# round for values very close to one
# handles some floating point errors
if y_s > -0.01:
y_s = 0.0
else:
raise Exception(
"A combination of the 'b' values, heights, and "
"number of subplots too large for this subplot grid."
)
if y_s > 1.0:
# round for values very close to one
# handles some floating point errors
if y_s < 1.01:
y_s = 1.0
else:
raise Exception(
"A combination of the 'b' values, heights, and "
"number of subplots too large for this subplot grid."
)

if y_e < 0.0:
if y_e > -0.01:
y_e = 0.0
else:
raise Exception(
"A combination of the 't' values, heights, and "
"number of subplots too large for this subplot grid."
)

if y_e > 1.0:
if y_e < 1.01:
y_e = 1.0
else:
raise Exception(
"A combination of the 't' values, heights, and "
"number of subplots too large for this subplot grid."
)

y_domain = [y_s, y_e]

list_of_domains.append(x_domain)
Expand All @@ -726,7 +765,6 @@ def _check_hv_spacing(dimsize, spacing, name, dimvarname, dimname):
insets_ref = [None for inset in range(len(insets))] if insets else None
if insets:
for i_inset, inset in enumerate(insets):

r = inset["cell"][0] - 1
c = inset["cell"][1] - 1

Expand Down Expand Up @@ -1052,7 +1090,6 @@ def _subplot_type_for_trace_type(trace_type):


def _validate_coerce_subplot_type(subplot_type):

# Lowercase subplot_type
orig_subplot_type = subplot_type
subplot_type = subplot_type.lower()
Expand Down Expand Up @@ -1200,7 +1237,6 @@ def _build_subplot_title_annotations(


def _build_grid_str(specs, grid_ref, insets, insets_ref, row_seq):

# Compute rows and columns
rows = len(specs)
cols = len(specs[0])
Expand Down Expand Up @@ -1257,7 +1293,6 @@ def _pad(s, cell_len=cell_len):
# Loop through specs, fill in _tmp
for r, spec_row in enumerate(specs):
for c, spec in enumerate(spec_row):

ref = grid_ref[r][c]
if ref is None:
if _tmp[r][c] == "":
Expand Down Expand Up @@ -1339,7 +1374,6 @@ def _pad(s, cell_len=cell_len):


def _set_trace_grid_reference(trace, layout, grid_ref, row, col, secondary_y=False):

if row <= 0:
raise Exception(
"Row value is out of range. " "Note: the starting cell is (1, 1)"
Expand Down Expand Up @@ -1461,7 +1495,6 @@ def _get_grid_subplot(fig, row, col, secondary_y=False):


def _get_subplot_ref_for_trace(trace):

if "domain" in trace:
return SubplotRef(
subplot_type="domain",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,22 @@ def test_specs_padding(self):
)
self.assertEqual(fig.to_plotly_json(), expected.to_plotly_json())

def test_specs_rounding_rounds_down(self):
n_subplots = 8
padding_size = 0.2

specs = []
for _ in range(n_subplots):
specs.append([{"b": padding_size / 2.0, "t": padding_size / 2.0}])

fig = subplots.make_subplots(rows=n_subplots, specs=specs)
self.assertTrue(
all(
fig.layout[f"yaxis{i if i > 1 else ''}"]["domain"][0] <= 1.0
for i in range(1, n_subplots + 1)
)
)

def test_specs_padding_bottom_left(self):
expected = Figure(
data=Data(),
Expand Down Expand Up @@ -1592,7 +1608,6 @@ def test_large_columns_no_errors(self):
)

def test_row_width_and_column_width(self):

expected = Figure(
{
"data": [],
Expand Down Expand Up @@ -1680,7 +1695,6 @@ def test_row_width_and_column_width(self):
self.assertEqual(fig.to_plotly_json(), expected.to_plotly_json())

def test_row_width_and_shared_yaxes(self):

expected = Figure(
{
"data": [],
Expand Down