From 016a5c2d7197cc61ea69b603bc54e3e209eed02a Mon Sep 17 00:00:00 2001 From: allegroai <> Date: Wed, 19 May 2021 15:24:47 +0300 Subject: [PATCH] Add Logger.matplotlib_force_report_non_interactive() --- clearml/backend_interface/metrics/reporter.py | 5 ++++ clearml/binding/matplotlib_bind.py | 26 ++++++++++++++----- clearml/logger.py | 13 ++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/clearml/backend_interface/metrics/reporter.py b/clearml/backend_interface/metrics/reporter.py index 5830238a..4b200344 100644 --- a/clearml/backend_interface/metrics/reporter.py +++ b/clearml/backend_interface/metrics/reporter.py @@ -839,6 +839,11 @@ class Reporter(InterfaceBase, AbstractContextManager, SetupUploadMixin, AsyncMan ) self._report(ev) + @classmethod + def matplotlib_force_report_non_interactive(cls, force): + from clearml.binding.matplotlib_bind import PatchedMatplotlib + PatchedMatplotlib.force_report_as_image(force=force) + @classmethod def _normalize_name(cls, name): return name diff --git a/clearml/binding/matplotlib_bind.py b/clearml/binding/matplotlib_bind.py index 09bde781..7a3f65df 100644 --- a/clearml/binding/matplotlib_bind.py +++ b/clearml/binding/matplotlib_bind.py @@ -34,6 +34,7 @@ class PatchedMatplotlib: _recursion_guard = {} _matplot_major_version = 0 _matplot_minor_version = 0 + _force_report_as_image = False _logger_started_reporting = False _matplotlib_reported_titles = set() @@ -49,6 +50,16 @@ class PatchedMatplotlib: pass return bypass + @staticmethod + def force_report_as_image(force): + # type: (bool) -> None + """ + Set force_report_as_image. If True all matplotlib are always converted to images + Otherwise we try to convert them into interactive plotly plots. + :param force: True force + """ + PatchedMatplotlib._force_report_as_image = bool(force) + @staticmethod def patch_matplotlib(): # only once @@ -361,18 +372,21 @@ class PatchedMatplotlib: # if auto bind (i.e. plt.show) and plot already displayed explicitly, do nothing. return + if PatchedMatplotlib._force_report_as_image: + force_save_as_image = True + # convert to plotly image = None plotly_dict = None image_format = 'jpeg' fig_dpi = 300 - if force_save_as_image or report_as_debug_sample: + if report_as_debug_sample: + fig_dpi = None + image_format = force_save_as_image \ + if force_save_as_image and isinstance(force_save_as_image, str) else 'jpeg' + elif force_save_as_image: # if this is an image, store as is. - fig_dpi = None if report_as_debug_sample else 300 - force_save_as_image = force_save_as_image \ - if force_save_as_image and isinstance(force_save_as_image, str) else 'png' - if isinstance(force_save_as_image, str): - image_format = force_save_as_image + image_format = force_save_as_image if isinstance(force_save_as_image, str) else 'png' else: image_format = 'svg' # protect with lock, so we support multiple threads using the same renderer diff --git a/clearml/logger.py b/clearml/logger.py index 787dfb1e..91590570 100644 --- a/clearml/logger.py +++ b/clearml/logger.py @@ -1167,6 +1167,19 @@ class Logger(object): """ cls._tensorboard_single_series_per_graph = single_series + @classmethod + def matplotlib_force_report_non_interactive(cls, force): + # type: (bool) -> None + """ + If True all matplotlib are always converted to non interactive static plots (images), appearing in under + the Plots section. If False (default), matplotlib figures are converted into interactive web UI plotly + figures, in case figure conversion fails, it defaults to non-interactive plots. + + :param force: If True all matplotlib figures are converted automatically to non-interactive plots. + """ + from clearml.backend_interface.metrics import Reporter + Reporter.matplotlib_force_report_non_interactive(force=force) + @classmethod def _remove_std_logger(cls): # noinspection PyBroadException