Coverage for /usr/lib/python3/dist-packages/matplotlib/_pylab_helpers.py: 40%
67 statements
« prev ^ index » next coverage.py v7.4.4, created at 2025-06-14 15:25 +0200
« prev ^ index » next coverage.py v7.4.4, created at 2025-06-14 15:25 +0200
1"""
2Manage figures for the pyplot interface.
3"""
5import atexit
6from collections import OrderedDict
9class Gcf:
10 """
11 Singleton to maintain the relation between figures and their managers, and
12 keep track of and "active" figure and manager.
14 The canvas of a figure created through pyplot is associated with a figure
15 manager, which handles the interaction between the figure and the backend.
16 pyplot keeps track of figure managers using an identifier, the "figure
17 number" or "manager number" (which can actually be any hashable value);
18 this number is available as the :attr:`number` attribute of the manager.
20 This class is never instantiated; it consists of an `OrderedDict` mapping
21 figure/manager numbers to managers, and a set of class methods that
22 manipulate this `OrderedDict`.
24 Attributes
25 ----------
26 figs : OrderedDict
27 `OrderedDict` mapping numbers to managers; the active manager is at the
28 end.
29 """
31 figs = OrderedDict()
33 @classmethod
34 def get_fig_manager(cls, num):
35 """
36 If manager number *num* exists, make it the active one and return it;
37 otherwise return *None*.
38 """
39 manager = cls.figs.get(num, None)
40 if manager is not None:
41 cls.set_active(manager)
42 return manager
44 @classmethod
45 def destroy(cls, num):
46 """
47 Destroy manager *num* -- either a manager instance or a manager number.
49 In the interactive backends, this is bound to the window "destroy" and
50 "delete" events.
52 It is recommended to pass a manager instance, to avoid confusion when
53 two managers share the same number.
54 """
55 if all(hasattr(num, attr) for attr in ["num", "destroy"]):
56 manager = num
57 if cls.figs.get(manager.num) is manager:
58 cls.figs.pop(manager.num)
59 else:
60 try:
61 manager = cls.figs.pop(num)
62 except KeyError:
63 return
64 if hasattr(manager, "_cidgcf"):
65 manager.canvas.mpl_disconnect(manager._cidgcf)
66 manager.destroy()
67 del manager, num
69 @classmethod
70 def destroy_fig(cls, fig):
71 """Destroy figure *fig*."""
72 num = next((manager.num for manager in cls.figs.values()
73 if manager.canvas.figure == fig), None)
74 if num is not None:
75 cls.destroy(num)
77 @classmethod
78 def destroy_all(cls):
79 """Destroy all figures."""
80 for manager in list(cls.figs.values()):
81 manager.canvas.mpl_disconnect(manager._cidgcf)
82 manager.destroy()
83 cls.figs.clear()
85 @classmethod
86 def has_fignum(cls, num):
87 """Return whether figure number *num* exists."""
88 return num in cls.figs
90 @classmethod
91 def get_all_fig_managers(cls):
92 """Return a list of figure managers."""
93 return list(cls.figs.values())
95 @classmethod
96 def get_num_fig_managers(cls):
97 """Return the number of figures being managed."""
98 return len(cls.figs)
100 @classmethod
101 def get_active(cls):
102 """Return the active manager, or *None* if there is no manager."""
103 return next(reversed(cls.figs.values())) if cls.figs else None
105 @classmethod
106 def _set_new_active_manager(cls, manager):
107 """Adopt *manager* into pyplot and make it the active manager."""
108 if not hasattr(manager, "_cidgcf"):
109 manager._cidgcf = manager.canvas.mpl_connect(
110 "button_press_event", lambda event: cls.set_active(manager))
111 fig = manager.canvas.figure
112 fig.number = manager.num
113 label = fig.get_label()
114 if label:
115 manager.set_window_title(label)
116 cls.set_active(manager)
118 @classmethod
119 def set_active(cls, manager):
120 """Make *manager* the active manager."""
121 cls.figs[manager.num] = manager
122 cls.figs.move_to_end(manager.num)
124 @classmethod
125 def draw_all(cls, force=False):
126 """
127 Redraw all stale managed figures, or, if *force* is True, all managed
128 figures.
129 """
130 for manager in cls.get_all_fig_managers():
131 if force or manager.canvas.figure.stale:
132 manager.canvas.draw_idle()
135atexit.register(Gcf.destroy_all)