From 9c873572ed4f5a1b2a0219eb688f737252fc43f4 Mon Sep 17 00:00:00 2001 From: Roberto Moura Date: Wed, 2 Sep 2026 15:48:28 +0000 Subject: [PATCH 1/4] Convert fill polygons to filled scatter traces --- plotly/matplotlylib/renderer.py | 25 ++++++++++++++++++++++ plotly/matplotlylib/tests/test_renderer.py | 18 ++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/plotly/matplotlylib/renderer.py b/plotly/matplotlylib/renderer.py index be10cd9af9..7c6fb93ffb 100644 --- a/plotly/matplotlylib/renderer.py +++ b/plotly/matplotlylib/renderer.py @@ -786,6 +786,12 @@ def draw_path(self, **props): elif isinstance(props["mplobj"], mpatches.StepPatch): self.msg += " Drawing a step path\n" self._draw_step_path(props) + elif ( + isinstance(props["mplobj"], mpatches.Polygon) + and props["coordinates"] == "data" + ): + self.msg += " Drawing a filled polygon\n" + self._draw_filled_polygon(props) else: self.msg += " This path isn't a bar, not drawing\n" warnings.warn( @@ -848,6 +854,25 @@ def _draw_step_path(self, props): ) ) + def _draw_filled_polygon(self, props): + """Draw a matplotlib Polygon patch as a filled scatter trace.""" + style = props["style"] + verts = props["data"] + facecolor = _export_color(style["facecolor"]) + edgecolor = _export_color(style["edgecolor"]) + self.plotly_fig.add_trace( + go.Scatter( + x=self._convert_x_dates([v[0] for v in verts]), + y=[v[1] for v in verts], + mode="lines", + line=go.scatter.Line(color=edgecolor, width=style["edgewidth"]), + fill="toself", + fillcolor=facecolor, + 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 a355db7dc4..9116d21dd4 100644 --- a/plotly/matplotlylib/tests/test_renderer.py +++ b/plotly/matplotlylib/tests/test_renderer.py @@ -852,6 +852,24 @@ def test_uneven_custom_date_xtickvals_are_converted(): ) +def test_fill_converts(): + """plt.fill polygons convert to filled scatter traces.""" + x = np.linspace(0, 2 * np.pi, 50) + fig, ax = plt.subplots() + ax.fill(x, np.sin(x), "g") + + plotly_fig = tls.mpl_to_plotly(fig) + + assert len(plotly_fig.data) == 1 + trace = plotly_fig.data[0] + assert trace.type == "scatter" + assert trace.fill == "toself" + assert np.allclose(trace.x, x) + assert np.allclose(trace.y, np.sin(x)) + assert trace.fillcolor == "#007F00" + assert trace.line.color == "rgba(0,0,0,0)" + + def test_custom_date_xtickvals_given_as_numbers_are_converted(): """Custom date ticks given as matplotlib date numbers must be converted to date strings.""" From 5d432a39e1a038f363cc074f1e223b62ca3f146e Mon Sep 17 00:00:00 2001 From: Roberto Moura Date: Tue, 6 Oct 2026 08:41:32 +0000 Subject: [PATCH 2/4] Support legend labels on filled polygon traces --- plotly/matplotlylib/renderer.py | 9 ++++++++ plotly/matplotlylib/tests/test_renderer.py | 24 ++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/plotly/matplotlylib/renderer.py b/plotly/matplotlylib/renderer.py index 7c6fb93ffb..738bf5ef45 100644 --- a/plotly/matplotlylib/renderer.py +++ b/plotly/matplotlylib/renderer.py @@ -860,8 +860,17 @@ def _draw_filled_polygon(self, props): verts = props["data"] facecolor = _export_color(style["facecolor"]) edgecolor = _export_color(style["edgecolor"]) + mplobj = props.get("mplobj") + label = mplobj.get_label() if mplobj is not None else None + if not label or (isinstance(label, str) and label.startswith("_")): + label = None + showlegend = False + else: + showlegend = None self.plotly_fig.add_trace( go.Scatter( + name=label, + showlegend=showlegend, x=self._convert_x_dates([v[0] for v in verts]), y=[v[1] for v in verts], mode="lines", diff --git a/plotly/matplotlylib/tests/test_renderer.py b/plotly/matplotlylib/tests/test_renderer.py index 9116d21dd4..25aa435091 100644 --- a/plotly/matplotlylib/tests/test_renderer.py +++ b/plotly/matplotlylib/tests/test_renderer.py @@ -870,6 +870,30 @@ def test_fill_converts(): assert trace.line.color == "rgba(0,0,0,0)" +def test_fill_with_legend_label(): + """plt.fill polygons with labels export their name and show in legend.""" + fig, ax = plt.subplots() + ax.fill([0, 1, 2], [0, 2, 0], "b", label="Shaded Area") + ax.fill([0, 1, 2], [0, 1, 0], "g") + ax.plot([0, 1, 2], [1, 1, 1], "r-", label="Threshold") + ax.legend() + + plotly_fig = tls.mpl_to_plotly(fig) + + assert plotly_fig.layout.showlegend == True + assert len(plotly_fig.data) == 3 + + labeled_fill = next( + t for t in plotly_fig.data if t.fill == "toself" and t.name == "Shaded Area" + ) + assert labeled_fill.showlegend is not False + + unlabeled_fill = next( + t for t in plotly_fig.data if t.fill == "toself" and t.name is None + ) + assert unlabeled_fill.showlegend is False + + def test_custom_date_xtickvals_given_as_numbers_are_converted(): """Custom date ticks given as matplotlib date numbers must be converted to date strings.""" From 57bca9b7d6f835dde8957f6291e7e5f08f9cdb3d Mon Sep 17 00:00:00 2001 From: Roberto Moura Date: Tue, 6 Oct 2026 08:46:11 +0000 Subject: [PATCH 3/4] Add changelog entry --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b45532a79b..9a26bb619a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased +### Added +- Add support for converting matplotlib fill polygons (`plt.fill`) to filled scatter traces in `mpl_to_plotly`, with thanks to @robertoffmoura for the contribution! + ### Fixed - Fix `mpl_to_plotly` tick marker mirroring, axis positioning, and trace visibility for twinned and overlaid subplots (such as `twinx` and `twiny`) [[#5310](https://github.com/plotly/plotly.py/pull/5310)], with thanks to @robertoffmoura for the contribution! - Fix `mpl_to_plotly` losing matplotlib axis line colors by exporting the color of each axis's displayed spine to the plotly x and y axis `linecolor` [[#5311](https://github.com/plotly/plotly.py/pull/5311)], with thanks to @robertoffmoura for the contribution! From 63ee8ff2921628fbdf4362cadfb3a66c27db292f Mon Sep 17 00:00:00 2001 From: Roberto Moura Date: Tue, 6 Oct 2026 09:03:23 +0000 Subject: [PATCH 4/4] Update changelog entry with PR number 5795 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a26bb619a..963109e29e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## Unreleased ### Added -- Add support for converting matplotlib fill polygons (`plt.fill`) to filled scatter traces in `mpl_to_plotly`, with thanks to @robertoffmoura for the contribution! +- Add support for converting matplotlib fill polygons (`plt.fill`) to filled scatter traces in `mpl_to_plotly` [[#5795](https://github.com/plotly/plotly.py/pull/5795)], with thanks to @robertoffmoura for the contribution! ### Fixed - Fix `mpl_to_plotly` tick marker mirroring, axis positioning, and trace visibility for twinned and overlaid subplots (such as `twinx` and `twiny`) [[#5310](https://github.com/plotly/plotly.py/pull/5310)], with thanks to @robertoffmoura for the contribution!