""" Manage figures for pyplot interface. """ from __future__ import (absolute_import, division, print_function, unicode_literals) from matplotlib.externals import six import sys import gc import atexit def error_msg(msg): print(msg, file=sys.stderr) class Gcf(object): """ Singleton to manage a set of integer-numbered figures. This class is never instantiated; it consists of two class attributes (a list and a dictionary), and a set of static methods that operate on those attributes, accessing them directly as class attributes. Attributes: *figs*: dictionary of the form {*num*: *manager*, ...} *_activeQue*: list of *managers*, with active one at the end """ _activeQue = [] figs = {} @classmethod def get_fig_manager(cls, num): """ If figure manager *num* exists, make it the active figure and return the manager; otherwise return *None*. """ manager = cls.figs.get(num, None) if manager is not None: cls.set_active(manager) return manager @classmethod def destroy(cls, num): """ Try to remove all traces of figure *num*. In the interactive backends, this is bound to the window "destroy" and "delete" events. """ if not cls.has_fignum(num): return manager = cls.figs[num] manager.canvas.mpl_disconnect(manager._cidgcf) # There must be a good reason for the following careful # rebuilding of the activeQue; what is it? oldQue = cls._activeQue[:] cls._activeQue = [] for f in oldQue: if f != manager: cls._activeQue.append(f) del cls.figs[num] manager.destroy() gc.collect(1) @classmethod def destroy_fig(cls, fig): "*fig* is a Figure instance" num = None for manager in six.itervalues(cls.figs): if manager.canvas.figure == fig: num = manager.num break if num is not None: cls.destroy(num) @classmethod def destroy_all(cls): # this is need to ensure that gc is available in corner cases # where modules are being torn down after install with easy_install import gc # noqa for manager in list(cls.figs.values()): manager.canvas.mpl_disconnect(manager._cidgcf) manager.destroy() cls._activeQue = [] cls.figs.clear() gc.collect(1) @classmethod def has_fignum(cls, num): """ Return *True* if figure *num* exists. """ return num in cls.figs @classmethod def get_all_fig_managers(cls): """ Return a list of figure managers. """ return list(cls.figs.values()) @classmethod def get_num_fig_managers(cls): """ Return the number of figures being managed. """ return len(cls.figs) @classmethod def get_active(cls): """ Return the manager of the active figure, or *None*. """ if len(cls._activeQue) == 0: return None else: return cls._activeQue[-1] @classmethod def set_active(cls, manager): """ Make the figure corresponding to *manager* the active one. """ oldQue = cls._activeQue[:] cls._activeQue = [] for m in oldQue: if m != manager: cls._activeQue.append(m) cls._activeQue.append(manager) cls.figs[manager.num] = manager @classmethod def draw_all(cls, force=False): """ Redraw all figures registered with the pyplot state machine. """ for f_mgr in cls.get_all_fig_managers(): if force or f_mgr.canvas.figure.stale: f_mgr.canvas.draw_idle() atexit.register(Gcf.destroy_all)