Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 30 additions & 8 deletions plotly/matplotlylib/renderer.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,24 @@
from plotly.matplotlylib import mpltools


def _export_color(color):
"""Export a matplotlib color for use as a plotly 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.
"""
if isinstance(color, str):
return "rgba(0,0,0,0)" if color == "none" else 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):
"""A renderer class inheriting from base for rendering mpl plots in plotly.

Expand Down Expand Up @@ -317,7 +335,7 @@ def draw_bar(self, coll):
yaxis="y{0}".format(self.axis_ct),
opacity=trace[0]["alpha"], # TODO: get all alphas if array?
marker=go.bar.Marker(
color=trace[0]["facecolor"], # TODO: get all
color=_export_color(trace[0]["facecolor"]), # TODO: get all
line=dict(width=trace[0]["edgewidth"]),
),
) # TODO ditto
Expand Down Expand Up @@ -379,9 +397,13 @@ def draw_marked_line(self, **props):
self.msg += "... with just markers\n"
mode = "markers"
if props["linestyle"]:
color = mpltools.merge_color_and_opacity(
props["linestyle"]["color"], props["linestyle"]["alpha"]
)
if props["linestyle"]["color"] == "none":
# a fully transparent line; plotly rejects "none" as a color
color = "rgba(0,0,0,0)"
else:
color = mpltools.merge_color_and_opacity(
props["linestyle"]["color"], props["linestyle"]["alpha"]
)

if props["coordinates"] == "data":
line = go.scatter.Line(
Expand All @@ -401,22 +423,22 @@ def draw_marked_line(self, **props):
if props["coordinates"] == "data":
marker = go.scatter.Marker(
opacity=props["markerstyle"]["alpha"],
color=props["markerstyle"]["facecolor"],
color=_export_color(props["markerstyle"]["facecolor"]),
symbol=mpltools.convert_symbol(props["markerstyle"]["marker"]),
size=props["markerstyle"]["markersize"],
line=dict(
color=props["markerstyle"]["edgecolor"],
color=_export_color(props["markerstyle"]["edgecolor"]),
width=props["markerstyle"]["edgewidth"],
),
)
else:
shape = dict(
opacity=props["markerstyle"]["alpha"],
fillcolor=props["markerstyle"]["facecolor"],
fillcolor=_export_color(props["markerstyle"]["facecolor"]),
symbol=mpltools.convert_symbol(props["markerstyle"]["marker"]),
size=props["markerstyle"]["markersize"],
line=dict(
color=props["markerstyle"]["edgecolor"],
color=_export_color(props["markerstyle"]["edgecolor"]),
width=props["markerstyle"]["edgewidth"],
),
)
Expand Down
9 changes: 9 additions & 0 deletions plotly/matplotlylib/tests/test_renderer.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import numpy as np
import matplotlib.pyplot as plt
import plotly.tools as tls

Expand Down Expand Up @@ -84,3 +85,11 @@ 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_boxplot_converts_with_none_marker_facecolor():
"""Boxplot outlier markers use facecolor 'none', which plotly rejects."""
fig, ax = plt.subplots()
ax.boxplot(np.random.randn(100, 4))
plotly_fig = tls.mpl_to_plotly(fig) # used to raise ValueError
assert len(plotly_fig.data) > 0