From 9793ffb73e9a88cd236b8749dde0d17a6a449cf0 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 30 Oct 2020 19:33:01 -0400 Subject: [PATCH 1/4] FIX: allow Manager classes to take string num The docstring in ManagerBase claims that *num* can be str or int, however ever backend used int-specific formatting so this was not actually true. Fixed the backends rather than fixing the docstring (because setting the window title on Manager init is useful and implicitly supported through some special-casing in `plt.figure`). --- lib/matplotlib/backends/_backend_tk.py | 6 +++++- lib/matplotlib/backends/backend_gtk3.py | 6 +++++- lib/matplotlib/backends/backend_macosx.py | 5 ++++- lib/matplotlib/backends/backend_qt5.py | 7 +++++-- lib/matplotlib/backends/backend_wx.py | 6 +++++- 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/matplotlib/backends/_backend_tk.py b/lib/matplotlib/backends/_backend_tk.py index 69b57fc15d2a..cf422e87eac1 100644 --- a/lib/matplotlib/backends/_backend_tk.py +++ b/lib/matplotlib/backends/_backend_tk.py @@ -348,7 +348,11 @@ def __init__(self, canvas, num, window): super().__init__(canvas, num) self.window = window self.window.withdraw() - self.set_window_title("Figure %d" % num) + if isinstance(num, str): + title = num + else: + title = f"Figure {num}" + self.set_window_title(title) # packing toolbar first, because if space is getting low, last packed # widget is getting shrunk first (-> the canvas) self.toolbar = self._get_toolbar() diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index 7587004fc685..35ab2aff2b40 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -316,7 +316,11 @@ def __init__(self, canvas, num): self.window = Gtk.Window() self.window.set_wmclass("matplotlib", "Matplotlib") - self.set_window_title("Figure %d" % num) + if isinstance(num, str): + title = num + else: + title = f"Figure {num}" + self.set_window_title(title) try: self.window.set_icon_from_file(window_icon) except Exception: diff --git a/lib/matplotlib/backends/backend_macosx.py b/lib/matplotlib/backends/backend_macosx.py index ea02d7cca484..cf669f5a9b1a 100644 --- a/lib/matplotlib/backends/backend_macosx.py +++ b/lib/matplotlib/backends/backend_macosx.py @@ -88,7 +88,10 @@ class FigureManagerMac(_macosx.FigureManager, FigureManagerBase): """ def __init__(self, canvas, num): FigureManagerBase.__init__(self, canvas, num) - title = "Figure %d" % num + if isinstance(num, str): + title = num + else: + title = f"Figure {num}" _macosx.FigureManager.__init__(self, canvas, title) if mpl.rcParams['toolbar'] == 'toolbar2': self.toolbar = NavigationToolbar2Mac(canvas) diff --git a/lib/matplotlib/backends/backend_qt5.py b/lib/matplotlib/backends/backend_qt5.py index 162af99f0efa..97392793d2cb 100644 --- a/lib/matplotlib/backends/backend_qt5.py +++ b/lib/matplotlib/backends/backend_qt5.py @@ -534,8 +534,11 @@ def __init__(self, canvas, num): self.window = MainWindow() self.window.closing.connect(canvas.close_event) self.window.closing.connect(self._widgetclosed) - - self.window.setWindowTitle("Figure %d" % num) + if isinstance(num, str): + title = num + else: + title = f"Figure {num}" + self.window.setWindowTitle(title) image = str(cbook._get_data_path('images/matplotlib.svg')) self.window.setWindowIcon(QtGui.QIcon(image)) diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 8d2083d555e5..8f7bb8ee157c 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -902,7 +902,11 @@ def __init__(self, num, fig): pos = wx.DefaultPosition else: pos = wx.Point(20, 20) - super().__init__(parent=None, id=-1, pos=pos, title="Figure %d" % num) + if isinstance(num, str): + title = num + else: + title = f"Figure {num}" + super().__init__(parent=None, id=-1, pos=pos, title=title) # Frame will be sized later by the Fit method _log.debug("%s - __init__()", type(self)) self.num = num From d969c8e7f6a16b0dfe6e3501d566389d24df6f31 Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 30 Oct 2020 19:37:49 -0400 Subject: [PATCH 2/4] FIX: make FigureManagerWebAgg.set_title "stick" The previous code only sets the title once, on refresh we would fall back to using the result of `fig.get_label()` if in is not the empty string or f'Figure {num}'. --- lib/matplotlib/backends/backend_webagg_core.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/backends/backend_webagg_core.py b/lib/matplotlib/backends/backend_webagg_core.py index d8016e537563..d6d7d8b90b92 100644 --- a/lib/matplotlib/backends/backend_webagg_core.py +++ b/lib/matplotlib/backends/backend_webagg_core.py @@ -298,7 +298,7 @@ def handle_toolbar_button(self, event): def handle_refresh(self, event): figure_label = self.figure.get_label() if not figure_label: - figure_label = "Figure {0}".format(self.manager.num) + figure_label = self._title self.send_event('figure_label', label=figure_label) self._force_full = True if self.toolbar: @@ -410,7 +410,10 @@ class FigureManagerWebAgg(backend_bases.FigureManagerBase): def __init__(self, canvas, num): super().__init__(canvas, num) - + if isinstance(num, str): + self._title = num + else: + self._title = f"Figure {num}" self.web_sockets = set() self.toolbar = self._get_toolbar(canvas) @@ -429,6 +432,7 @@ def resize(self, w, h, forward=True): forward=forward) def set_window_title(self, title): + self._title = title self._send_event('figure_label', label=title) # The following methods are specific to FigureManagerWebAgg From 7dd08a8f7dfd9575ec9c0605702c235dc7b49e0d Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Fri, 30 Oct 2020 20:10:44 -0400 Subject: [PATCH 3/4] ENH: new backend function to fabricate a fully operational figure --- lib/matplotlib/backend_bases.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 7f2ab50a56b2..98d479b6d563 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -3537,6 +3537,38 @@ def new_figure_manager_given_figure(cls, num, figure): manager = cls.FigureManager(canvas, num) return manager + @classmethod + def new_figure(cls, label='Matplotlib Figure', *, auto_redraw=True): + """ + Create a new window with a Figure and toolbar + + Parameters + ---------- + label : str + Use for the window title and figure label. + + auto_redraw : bool + If the figure should automatically re-draw when stale. + """ + manager = cls.new_figure_manager(label) + manager.canvas.figure.set_label(label) + + def redraw(fig, val): + canvas = fig.canvas + if val and not canvas.is_saving() and not canvas._is_idle_drawing: + # Some artists can mark themselves as stale in the + # middle of drawing (e.g. axes position & tick labels + # being computed at draw time), but this shouldn't + # trigger a redraw because the current redraw will + # already take them into account. + with fig.canvas._idle_draw_cntx(): + fig.canvas.draw_idle() + + if auto_redraw: + manager.canvas.figure.stale_callback = redraw + + return manager.canvas.figure + @classmethod def draw_if_interactive(cls): if cls.trigger_manager_draw is not None and is_interactive(): @@ -3590,6 +3622,7 @@ def export(cls): "FigureManager", "new_figure_manager", "new_figure_manager_given_figure", + "new_figure", "draw_if_interactive", "show", ]: From 624d96f3459ab12aea324235a7295ea659e1f53f Mon Sep 17 00:00:00 2001 From: Thomas A Caswell Date: Sat, 31 Oct 2020 17:08:11 -0400 Subject: [PATCH 4/4] ENH: add auto-show flag --- lib/matplotlib/backend_bases.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 98d479b6d563..027baa36b68c 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -3538,7 +3538,8 @@ def new_figure_manager_given_figure(cls, num, figure): return manager @classmethod - def new_figure(cls, label='Matplotlib Figure', *, auto_redraw=True): + def new_figure(cls, label='Matplotlib Figure', *, + auto_redraw=True, auto_show=True): """ Create a new window with a Figure and toolbar @@ -3549,6 +3550,9 @@ def new_figure(cls, label='Matplotlib Figure', *, auto_redraw=True): auto_redraw : bool If the figure should automatically re-draw when stale. + + auto_show : bool + If the GUI window should be shown on creation. """ manager = cls.new_figure_manager(label) manager.canvas.figure.set_label(label) @@ -3566,7 +3570,8 @@ def redraw(fig, val): if auto_redraw: manager.canvas.figure.stale_callback = redraw - + if auto_show: + manager.show() return manager.canvas.figure @classmethod