1
1
"""
2
- Manage figures for pyplot interface.
2
+ Manage figures for the pyplot interface.
3
3
"""
4
4
5
5
import atexit
6
+ from collections import OrderedDict
6
7
import gc
7
8
8
9
9
10
class Gcf :
10
11
"""
11
- Singleton to manage a set of integer-numbered figures.
12
+ Singleton to maintain the relation between figures and their managers, and
13
+ keep track of and "active" figure and manager.
12
14
13
- This class is never instantiated; it consists of two class
14
- attributes (a list and a dictionary), and a set of static
15
- methods that operate on those attributes, accessing them
16
- directly as class attributes.
15
+ The canvas of a figure created through pyplot is associated with a figure
16
+ manager, which handles the interaction between the figure and the backend.
17
+ pyplot keeps track of figure managers using an identifier, the "figure
18
+ number" or "manager number" (which can actually be any hashable value);
19
+ this number is available as the :attr:`number` attribute of the manager.
20
+
21
+ This class is never instantiated; it consists of an `OrderedDict` mapping
22
+ figure/manager numbers to managers, and a set of class methods that
23
+ manipulate this `OrderedDict`.
17
24
18
25
Attributes
19
26
----------
20
- figs
21
- dictionary of the form {*num*: *manager*, ...}
22
- _activeQue
23
- list of *managers*, with active one at the end
24
-
27
+ figs : OrderedDict
28
+ `OrderedDict` mapping numbers to managers; the active manager is at the
29
+ end.
25
30
"""
26
- _activeQue = []
27
- figs = {}
31
+
32
+ figs = OrderedDict ()
28
33
29
34
@classmethod
30
35
def get_fig_manager (cls , num ):
31
36
"""
32
- If figure manager *num* exists, make it the active
33
- figure and return the manager; otherwise return *None*.
37
+ If manager number *num* exists, make it the active one and return it;
38
+ otherwise return *None*.
34
39
"""
35
40
manager = cls .figs .get (num , None )
36
41
if manager is not None :
@@ -40,90 +45,73 @@ def get_fig_manager(cls, num):
40
45
@classmethod
41
46
def destroy (cls , num ):
42
47
"""
43
- Try to remove all traces of figure *num*.
48
+ Destroy figure number *num*.
44
49
45
- In the interactive backends, this is bound to the
46
- window "destroy" and "delete" events.
50
+ In the interactive backends, this is bound to the window "destroy" and
51
+ "delete" events.
47
52
"""
48
53
if not cls .has_fignum (num ):
49
54
return
50
- manager = cls .figs [ num ]
55
+ manager = cls .figs . pop ( num )
51
56
manager .canvas .mpl_disconnect (manager ._cidgcf )
52
- cls ._activeQue .remove (manager )
53
- del cls .figs [num ]
54
57
manager .destroy ()
55
58
gc .collect (1 )
56
59
57
60
@classmethod
58
61
def destroy_fig (cls , fig ):
59
- "*fig* is a Figure instance "
60
- num = next (( manager . num for manager in cls . figs . values ( )
61
- if manager . canvas . figure == fig ) , None )
62
- if num is not None :
63
- cls .destroy (num )
62
+ """Destroy figure *fig*."" "
63
+ canvas = getattr ( fig , "canvas" , None )
64
+ manager = getattr ( canvas , "manager" , None )
65
+ num = getattr ( manager , "num" , None )
66
+ cls .destroy (num )
64
67
65
68
@classmethod
66
69
def destroy_all (cls ):
67
- # this is need to ensure that gc is available in corner cases
68
- # where modules are being torn down after install with easy_install
69
- import gc # noqa
70
+ """Destroy all figures."""
71
+ # Reimport gc in case the module globals have already been removed
72
+ # during interpreter shutdown.
73
+ import gc
70
74
for manager in list (cls .figs .values ()):
71
75
manager .canvas .mpl_disconnect (manager ._cidgcf )
72
76
manager .destroy ()
73
-
74
- cls ._activeQue = []
75
77
cls .figs .clear ()
76
78
gc .collect (1 )
77
79
78
80
@classmethod
79
81
def has_fignum (cls , num ):
80
- """
81
- Return *True* if figure *num* exists.
82
- """
82
+ """Return whether figure number *num* exists."""
83
83
return num in cls .figs
84
84
85
85
@classmethod
86
86
def get_all_fig_managers (cls ):
87
- """
88
- Return a list of figure managers.
89
- """
87
+ """Return a list of figure managers."""
90
88
return list (cls .figs .values ())
91
89
92
90
@classmethod
93
91
def get_num_fig_managers (cls ):
94
- """
95
- Return the number of figures being managed.
96
- """
92
+ """Return the number of figures being managed."""
97
93
return len (cls .figs )
98
94
99
95
@classmethod
100
96
def get_active (cls ):
101
- """
102
- Return the manager of the active figure, or *None*.
103
- """
104
- if len (cls ._activeQue ) == 0 :
105
- return None
106
- else :
107
- return cls ._activeQue [- 1 ]
97
+ """Return the active manager, or *None* if there is no manager."""
98
+ return next (reversed (cls .figs .values ())) if cls .figs else None
108
99
109
100
@classmethod
110
101
def set_active (cls , manager ):
111
- """
112
- Make the figure corresponding to *manager* the active one.
113
- """
114
- oldQue = cls ._activeQue [:]
115
- cls ._activeQue = [m for m in oldQue if m != manager ]
116
- cls ._activeQue .append (manager )
102
+ """Make *manager* the active manager."""
117
103
cls .figs [manager .num ] = manager
104
+ cls .figs .move_to_end (manager .num )
118
105
119
106
@classmethod
120
107
def draw_all (cls , force = False ):
121
108
"""
122
- Redraw all figures registered with the pyplot
123
- state machine .
109
+ Redraw all stale managed figures, or, if *force* is True, all managed
110
+ figures .
124
111
"""
125
- for f_mgr in cls .get_all_fig_managers ():
126
- if force or f_mgr .canvas .figure .stale :
127
- f_mgr .canvas .draw_idle ()
112
+ for manager in cls .get_all_fig_managers ():
113
+ if force or manager .canvas .figure .stale :
114
+ manager .canvas .draw_idle ()
115
+
128
116
129
117
atexit .register (Gcf .destroy_all )
0 commit comments