diff --git a/plotly/matplotlylib/renderer.py b/plotly/matplotlylib/renderer.py index a282c67cec..933a609c98 100644 --- a/plotly/matplotlylib/renderer.py +++ b/plotly/matplotlylib/renderer.py @@ -11,6 +11,7 @@ import plotly.graph_objs as go from plotly.matplotlylib.mplexporter import Renderer +from plotly.matplotlylib.mplexporter.utils import export_color from plotly.matplotlylib import mpltools @@ -20,11 +21,15 @@ def _export_color(color): matplotlib uses "none" for fully transparent colors, which plotly does not accept, so transparent colors are exported as transparent black. Colors already exported by the mplexporter (hex or rgba strings) are - passed through unchanged. + passed through unchanged; raw matplotlib colors are converted with the + mplexporter's export_color. """ if isinstance(color, str): return "rgba(0,0,0,0)" if color == "none" else color - return [_export_color(c) for c in color] + if isinstance(color, (list, tuple)) and all(isinstance(c, str) for c in color): + return [_export_color(c) for c in color] + bgcolor = export_color(color) + return "rgba(0,0,0,0)" if bgcolor == "none" else bgcolor class PlotlyRenderer(Renderer): @@ -101,6 +106,9 @@ def open_figure(self, fig, props): autosize=False, hovermode="closest", ) + self.plotly_fig["layout"].paper_bgcolor = _export_color( + fig.patch.get_facecolor() + ) self.mpl_x_bounds, self.mpl_y_bounds = mpltools.get_axes_bounds(fig) margin = go.layout.Margin( l=int(self.mpl_x_bounds[0] * self.plotly_fig["layout"]["width"]), @@ -166,6 +174,8 @@ def open_axes(self, ax, props): ] self.current_bars = [] self.axis_ct += 1 + # update plot background with the axes background from mpl + self.plotly_fig["layout"].plot_bgcolor = _export_color(props["axesbg"]) # set defaults in axes xaxis = go.layout.XAxis( anchor="y{0}".format(self.axis_ct), zeroline=False, ticks="inside" diff --git a/plotly/matplotlylib/tests/test_renderer.py b/plotly/matplotlylib/tests/test_renderer.py index f56d830917..81b7c22271 100644 --- a/plotly/matplotlylib/tests/test_renderer.py +++ b/plotly/matplotlylib/tests/test_renderer.py @@ -199,3 +199,37 @@ def test_filled_path_collection_date_xaxis(): filled = [t for t in plotly_fig.data if t.fill == "toself"] assert len(filled) >= 1 assert all(isinstance(x, str) for x in filled[0].x) + + +def test_background_colors_from_matplotlib_defaults(): + fig, ax = plt.subplots() + ax.plot([0, 1], [0, 1]) + + plotly_fig = tls.mpl_to_plotly(fig) + + assert plotly_fig.layout.plot_bgcolor == "#FFFFFF" + assert plotly_fig.layout.paper_bgcolor == "#FFFFFF" + + +def test_custom_background_colors_are_preserved(): + fig, ax = plt.subplots() + fig.patch.set_facecolor("lightyellow") + ax.set_facecolor("lightgray") + ax.plot([0, 1], [0, 1]) + + plotly_fig = tls.mpl_to_plotly(fig) + + assert plotly_fig.layout.plot_bgcolor == "#D3D3D3" + assert plotly_fig.layout.paper_bgcolor == "#FFFFE0" + + +def test_semitransparent_axes_background_preserved(): + """Axes backgrounds with alpha export as mpl-style rgba strings, which + must be passed through as-is, not re-parsed by export_color.""" + fig, ax = plt.subplots() + ax.set_facecolor((0.1, 0.2, 0.3, 0.4)) + ax.plot([0, 1], [0, 1]) + + plotly_fig = tls.mpl_to_plotly(fig) + + assert plotly_fig.layout.plot_bgcolor == "rgba(26, 51, 76, 0.4)"