26
26
import re
27
27
import sys
28
28
import time
29
+ try :
30
+ import threading
31
+ except ImportError :
32
+ import dummy_threading as threading
29
33
30
34
from cycler import cycler
31
35
import matplotlib
@@ -175,6 +179,11 @@ def findobj(o=None, match=None, include_self=True):
175
179
return o .findobj (match , include_self = include_self )
176
180
177
181
182
+ def _get_required_interactive_framework (backend_mod ):
183
+ return getattr (
184
+ backend_mod .FigureCanvas , "required_interactive_framework" , None )
185
+
186
+
178
187
def switch_backend (newbackend ):
179
188
"""
180
189
Close all open figures and set the Matplotlib backend.
@@ -188,6 +197,8 @@ def switch_backend(newbackend):
188
197
newbackend : str
189
198
The name of the backend to use.
190
199
"""
200
+ global _backend_mod
201
+
191
202
close ("all" )
192
203
193
204
if newbackend is rcsetup ._auto_backend_sentinel :
@@ -210,15 +221,17 @@ def switch_backend(newbackend):
210
221
rcParamsOrig ["backend" ] = "agg"
211
222
return
212
223
224
+ # Backends are implemented as modules, but "inherit" default method
225
+ # implementations from backend_bases._Backend. This is achieved by
226
+ # creating a "class" that inherits from backend_bases._Backend and whose
227
+ # body is filled with the module's globals.
228
+
213
229
backend_name = cbook ._backend_module_name (newbackend )
214
- backend_mod = importlib .import_module (backend_name )
215
- Backend = type (
216
- "Backend" , (matplotlib .backend_bases ._Backend ,), vars (backend_mod ))
217
- _log .debug ("Loaded backend %s version %s." ,
218
- newbackend , Backend .backend_version )
219
230
220
- required_framework = getattr (
221
- Backend .FigureCanvas , "required_interactive_framework" , None )
231
+ class backend_mod (matplotlib .backend_bases ._Backend ):
232
+ locals ().update (vars (importlib .import_module (backend_name )))
233
+
234
+ required_framework = _get_required_interactive_framework (backend_mod )
222
235
if required_framework is not None :
223
236
current_framework = cbook ._get_running_interactive_framework ()
224
237
if (current_framework and required_framework
@@ -228,23 +241,42 @@ def switch_backend(newbackend):
228
241
"framework, as {!r} is currently running" .format (
229
242
newbackend , required_framework , current_framework ))
230
243
231
- # Update both rcParams and rcDefaults so restoring the defaults later with
232
- # rcdefaults won't change the backend. A bit of overkill as 'backend' is
233
- # already in style.core.STYLE_BLACKLIST, but better to be safe.
234
- rcParams ['backend' ] = rcParamsDefault ['backend' ] = newbackend
244
+ _log .debug ("Loaded backend %s version %s." ,
245
+ newbackend , backend_mod .backend_version )
235
246
236
- global _backend_mod , new_figure_manager , draw_if_interactive , _show
247
+ rcParams [ 'backend' ] = rcParamsDefault [ 'backend' ] = newbackend
237
248
_backend_mod = backend_mod
238
- new_figure_manager = Backend . new_figure_manager
239
- draw_if_interactive = Backend . draw_if_interactive
240
- _show = Backend . show
249
+ for func_name in [ " new_figure_manager" , "draw_if_interactive" , "show" ]:
250
+ globals ()[ func_name ]. __signature__ = inspect . signature (
251
+ getattr ( backend_mod , func_name ))
241
252
242
253
# Need to keep a global reference to the backend for compatibility reasons.
243
254
# See https://github.com/matplotlib/matplotlib/issues/6092
244
255
matplotlib .backends .backend = newbackend
245
256
246
257
247
- def show (* args , ** kw ):
258
+ def _warn_if_gui_out_of_main_thread ():
259
+ if (_get_required_interactive_framework (_backend_mod )
260
+ and threading .current_thread () is not threading .main_thread ()):
261
+ cbook ._warn_external (
262
+ "Starting a Matplotlib GUI outside of the main thread will likely "
263
+ "fail." )
264
+
265
+
266
+ # This function's signature is rewritten upon backend-load by switch_backend.
267
+ def new_figure_manager (* args , ** kwargs ):
268
+ """Create a new figure manager instance."""
269
+ _warn_if_gui_out_of_main_thread ()
270
+ return _backend_mod .new_figure_manager (* args , ** kwargs )
271
+
272
+
273
+ # This function's signature is rewritten upon backend-load by switch_backend.
274
+ def draw_if_interactive (* args , ** kwargs ):
275
+ return _backend_mod .draw_if_interactive (* args , ** kwargs )
276
+
277
+
278
+ # This function's signature is rewritten upon backend-load by switch_backend.
279
+ def show (* args , ** kwargs ):
248
280
"""
249
281
Display all figures.
250
282
@@ -263,8 +295,8 @@ def show(*args, **kw):
263
295
This is experimental, and may be set to ``True`` or ``False`` to
264
296
override the blocking behavior described above.
265
297
"""
266
- global _show
267
- return _show (* args , ** kw )
298
+ _warn_if_gui_out_of_main_thread ()
299
+ return _backend_mod . show (* args , ** kwargs )
268
300
269
301
270
302
def isinteractive ():
0 commit comments