@@ -78,9 +78,10 @@ def connection_info():
78
78
for manager in Gcf .get_all_fig_managers ():
79
79
fig = manager .canvas .figure
80
80
result .append ('{0} - {0}' .format ((fig .get_label () or
81
- "Figure {0}" .format (manager .num )),
82
- manager .web_sockets ))
83
- result .append ('Figures pending show: {0}' .format (len (Gcf ._activeQue )))
81
+ "Figure {0}" .format (manager .num )),
82
+ manager .web_sockets ))
83
+ if not is_interactive ():
84
+ result .append ('Figures pending show: {0}' .format (len (Gcf ._activeQue )))
84
85
return '\n ' .join (result )
85
86
86
87
@@ -166,13 +167,22 @@ def _create_comm(self):
166
167
167
168
def destroy (self ):
168
169
self ._send_event ('close' )
169
- for comm in self .web_sockets .copy ():
170
+ # need to copy comms as callbacks will modify this list
171
+ for comm in list (self .web_sockets ):
170
172
comm .on_close ()
173
+ self .clearup_closed ()
171
174
172
175
def clearup_closed (self ):
173
176
"""Clear up any closed Comms."""
174
177
self .web_sockets = set ([socket for socket in self .web_sockets
175
- if not socket .is_open ()])
178
+ if socket .is_open ()])
179
+
180
+ if len (self .web_sockets ) == 0 :
181
+ self .canvas .close_event ()
182
+
183
+ def remove_comm (self , comm_id ):
184
+ self .web_sockets = set ([socket for socket in self .web_sockets
185
+ if not socket .comm .comm_id == comm_id ])
176
186
177
187
178
188
class TimerTornado (TimerBase ):
@@ -231,13 +241,22 @@ def new_figure_manager_given_figure(num, figure):
231
241
"""
232
242
Create a new figure manager instance for the given figure.
233
243
"""
244
+ from .._pylab_helpers import Gcf
245
+
246
+ def closer (event ):
247
+ Gcf .destroy (num )
248
+
234
249
canvas = FigureCanvasNbAgg (figure )
235
250
if rcParams ['nbagg.transparent' ]:
236
251
figure .patch .set_alpha (0 )
237
252
manager = FigureManagerNbAgg (canvas , num )
253
+
238
254
if is_interactive ():
239
255
manager .show ()
240
256
figure .canvas .draw_idle ()
257
+
258
+ canvas .mpl_connect ('close_event' , closer )
259
+
241
260
return manager
242
261
243
262
@@ -266,16 +285,27 @@ def __init__(self, manager):
266
285
self .comm .on_msg (self .on_message )
267
286
268
287
manager = self .manager
269
- self .comm .on_close (lambda close_message : manager .clearup_closed ())
288
+ self ._ext_close = False
289
+
290
+ def _on_close (close_message ):
291
+ self ._ext_close = True
292
+ manager .remove_comm (close_message ['content' ]['comm_id' ])
293
+ manager .clearup_closed ()
294
+
295
+ self .comm .on_close (_on_close )
270
296
271
297
def is_open (self ):
272
- return not self .comm ._closed
298
+ return not ( self ._ext_close or self . comm ._closed )
273
299
274
300
def on_close (self ):
275
301
# When the socket is closed, deregister the websocket with
276
302
# the FigureManager.
277
- self .comm .close ()
278
- self .manager .clearup_closed ()
303
+ if self .is_open ():
304
+ try :
305
+ self .comm .close ()
306
+ except KeyError :
307
+ # apparently already cleaned it up?
308
+ pass
279
309
280
310
def send_json (self , content ):
281
311
self .comm .send ({'data' : json .dumps (content )})
@@ -298,6 +328,7 @@ def on_message(self, message):
298
328
message = json .loads (message ['content' ]['data' ])
299
329
if message ['type' ] == 'closing' :
300
330
self .on_close ()
331
+ self .manager .clearup_closed ()
301
332
elif message ['type' ] == 'supports_binary' :
302
333
self .supports_binary = message ['value' ]
303
334
else :
0 commit comments