123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135 |
- """
- Manage figures for the pyplot interface.
- """
- import atexit
- from collections import OrderedDict
- class Gcf:
- """
- Singleton to maintain the relation between figures and their managers, and
- keep track of and "active" figure and manager.
- The canvas of a figure created through pyplot is associated with a figure
- manager, which handles the interaction between the figure and the backend.
- pyplot keeps track of figure managers using an identifier, the "figure
- number" or "manager number" (which can actually be any hashable value);
- this number is available as the :attr:`number` attribute of the manager.
- This class is never instantiated; it consists of an `OrderedDict` mapping
- figure/manager numbers to managers, and a set of class methods that
- manipulate this `OrderedDict`.
- Attributes
- ----------
- figs : OrderedDict
- `OrderedDict` mapping numbers to managers; the active manager is at the
- end.
- """
- figs = OrderedDict()
- @classmethod
- def get_fig_manager(cls, num):
- """
- If manager number *num* exists, make it the active one and return it;
- 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):
- """
- Destroy manager *num* -- either a manager instance or a manager number.
- In the interactive backends, this is bound to the window "destroy" and
- "delete" events.
- It is recommended to pass a manager instance, to avoid confusion when
- two managers share the same number.
- """
- if all(hasattr(num, attr) for attr in ["num", "destroy"]):
- manager = num
- if cls.figs.get(manager.num) is manager:
- cls.figs.pop(manager.num)
- else:
- try:
- manager = cls.figs.pop(num)
- except KeyError:
- return
- if hasattr(manager, "_cidgcf"):
- manager.canvas.mpl_disconnect(manager._cidgcf)
- manager.destroy()
- del manager, num
- @classmethod
- def destroy_fig(cls, fig):
- """Destroy figure *fig*."""
- num = next((manager.num for manager in cls.figs.values()
- if manager.canvas.figure == fig), None)
- if num is not None:
- cls.destroy(num)
- @classmethod
- def destroy_all(cls):
- """Destroy all figures."""
- for manager in list(cls.figs.values()):
- manager.canvas.mpl_disconnect(manager._cidgcf)
- manager.destroy()
- cls.figs.clear()
- @classmethod
- def has_fignum(cls, num):
- """Return whether figure number *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 active manager, or *None* if there is no manager."""
- return next(reversed(cls.figs.values())) if cls.figs else None
- @classmethod
- def _set_new_active_manager(cls, manager):
- """Adopt *manager* into pyplot and make it the active manager."""
- if not hasattr(manager, "_cidgcf"):
- manager._cidgcf = manager.canvas.mpl_connect(
- "button_press_event", lambda event: cls.set_active(manager))
- fig = manager.canvas.figure
- fig.number = manager.num
- label = fig.get_label()
- if label:
- manager.set_window_title(label)
- cls.set_active(manager)
- @classmethod
- def set_active(cls, manager):
- """Make *manager* the active manager."""
- cls.figs[manager.num] = manager
- cls.figs.move_to_end(manager.num)
- @classmethod
- def draw_all(cls, force=False):
- """
- Redraw all stale managed figures, or, if *force* is True, all managed
- figures.
- """
- for manager in cls.get_all_fig_managers():
- if force or manager.canvas.figure.stale:
- manager.canvas.draw_idle()
- atexit.register(Gcf.destroy_all)
|