diff --git a/plotly/matplotlylib/renderer.py b/plotly/matplotlylib/renderer.py index 315cfc51a12..aca990da93b 100644 --- a/plotly/matplotlylib/renderer.py +++ b/plotly/matplotlylib/renderer.py @@ -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) @@ -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']), @@ -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'], diff --git a/plotly/tests/test_core/test_tools/test_make_subplots.py b/plotly/tests/test_core/test_tools/test_make_subplots.py index 903ca36968b..9db24b3cd69 100644 --- a/plotly/tests/test_core/test_tools/test_make_subplots.py +++ b/plotly/tests/test_core/test_tools/test_make_subplots.py @@ -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)]) diff --git a/plotly/tools.py b/plotly/tools.py index dffd60c9b66..8e10c91f32a 100644 --- a/plotly/tools.py +++ b/plotly/tools.py @@ -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 @@ -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): @@ -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 @@ -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' })