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

Handle large collections of subplots without validation error #1091

Merged
merged 2 commits into from
Aug 5, 2018
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
6 changes: 3 additions & 3 deletions plotly/matplotlylib/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -530,7 +530,7 @@ def draw_text(self, **props):
if not align:
align = props['style']['halign'] # mpl default
if 'annotations' not in self.plotly_fig['layout']:
self.plotly_fig['layout']['annotations'] = go.Annotations()
self.plotly_fig['layout']['annotations'] = []
if props['text_type'] == 'xlabel':
self.msg += " Text object is an xlabel\n"
self.draw_xlabel(**props)
Expand Down Expand Up @@ -576,7 +576,7 @@ def draw_text(self, **props):
yref = 'paper'
xanchor = props['style']['halign'] # no difference here!
yanchor = mpltools.convert_va(props['style']['valign'])
annotation = go.Annotation(
annotation = go.layout.Annotation(
text=(str(props['text']) if
isinstance(props['text'], six.string_types) else
props['text']),
Expand Down Expand Up @@ -631,7 +631,7 @@ def draw_title(self, **props):
'position'])
x, y = mpltools.display_to_paper(x_px, y_px,
self.plotly_fig['layout'])
annotation = go.Annotation(
annotation = go.layout.Annotation(
text=props['text'],
font=go.layout.annotation.Font(
color=props['style']['color'],
Expand Down
27 changes: 27 additions & 0 deletions plotly/tests/test_core/test_tools/test_make_subplots.py
Original file line number Diff line number Diff line change
Expand Up @@ -2128,3 +2128,30 @@ def test_subplot_titles_insets(self):
fig = tls.make_subplots(insets=[{'cell': (1, 1), 'l': 0.7, 'b': 0.3}],
subplot_titles=("", 'Inset'))
self.assertEqual(fig, expected)

def test_large_columns_no_errors(self):
"""
Test that creating subplots with a large number of columns, and
zero vertical spacing doesn't result in domain values that are out
of range.

Here is the error that was reported in GH1031

ValueError:
Invalid value of type 'builtins.float' received for the
'domain[1]' property of layout.yaxis
Received value: 1.0000000000000007

The 'domain[1]' property is a number and may be specified as:
- An int or float in the interval [0, 1]

"""
v_space = 0.0

# 2D
fig = tls.make_subplots(100, 1, vertical_spacing=v_space)

# 3D
fig = tls.make_subplots(100, 1,
vertical_spacing=v_space,
specs=[[{'is_3d': True}] for _ in range(100)])
16 changes: 11 additions & 5 deletions plotly/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -568,9 +568,9 @@ def get_subplots(rows=1, columns=1, print_grid=False, **kwargs):
y_start = (plot_height + vertical_spacing) * rrr
y_end = y_start + plot_height

xaxis = graph_objs.XAxis(domain=[x_start, x_end], anchor=x_anchor)
xaxis = dict(domain=[x_start, x_end], anchor=x_anchor)
fig['layout'][xaxis_name] = xaxis
yaxis = graph_objs.YAxis(domain=[y_start, y_end], anchor=y_anchor)
yaxis = dict(domain=[y_start, y_end], anchor=y_anchor)
fig['layout'][yaxis_name] = yaxis
plot_num += 1

Expand Down Expand Up @@ -1080,7 +1080,11 @@ def _get_anchors(r, c, x_cnt, y_cnt, shared_xaxes, shared_yaxes):
# Function pasting x/y domains in layout object (2d case)
def _add_domain(layout, x_or_y, label, domain, anchor, position):
name = label[0] + 'axis' + label[1:]
axis = {'domain': domain}

# Clamp domain elements between [0, 1].
# This is only needed to combat numerical precision errors
# See GH1031
axis = {'domain': [max(0.0, domain[0]), min(1.0, domain[1])]}
if anchor:
axis['anchor'] = anchor
if isinstance(position, float):
Expand All @@ -1090,7 +1094,9 @@ def _add_domain(layout, x_or_y, label, domain, anchor, position):

# Function pasting x/y domains in layout object (3d case)
def _add_domain_is_3d(layout, s_label, x_domain, y_domain):
scene = graph_objs.Scene(domain={'x': x_domain, 'y': y_domain})
scene = dict(
domain={'x': [max(0.0, x_domain[0]), min(1.0, x_domain[1])],
'y': [max(0.0, y_domain[0]), min(1.0, y_domain[1])]})
layout[s_label] = scene

x_cnt = y_cnt = s_cnt = 1 # subplot axis/scene counters
Expand Down Expand Up @@ -1339,7 +1345,7 @@ def _pad(s, cell_len=cell_len):
'yref': 'paper',
'text': subplot_titles[index],
'showarrow': False,
'font': graph_objs.Font(size=16),
'font': dict(size=16),
'xanchor': 'center',
'yanchor': 'bottom'
})
Expand Down