##// END OF EJS Templates
Fix/mpl integration (#14128)...
Matthias Bussonnier -
r28375:175d52c8 merge
parent child Browse files
Show More
@@ -1,425 +1,433 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Pylab (matplotlib) support utilities."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from io import BytesIO
8 8 from binascii import b2a_base64
9 9 from functools import partial
10 10 import warnings
11 11
12 12 from IPython.core.display import _pngxy
13 13 from IPython.utils.decorators import flag_calls
14 14
15 15 # If user specifies a GUI, that dictates the backend, otherwise we read the
16 16 # user's mpl default from the mpl rc structure
17 17 backends = {
18 18 "tk": "TkAgg",
19 19 "gtk": "GTKAgg",
20 20 "gtk3": "GTK3Agg",
21 21 "gtk4": "GTK4Agg",
22 22 "wx": "WXAgg",
23 23 "qt4": "Qt4Agg",
24 24 "qt5": "Qt5Agg",
25 25 "qt6": "QtAgg",
26 "qt": "Qt5Agg",
26 "qt": "QtAgg",
27 27 "osx": "MacOSX",
28 28 "nbagg": "nbAgg",
29 29 "webagg": "WebAgg",
30 30 "notebook": "nbAgg",
31 31 "agg": "agg",
32 32 "svg": "svg",
33 33 "pdf": "pdf",
34 34 "ps": "ps",
35 35 "inline": "module://matplotlib_inline.backend_inline",
36 36 "ipympl": "module://ipympl.backend_nbagg",
37 37 "widget": "module://ipympl.backend_nbagg",
38 38 }
39 39
40 40 # We also need a reverse backends2guis mapping that will properly choose which
41 41 # GUI support to activate based on the desired matplotlib backend. For the
42 42 # most part it's just a reverse of the above dict, but we also need to add a
43 43 # few others that map to the same GUI manually:
44 44 backend2gui = dict(zip(backends.values(), backends.keys()))
45 45 # In the reverse mapping, there are a few extra valid matplotlib backends that
46 46 # map to the same GUI support
47 47 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
48 48 backend2gui["GTK3Cairo"] = "gtk3"
49 49 backend2gui["GTK4Cairo"] = "gtk4"
50 50 backend2gui["WX"] = "wx"
51 51 backend2gui["CocoaAgg"] = "osx"
52 52 # There needs to be a hysteresis here as the new QtAgg Matplotlib backend
53 53 # supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
54 54 # and Qt6.
55 55 backend2gui["QtAgg"] = "qt"
56 backend2gui["Qt4Agg"] = "qt"
57 backend2gui["Qt5Agg"] = "qt"
56 backend2gui["Qt4Agg"] = "qt4"
57 backend2gui["Qt5Agg"] = "qt5"
58 58
59 59 # And some backends that don't need GUI integration
60 60 del backend2gui["nbAgg"]
61 61 del backend2gui["agg"]
62 62 del backend2gui["svg"]
63 63 del backend2gui["pdf"]
64 64 del backend2gui["ps"]
65 65 del backend2gui["module://matplotlib_inline.backend_inline"]
66 66 del backend2gui["module://ipympl.backend_nbagg"]
67 67
68 68 #-----------------------------------------------------------------------------
69 69 # Matplotlib utilities
70 70 #-----------------------------------------------------------------------------
71 71
72 72
73 73 def getfigs(*fig_nums):
74 74 """Get a list of matplotlib figures by figure numbers.
75 75
76 76 If no arguments are given, all available figures are returned. If the
77 77 argument list contains references to invalid figures, a warning is printed
78 78 but the function continues pasting further figures.
79 79
80 80 Parameters
81 81 ----------
82 82 figs : tuple
83 83 A tuple of ints giving the figure numbers of the figures to return.
84 84 """
85 85 from matplotlib._pylab_helpers import Gcf
86 86 if not fig_nums:
87 87 fig_managers = Gcf.get_all_fig_managers()
88 88 return [fm.canvas.figure for fm in fig_managers]
89 89 else:
90 90 figs = []
91 91 for num in fig_nums:
92 92 f = Gcf.figs.get(num)
93 93 if f is None:
94 94 print('Warning: figure %s not available.' % num)
95 95 else:
96 96 figs.append(f.canvas.figure)
97 97 return figs
98 98
99 99
100 100 def figsize(sizex, sizey):
101 101 """Set the default figure size to be [sizex, sizey].
102 102
103 103 This is just an easy to remember, convenience wrapper that sets::
104 104
105 105 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
106 106 """
107 107 import matplotlib
108 108 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
109 109
110 110
111 111 def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
112 112 """Print a figure to an image, and return the resulting file data
113 113
114 114 Returned data will be bytes unless ``fmt='svg'``,
115 115 in which case it will be unicode.
116 116
117 117 Any keyword args are passed to fig.canvas.print_figure,
118 118 such as ``quality`` or ``bbox_inches``.
119 119
120 120 If `base64` is True, return base64-encoded str instead of raw bytes
121 121 for binary-encoded image formats
122 122
123 123 .. versionadded:: 7.29
124 124 base64 argument
125 125 """
126 126 # When there's an empty figure, we shouldn't return anything, otherwise we
127 127 # get big blank areas in the qt console.
128 128 if not fig.axes and not fig.lines:
129 129 return
130 130
131 131 dpi = fig.dpi
132 132 if fmt == 'retina':
133 133 dpi = dpi * 2
134 134 fmt = 'png'
135 135
136 136 # build keyword args
137 137 kw = {
138 138 "format":fmt,
139 139 "facecolor":fig.get_facecolor(),
140 140 "edgecolor":fig.get_edgecolor(),
141 141 "dpi":dpi,
142 142 "bbox_inches":bbox_inches,
143 143 }
144 144 # **kwargs get higher priority
145 145 kw.update(kwargs)
146 146
147 147 bytes_io = BytesIO()
148 148 if fig.canvas is None:
149 149 from matplotlib.backend_bases import FigureCanvasBase
150 150 FigureCanvasBase(fig)
151 151
152 152 fig.canvas.print_figure(bytes_io, **kw)
153 153 data = bytes_io.getvalue()
154 154 if fmt == 'svg':
155 155 data = data.decode('utf-8')
156 156 elif base64:
157 157 data = b2a_base64(data, newline=False).decode("ascii")
158 158 return data
159 159
160 160 def retina_figure(fig, base64=False, **kwargs):
161 161 """format a figure as a pixel-doubled (retina) PNG
162 162
163 163 If `base64` is True, return base64-encoded str instead of raw bytes
164 164 for binary-encoded image formats
165 165
166 166 .. versionadded:: 7.29
167 167 base64 argument
168 168 """
169 169 pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
170 170 # Make sure that retina_figure acts just like print_figure and returns
171 171 # None when the figure is empty.
172 172 if pngdata is None:
173 173 return
174 174 w, h = _pngxy(pngdata)
175 175 metadata = {"width": w//2, "height":h//2}
176 176 if base64:
177 177 pngdata = b2a_base64(pngdata, newline=False).decode("ascii")
178 178 return pngdata, metadata
179 179
180 180
181 181 # We need a little factory function here to create the closure where
182 182 # safe_execfile can live.
183 183 def mpl_runner(safe_execfile):
184 184 """Factory to return a matplotlib-enabled runner for %run.
185 185
186 186 Parameters
187 187 ----------
188 188 safe_execfile : function
189 189 This must be a function with the same interface as the
190 190 :meth:`safe_execfile` method of IPython.
191 191
192 192 Returns
193 193 -------
194 194 A function suitable for use as the ``runner`` argument of the %run magic
195 195 function.
196 196 """
197 197
198 198 def mpl_execfile(fname,*where,**kw):
199 199 """matplotlib-aware wrapper around safe_execfile.
200 200
201 201 Its interface is identical to that of the :func:`execfile` builtin.
202 202
203 203 This is ultimately a call to execfile(), but wrapped in safeties to
204 204 properly handle interactive rendering."""
205 205
206 206 import matplotlib
207 207 import matplotlib.pyplot as plt
208 208
209 209 #print '*** Matplotlib runner ***' # dbg
210 210 # turn off rendering until end of script
211 is_interactive = matplotlib.rcParams['interactive']
212 matplotlib.interactive(False)
213 safe_execfile(fname,*where,**kw)
214 matplotlib.interactive(is_interactive)
211 with matplotlib.rc_context({"interactive": False}):
212 safe_execfile(fname, *where, **kw)
213
214 if matplotlib.is_interactive():
215 plt.show()
216
215 217 # make rendering call now, if the user tried to do it
216 218 if plt.draw_if_interactive.called:
217 219 plt.draw()
218 220 plt.draw_if_interactive.called = False
219 221
220 222 # re-draw everything that is stale
221 223 try:
222 224 da = plt.draw_all
223 225 except AttributeError:
224 226 pass
225 227 else:
226 228 da()
227 229
228 230 return mpl_execfile
229 231
230 232
231 233 def _reshow_nbagg_figure(fig):
232 234 """reshow an nbagg figure"""
233 235 try:
234 236 reshow = fig.canvas.manager.reshow
235 237 except AttributeError as e:
236 238 raise NotImplementedError() from e
237 239 else:
238 240 reshow()
239 241
240 242
241 243 def select_figure_formats(shell, formats, **kwargs):
242 244 """Select figure formats for the inline backend.
243 245
244 246 Parameters
245 247 ----------
246 248 shell : InteractiveShell
247 249 The main IPython instance.
248 250 formats : str or set
249 251 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
250 252 **kwargs : any
251 253 Extra keyword arguments to be passed to fig.canvas.print_figure.
252 254 """
253 255 import matplotlib
254 256 from matplotlib.figure import Figure
255 257
256 258 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
257 259 png_formatter = shell.display_formatter.formatters['image/png']
258 260 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
259 261 pdf_formatter = shell.display_formatter.formatters['application/pdf']
260 262
261 263 if isinstance(formats, str):
262 264 formats = {formats}
263 265 # cast in case of list / tuple
264 266 formats = set(formats)
265 267
266 268 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
267 269 mplbackend = matplotlib.get_backend().lower()
268 270 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
269 271 formatter = shell.display_formatter.ipython_display_formatter
270 272 formatter.for_type(Figure, _reshow_nbagg_figure)
271 273
272 274 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
273 275 bad = formats.difference(supported)
274 276 if bad:
275 277 bs = "%s" % ','.join([repr(f) for f in bad])
276 278 gs = "%s" % ','.join([repr(f) for f in supported])
277 279 raise ValueError("supported formats are: %s not %s" % (gs, bs))
278 280
279 281 if "png" in formats:
280 282 png_formatter.for_type(
281 283 Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
282 284 )
283 285 if "retina" in formats or "png2x" in formats:
284 286 png_formatter.for_type(Figure, partial(retina_figure, base64=True, **kwargs))
285 287 if "jpg" in formats or "jpeg" in formats:
286 288 jpg_formatter.for_type(
287 289 Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
288 290 )
289 291 if "svg" in formats:
290 292 svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", **kwargs))
291 293 if "pdf" in formats:
292 294 pdf_formatter.for_type(
293 295 Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
294 296 )
295 297
296 298 #-----------------------------------------------------------------------------
297 299 # Code for initializing matplotlib and importing pylab
298 300 #-----------------------------------------------------------------------------
299 301
300 302
301 303 def find_gui_and_backend(gui=None, gui_select=None):
302 304 """Given a gui string return the gui and mpl backend.
303 305
304 306 Parameters
305 307 ----------
306 308 gui : str
307 309 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
308 310 gui_select : str
309 311 Can be one of ('tk','gtk','wx','qt','qt4','inline').
310 312 This is any gui already selected by the shell.
311 313
312 314 Returns
313 315 -------
314 316 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
315 317 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
316 318 """
317 319
318 320 import matplotlib
319 321
322 has_unified_qt_backend = getattr(matplotlib, "__version_info__", (0, 0)) >= (3, 5)
323
324 backends_ = dict(backends)
325 if not has_unified_qt_backend:
326 backends_["qt"] = "qt5agg"
327
320 328 if gui and gui != 'auto':
321 329 # select backend based on requested gui
322 backend = backends[gui]
330 backend = backends_[gui]
323 331 if gui == 'agg':
324 332 gui = None
325 333 else:
326 334 # We need to read the backend from the original data structure, *not*
327 335 # from mpl.rcParams, since a prior invocation of %matplotlib may have
328 336 # overwritten that.
329 337 # WARNING: this assumes matplotlib 1.1 or newer!!
330 338 backend = matplotlib.rcParamsOrig['backend']
331 339 # In this case, we need to find what the appropriate gui selection call
332 340 # should be for IPython, so we can activate inputhook accordingly
333 341 gui = backend2gui.get(backend, None)
334 342
335 343 # If we have already had a gui active, we need it and inline are the
336 344 # ones allowed.
337 345 if gui_select and gui != gui_select:
338 346 gui = gui_select
339 backend = backends[gui]
347 backend = backends_[gui]
340 348
341 349 return gui, backend
342 350
343 351
344 352 def activate_matplotlib(backend):
345 353 """Activate the given backend and set interactive to True."""
346 354
347 355 import matplotlib
348 356 matplotlib.interactive(True)
349 357
350 358 # Matplotlib had a bug where even switch_backend could not force
351 359 # the rcParam to update. This needs to be set *before* the module
352 360 # magic of switch_backend().
353 361 matplotlib.rcParams['backend'] = backend
354 362
355 363 # Due to circular imports, pyplot may be only partially initialised
356 364 # when this function runs.
357 365 # So avoid needing matplotlib attribute-lookup to access pyplot.
358 366 from matplotlib import pyplot as plt
359 367
360 368 plt.switch_backend(backend)
361 369
362 370 plt.show._needmain = False
363 371 # We need to detect at runtime whether show() is called by the user.
364 372 # For this, we wrap it into a decorator which adds a 'called' flag.
365 373 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
366 374
367 375
368 376 def import_pylab(user_ns, import_all=True):
369 377 """Populate the namespace with pylab-related values.
370 378
371 379 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
372 380
373 381 Also imports a few names from IPython (figsize, display, getfigs)
374 382
375 383 """
376 384
377 385 # Import numpy as np/pyplot as plt are conventions we're trying to
378 386 # somewhat standardize on. Making them available to users by default
379 387 # will greatly help this.
380 388 s = ("import numpy\n"
381 389 "import matplotlib\n"
382 390 "from matplotlib import pylab, mlab, pyplot\n"
383 391 "np = numpy\n"
384 392 "plt = pyplot\n"
385 393 )
386 394 exec(s, user_ns)
387 395
388 396 if import_all:
389 397 s = ("from matplotlib.pylab import *\n"
390 398 "from numpy import *\n")
391 399 exec(s, user_ns)
392 400
393 401 # IPython symbols to add
394 402 user_ns['figsize'] = figsize
395 403 from IPython.display import display
396 404 # Add display and getfigs to the user's namespace
397 405 user_ns['display'] = display
398 406 user_ns['getfigs'] = getfigs
399 407
400 408
401 409 def configure_inline_support(shell, backend):
402 410 """
403 411 .. deprecated:: 7.23
404 412
405 413 use `matplotlib_inline.backend_inline.configure_inline_support()`
406 414
407 415 Configure an IPython shell object for matplotlib use.
408 416
409 417 Parameters
410 418 ----------
411 419 shell : InteractiveShell instance
412 420 backend : matplotlib backend
413 421 """
414 422 warnings.warn(
415 423 "`configure_inline_support` is deprecated since IPython 7.23, directly "
416 424 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
417 425 DeprecationWarning,
418 426 stacklevel=2,
419 427 )
420 428
421 429 from matplotlib_inline.backend_inline import (
422 430 configure_inline_support as configure_inline_support_orig,
423 431 )
424 432
425 433 configure_inline_support_orig(shell, backend)
@@ -1,270 +1,270 b''
1 1 """Tests for pylab tools module.
2 2 """
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 from binascii import a2b_base64
9 9 from io import BytesIO
10 10
11 11 import pytest
12 12
13 13 matplotlib = pytest.importorskip("matplotlib")
14 14 matplotlib.use('Agg')
15 15 from matplotlib.figure import Figure
16 16
17 17 from matplotlib import pyplot as plt
18 18 from matplotlib_inline import backend_inline
19 19 import numpy as np
20 20
21 21 from IPython.core.getipython import get_ipython
22 22 from IPython.core.interactiveshell import InteractiveShell
23 23 from IPython.core.display import _PNG, _JPEG
24 24 from .. import pylabtools as pt
25 25
26 26 from IPython.testing import decorators as dec
27 27
28 28
29 29 def test_figure_to_svg():
30 30 # simple empty-figure test
31 31 fig = plt.figure()
32 32 assert pt.print_figure(fig, "svg") is None
33 33
34 34 plt.close('all')
35 35
36 36 # simple check for at least svg-looking output
37 37 fig = plt.figure()
38 38 ax = fig.add_subplot(1,1,1)
39 39 ax.plot([1,2,3])
40 40 plt.draw()
41 41 svg = pt.print_figure(fig, "svg")[:100].lower()
42 42 assert "doctype svg" in svg
43 43
44 44
45 45 def _check_pil_jpeg_bytes():
46 46 """Skip if PIL can't write JPEGs to BytesIO objects"""
47 47 # PIL's JPEG plugin can't write to BytesIO objects
48 48 # Pillow fixes this
49 49 from PIL import Image
50 50 buf = BytesIO()
51 51 img = Image.new("RGB", (4,4))
52 52 try:
53 53 img.save(buf, 'jpeg')
54 54 except Exception as e:
55 55 ename = e.__class__.__name__
56 56 raise pytest.skip("PIL can't write JPEG to BytesIO: %s: %s" % (ename, e)) from e
57 57
58 58 @dec.skip_without("PIL.Image")
59 59 def test_figure_to_jpeg():
60 60 _check_pil_jpeg_bytes()
61 61 # simple check for at least jpeg-looking output
62 62 fig = plt.figure()
63 63 ax = fig.add_subplot(1,1,1)
64 64 ax.plot([1,2,3])
65 65 plt.draw()
66 66 jpeg = pt.print_figure(fig, 'jpeg', pil_kwargs={'optimize': 50})[:100].lower()
67 67 assert jpeg.startswith(_JPEG)
68 68
69 69 def test_retina_figure():
70 70 # simple empty-figure test
71 71 fig = plt.figure()
72 72 assert pt.retina_figure(fig) == None
73 73 plt.close('all')
74 74
75 75 fig = plt.figure()
76 76 ax = fig.add_subplot(1,1,1)
77 77 ax.plot([1,2,3])
78 78 plt.draw()
79 79 png, md = pt.retina_figure(fig)
80 80 assert png.startswith(_PNG)
81 81 assert "width" in md
82 82 assert "height" in md
83 83
84 84
85 85 _fmt_mime_map = {
86 86 'png': 'image/png',
87 87 'jpeg': 'image/jpeg',
88 88 'pdf': 'application/pdf',
89 89 'retina': 'image/png',
90 90 'svg': 'image/svg+xml',
91 91 }
92 92
93 93 def test_select_figure_formats_str():
94 94 ip = get_ipython()
95 95 for fmt, active_mime in _fmt_mime_map.items():
96 96 pt.select_figure_formats(ip, fmt)
97 97 for mime, f in ip.display_formatter.formatters.items():
98 98 if mime == active_mime:
99 99 assert Figure in f
100 100 else:
101 101 assert Figure not in f
102 102
103 103 def test_select_figure_formats_kwargs():
104 104 ip = get_ipython()
105 105 kwargs = dict(bbox_inches="tight")
106 106 pt.select_figure_formats(ip, "png", **kwargs)
107 107 formatter = ip.display_formatter.formatters["image/png"]
108 108 f = formatter.lookup_by_type(Figure)
109 109 cell = f.keywords
110 110 expected = kwargs
111 111 expected["base64"] = True
112 112 expected["fmt"] = "png"
113 113 assert cell == expected
114 114
115 115 # check that the formatter doesn't raise
116 116 fig = plt.figure()
117 117 ax = fig.add_subplot(1,1,1)
118 118 ax.plot([1,2,3])
119 119 plt.draw()
120 120 formatter.enabled = True
121 121 png = formatter(fig)
122 122 assert isinstance(png, str)
123 123 png_bytes = a2b_base64(png)
124 124 assert png_bytes.startswith(_PNG)
125 125
126 126 def test_select_figure_formats_set():
127 127 ip = get_ipython()
128 128 for fmts in [
129 129 {'png', 'svg'},
130 130 ['png'],
131 131 ('jpeg', 'pdf', 'retina'),
132 132 {'svg'},
133 133 ]:
134 134 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
135 135 pt.select_figure_formats(ip, fmts)
136 136 for mime, f in ip.display_formatter.formatters.items():
137 137 if mime in active_mimes:
138 138 assert Figure in f
139 139 else:
140 140 assert Figure not in f
141 141
142 142 def test_select_figure_formats_bad():
143 143 ip = get_ipython()
144 144 with pytest.raises(ValueError):
145 145 pt.select_figure_formats(ip, 'foo')
146 146 with pytest.raises(ValueError):
147 147 pt.select_figure_formats(ip, {'png', 'foo'})
148 148 with pytest.raises(ValueError):
149 149 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
150 150
151 151 def test_import_pylab():
152 152 ns = {}
153 153 pt.import_pylab(ns, import_all=False)
154 154 assert "plt" in ns
155 155 assert ns["np"] == np
156 156
157 157
158 158 class TestPylabSwitch(object):
159 159 class Shell(InteractiveShell):
160 160 def init_history(self):
161 161 """Sets up the command history, and starts regular autosaves."""
162 162 self.config.HistoryManager.hist_file = ":memory:"
163 163 super().init_history()
164 164
165 165 def enable_gui(self, gui):
166 166 pass
167 167
168 168 def setup(self):
169 169 import matplotlib
170 170 def act_mpl(backend):
171 171 matplotlib.rcParams['backend'] = backend
172 172
173 173 # Save rcParams since they get modified
174 174 self._saved_rcParams = matplotlib.rcParams
175 175 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
176 matplotlib.rcParams = dict(backend='Qt4Agg')
177 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
176 matplotlib.rcParams = dict(backend="QtAgg")
177 matplotlib.rcParamsOrig = dict(backend="QtAgg")
178 178
179 179 # Mock out functions
180 180 self._save_am = pt.activate_matplotlib
181 181 pt.activate_matplotlib = act_mpl
182 182 self._save_ip = pt.import_pylab
183 183 pt.import_pylab = lambda *a,**kw:None
184 184 self._save_cis = backend_inline.configure_inline_support
185 185 backend_inline.configure_inline_support = lambda *a, **kw: None
186 186
187 187 def teardown(self):
188 188 pt.activate_matplotlib = self._save_am
189 189 pt.import_pylab = self._save_ip
190 190 backend_inline.configure_inline_support = self._save_cis
191 191 import matplotlib
192 192 matplotlib.rcParams = self._saved_rcParams
193 193 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
194 194
195 195 def test_qt(self):
196 196 s = self.Shell()
197 197 gui, backend = s.enable_matplotlib(None)
198 198 assert gui == "qt"
199 199 assert s.pylab_gui_select == "qt"
200 200
201 201 gui, backend = s.enable_matplotlib("inline")
202 202 assert gui == "inline"
203 203 assert s.pylab_gui_select == "qt"
204 204
205 205 gui, backend = s.enable_matplotlib("qt")
206 206 assert gui == "qt"
207 207 assert s.pylab_gui_select == "qt"
208 208
209 209 gui, backend = s.enable_matplotlib("inline")
210 210 assert gui == "inline"
211 211 assert s.pylab_gui_select == "qt"
212 212
213 213 gui, backend = s.enable_matplotlib()
214 214 assert gui == "qt"
215 215 assert s.pylab_gui_select == "qt"
216 216
217 217 def test_inline(self):
218 218 s = self.Shell()
219 219 gui, backend = s.enable_matplotlib("inline")
220 220 assert gui == "inline"
221 221 assert s.pylab_gui_select == None
222 222
223 223 gui, backend = s.enable_matplotlib("inline")
224 224 assert gui == "inline"
225 225 assert s.pylab_gui_select == None
226 226
227 227 gui, backend = s.enable_matplotlib("qt")
228 228 assert gui == "qt"
229 229 assert s.pylab_gui_select == "qt"
230 230
231 231 def test_inline_twice(self):
232 232 "Using '%matplotlib inline' twice should not reset formatters"
233 233
234 234 ip = self.Shell()
235 235 gui, backend = ip.enable_matplotlib("inline")
236 236 assert gui == "inline"
237 237
238 238 fmts = {'png'}
239 239 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
240 240 pt.select_figure_formats(ip, fmts)
241 241
242 242 gui, backend = ip.enable_matplotlib("inline")
243 243 assert gui == "inline"
244 244
245 245 for mime, f in ip.display_formatter.formatters.items():
246 246 if mime in active_mimes:
247 247 assert Figure in f
248 248 else:
249 249 assert Figure not in f
250 250
251 251 def test_qt_gtk(self):
252 252 s = self.Shell()
253 253 gui, backend = s.enable_matplotlib("qt")
254 254 assert gui == "qt"
255 255 assert s.pylab_gui_select == "qt"
256 256
257 257 gui, backend = s.enable_matplotlib("gtk")
258 258 assert gui == "qt"
259 259 assert s.pylab_gui_select == "qt"
260 260
261 261
262 262 def test_no_gui_backends():
263 263 for k in ['agg', 'svg', 'pdf', 'ps']:
264 264 assert k not in pt.backend2gui
265 265
266 266
267 267 def test_figure_no_canvas():
268 268 fig = Figure()
269 269 fig.canvas = None
270 270 pt.print_figure(fig)
General Comments 0
You need to be logged in to leave comments. Login now