diff --git a/plotly/matplotlylib/renderer.py b/plotly/matplotlylib/renderer.py index 7c2340180cc..5c94f3d62bb 100644 --- a/plotly/matplotlylib/renderer.py +++ b/plotly/matplotlylib/renderer.py @@ -9,6 +9,7 @@ import warnings +import matplotlib.patches as mpatches import plotly.graph_objs as go from plotly.matplotlylib.mplexporter import Renderer from plotly.matplotlylib import mpltools @@ -551,6 +552,9 @@ def draw_path(self, **props): is_bar = mpltools.is_bar(self.current_mpl_ax.containers, **props) if is_bar: self.current_bars += [props] + elif isinstance(props["mplobj"], mpatches.StepPatch): + self.msg += " Drawing a step path\n" + self._draw_step_path(props) else: self.msg += " This path isn't a bar, not drawing\n" warnings.warn( @@ -558,6 +562,38 @@ def draw_path(self, **props): "of a bar chart. Ignoring." ) + def _draw_step_path(self, props): + """Draw a matplotlib StepPatch as a step line trace.""" + if props["coordinates"] != "data": + self.msg += " Step path is not in data coordinates, not drawing\n" + return + style = props["style"] + x = [] + y = [] + for x0, y0 in props["data"]: + if not x or x0 != x[-1] or y0 != y[-1]: + x.append(x0) + y.append(y0) + if len(x) < 2: + self.msg += " Step path has fewer than 2 points, not drawing\n" + return + self.plotly_fig.add_trace( + go.Scatter( + x=x, + y=y, + mode="lines", + line=go.scatter.Line( + color=mpltools.merge_color_and_opacity( + style["edgecolor"], style["alpha"] + ), + width=style["edgewidth"], + dash=mpltools.convert_dash(style["dasharray"]), + ), + xaxis="x{0}".format(self.axis_ct), + yaxis="y{0}".format(self.axis_ct), + ) + ) + def draw_text(self, **props): """Create an annotation dict for a text obj. diff --git a/plotly/matplotlylib/tests/test_renderer.py b/plotly/matplotlylib/tests/test_renderer.py index 0d63e4815b9..c7e18f815b2 100644 --- a/plotly/matplotlylib/tests/test_renderer.py +++ b/plotly/matplotlylib/tests/test_renderer.py @@ -84,3 +84,14 @@ def test_multiple_traces_native_legend(): assert plotly_fig.data[0].mode == "lines" assert plotly_fig.data[1].mode == "markers" assert plotly_fig.data[2].mode == "lines+markers" + + +def test_stairs_converts_to_step_line(): + fig, ax = plt.subplots() + ax.stairs([0.0, 1.0, 0.0], [0.0, 1.0, 2.0, 3.0]) + plotly_fig = tls.mpl_to_plotly(fig) + assert len(plotly_fig.data) == 1 + trace = plotly_fig.data[0] + assert trace.mode == "lines" + assert tuple(trace.x) == (0.0, 1.0, 1.0, 2.0, 2.0, 3.0) + assert tuple(trace.y) == (0.0, 0.0, 1.0, 1.0, 0.0, 0.0)