diff --git a/clearml/utilities/plotlympl/mplexporter/exporter.py b/clearml/utilities/plotlympl/mplexporter/exporter.py index 2e73fe50..3a1a8e82 100644 --- a/clearml/utilities/plotlympl/mplexporter/exporter.py +++ b/clearml/utilities/plotlympl/mplexporter/exporter.py @@ -31,8 +31,10 @@ class Exporter(object): def __init__(self, renderer, close_mpl=True): self.close_mpl = close_mpl self.renderer = renderer + self.has_legend = False + self.legend_as_annotation = True - def run(self, fig): + def run(self, fig, show_legend=True): """ Run the exporter on the given figure @@ -40,9 +42,12 @@ class Exporter(object): --------- fig : matplotlib.Figure instance The figure to export + + show_legend: If True, plotly show legend if plt has one, If False add legend as annotations on plot. """ # Calling savefig executes the draw() command, putting elements # in the correct place. + self.legend_as_annotation = not show_legend if fig.canvas is None: canvas = FigureCanvasAgg(fig) # noqa: F841 fig.savefig(io.BytesIO(), format='png', dpi=fig.dpi) @@ -50,6 +55,8 @@ class Exporter(object): import matplotlib.pyplot as plt plt.close(fig) self.crawl_fig(fig) + if show_legend and self.has_legend: + self.renderer.plotly_fig['layout']['showlegend'] = True @staticmethod def process_transform(transform, ax=None, data=None, return_trans=False, @@ -144,10 +151,12 @@ class Exporter(object): legend = ax.get_legend() if legend is not None: - props = utils.get_legend_properties(ax, legend) - with self.renderer.draw_legend(legend=legend, props=props): - if props['visible']: - self.crawl_legend(ax, legend) + self.has_legend = True + if self.legend_as_annotation: + props = utils.get_legend_properties(ax, legend) + with self.renderer.draw_legend(legend=legend, props=props): + if props['visible']: + self.crawl_legend(ax, legend) def crawl_legend(self, ax, legend): """ diff --git a/clearml/utilities/plotlympl/mpltools.py b/clearml/utilities/plotlympl/mpltools.py index 36133219..a55647db 100644 --- a/clearml/utilities/plotlympl/mpltools.py +++ b/clearml/utilities/plotlympl/mpltools.py @@ -8,6 +8,10 @@ import math import warnings import matplotlib.dates +try: + from matplotlib.patches import FancyBboxPatch +except ImportError: + FancyBboxPatch = None def check_bar_match(old_bar, new_bar): @@ -389,6 +393,11 @@ def is_bar(bar_containers, **props): return False +def is_fancy_bbox(**props): + """A test to decide whether a path is a simple FancyBboxPatch.""" + return FancyBboxPatch and isinstance(props.get("mplobj"), FancyBboxPatch) + + def make_bar(**props): """Make an intermediate bar dictionary. diff --git a/clearml/utilities/plotlympl/renderer.py b/clearml/utilities/plotlympl/renderer.py index ab6c5ac7..30d754ee 100644 --- a/clearml/utilities/plotlympl/renderer.py +++ b/clearml/utilities/plotlympl/renderer.py @@ -509,6 +509,8 @@ class PlotlyRenderer(Renderer): is_bar = mpltools.is_bar(self.current_mpl_ax.containers, **props) if is_bar: self.current_bars += [props] + elif mpltools.is_fancy_bbox(**props): + self.current_bars += [props] else: self.msg += " This path isn't a bar, not drawing\n" warnings.warn( @@ -588,8 +590,8 @@ class PlotlyRenderer(Renderer): self.msg += " Text object is linked to 'data' " "coordinates\n" x, y = props["position"] axis_ct = self.axis_ct - xaxis = self.plotly_fig["layout"]["xaxis{0}".format(axis_ct)] - yaxis = self.plotly_fig["layout"]["yaxis{0}".format(axis_ct)] + xaxis = self.plotly_fig["layout"]["xaxis{0}".format(axis_ct or '')] + yaxis = self.plotly_fig["layout"]["yaxis{0}".format(axis_ct or '')] if ( xaxis["range"][0] < x < xaxis["range"][1] and yaxis["range"][0] < y < yaxis["range"][1] @@ -714,7 +716,10 @@ class PlotlyRenderer(Renderer): """ self.msg += " Adding xlabel\n" - axis_key = "xaxis{0}".format(self.axis_ct) + axis_key = "xaxis{0}".format(self.axis_ct or '') + # bugfix: add on last axis, self.axis_ct-1 + if axis_key not in self.plotly_fig["layout"]: + axis_key = "xaxis{0}".format(max(0, self.axis_ct - 1) or '') self.plotly_fig["layout"][axis_key]["title"] = str(props["text"]) titlefont = dict(size=props["style"]["fontsize"], color=props["style"]["color"]) self.plotly_fig["layout"][axis_key]["titlefont"] = titlefont @@ -743,7 +748,10 @@ class PlotlyRenderer(Renderer): """ self.msg += " Adding ylabel\n" - axis_key = "yaxis{0}".format(self.axis_ct) + axis_key = "yaxis{0}".format(self.axis_ct or '') + # bugfix: add on last axis, self.axis_ct-1 + if axis_key not in self.plotly_fig["layout"]: + axis_key = "yaxis{0}".format(max(0, self.axis_ct - 1) or '') self.plotly_fig["layout"][axis_key]["title"] = props["text"] titlefont = dict(size=props["style"]["fontsize"], color=props["style"]["color"]) self.plotly_fig["layout"][axis_key]["titlefont"] = titlefont