diff --git a/plotly/matplotlylib/renderer.py b/plotly/matplotlylib/renderer.py index 7c2340180cc..13599283863 100644 --- a/plotly/matplotlylib/renderer.py +++ b/plotly/matplotlylib/renderer.py @@ -78,6 +78,10 @@ def open_figure(self, fig, props): height=int(props["figheight"] * props["dpi"]), autosize=False, hovermode="closest", + # plotly.js auto-names unnamed traces "trace N" and shows them + # in the legend; the legend is only enabled when the mpl figure + # actually has one (see open_legend) + showlegend=False, ) self.mpl_x_bounds, self.mpl_y_bounds = mpltools.get_axes_bounds(fig) margin = go.layout.Margin( @@ -421,13 +425,14 @@ def draw_marked_line(self, **props): ), ) if props["coordinates"] == "data": + label = props["label"] + # matplotlib uses "_nolegend_" and auto-generated "_childN" + # labels for artists that must not appear in a legend + if isinstance(label, str) and label.startswith("_"): + label = None marked_line = go.Scatter( mode=mode, - name=( - str(props["label"]) - if isinstance(props["label"], str) - else props["label"] - ), + name=label, x=[xy_pair[0] for xy_pair in props["data"]], y=[xy_pair[1] for xy_pair in props["data"]], xaxis="x{0}".format(self.axis_ct), diff --git a/plotly/matplotlylib/tests/test_renderer.py b/plotly/matplotlylib/tests/test_renderer.py index 0d63e4815b9..74698eaf73c 100644 --- a/plotly/matplotlylib/tests/test_renderer.py +++ b/plotly/matplotlylib/tests/test_renderer.py @@ -84,3 +84,12 @@ 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_no_legend_entries_for_internal_mpl_labels(): + """mpl internal labels (_nolegend_, _childN) must not become legend entries.""" + fig, ax = plt.subplots() + ax.plot([0, 1, 2, 3], [0, 1, 0, 1], "b", [0, 1, 2, 3], [1, 0, 1, 0], "r--") + plotly_fig = tls.mpl_to_plotly(fig) + assert plotly_fig.layout.showlegend == False + assert all(t.name is None for t in plotly_fig.data)