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