##// END OF EJS Templates
reformat
Matthias Bussonnier -
Show More
@@ -1,393 +1,393 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 import warnings
9 9
10 10 from IPython.core.display import _pngxy
11 11 from IPython.utils.decorators import flag_calls
12 12
13 13 # If user specifies a GUI, that dictates the backend, otherwise we read the
14 14 # user's mpl default from the mpl rc structure
15 15 backends = {
16 16 "tk": "TkAgg",
17 17 "gtk": "GTKAgg",
18 18 "gtk3": "GTK3Agg",
19 19 "gtk4": "GTK4Agg",
20 20 "wx": "WXAgg",
21 21 "qt4": "Qt4Agg",
22 22 "qt5": "Qt5Agg",
23 23 "qt6": "QtAgg",
24 24 "qt": "Qt5Agg",
25 25 "osx": "MacOSX",
26 26 "nbagg": "nbAgg",
27 27 "notebook": "nbAgg",
28 28 "agg": "agg",
29 29 "svg": "svg",
30 30 "pdf": "pdf",
31 31 "ps": "ps",
32 32 "inline": "module://matplotlib_inline.backend_inline",
33 33 "ipympl": "module://ipympl.backend_nbagg",
34 34 "widget": "module://ipympl.backend_nbagg",
35 35 }
36 36
37 37 # We also need a reverse backends2guis mapping that will properly choose which
38 38 # GUI support to activate based on the desired matplotlib backend. For the
39 39 # most part it's just a reverse of the above dict, but we also need to add a
40 40 # few others that map to the same GUI manually:
41 41 backend2gui = dict(zip(backends.values(), backends.keys()))
42 42 # Our tests expect backend2gui to just return 'qt'
43 43 backend2gui['Qt4Agg'] = 'qt'
44 44 # In the reverse mapping, there are a few extra valid matplotlib backends that
45 45 # map to the same GUI support
46 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
47 backend2gui['GTK3Cairo'] = 'gtk3'
48 backend2gui['GTK4Cairo'] = 'gtk4'
49 backend2gui['WX'] = 'wx'
50 backend2gui['CocoaAgg'] = 'osx'
46 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
47 backend2gui["GTK3Cairo"] = "gtk3"
48 backend2gui["GTK4Cairo"] = "gtk4"
49 backend2gui["WX"] = "wx"
50 backend2gui["CocoaAgg"] = "osx"
51 51 # And some backends that don't need GUI integration
52 52 del backend2gui["nbAgg"]
53 53 del backend2gui["agg"]
54 54 del backend2gui["svg"]
55 55 del backend2gui["pdf"]
56 56 del backend2gui["ps"]
57 57 del backend2gui["module://matplotlib_inline.backend_inline"]
58 58
59 59 #-----------------------------------------------------------------------------
60 60 # Matplotlib utilities
61 61 #-----------------------------------------------------------------------------
62 62
63 63
64 64 def getfigs(*fig_nums):
65 65 """Get a list of matplotlib figures by figure numbers.
66 66
67 67 If no arguments are given, all available figures are returned. If the
68 68 argument list contains references to invalid figures, a warning is printed
69 69 but the function continues pasting further figures.
70 70
71 71 Parameters
72 72 ----------
73 73 figs : tuple
74 74 A tuple of ints giving the figure numbers of the figures to return.
75 75 """
76 76 from matplotlib._pylab_helpers import Gcf
77 77 if not fig_nums:
78 78 fig_managers = Gcf.get_all_fig_managers()
79 79 return [fm.canvas.figure for fm in fig_managers]
80 80 else:
81 81 figs = []
82 82 for num in fig_nums:
83 83 f = Gcf.figs.get(num)
84 84 if f is None:
85 85 print('Warning: figure %s not available.' % num)
86 86 else:
87 87 figs.append(f.canvas.figure)
88 88 return figs
89 89
90 90
91 91 def figsize(sizex, sizey):
92 92 """Set the default figure size to be [sizex, sizey].
93 93
94 94 This is just an easy to remember, convenience wrapper that sets::
95 95
96 96 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
97 97 """
98 98 import matplotlib
99 99 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
100 100
101 101
102 102 def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
103 103 """Print a figure to an image, and return the resulting file data
104 104
105 105 Returned data will be bytes unless ``fmt='svg'``,
106 106 in which case it will be unicode.
107 107
108 108 Any keyword args are passed to fig.canvas.print_figure,
109 109 such as ``quality`` or ``bbox_inches``.
110 110 """
111 111 # When there's an empty figure, we shouldn't return anything, otherwise we
112 112 # get big blank areas in the qt console.
113 113 if not fig.axes and not fig.lines:
114 114 return
115 115
116 116 dpi = fig.dpi
117 117 if fmt == 'retina':
118 118 dpi = dpi * 2
119 119 fmt = 'png'
120 120
121 121 # build keyword args
122 122 kw = {
123 123 "format":fmt,
124 124 "facecolor":fig.get_facecolor(),
125 125 "edgecolor":fig.get_edgecolor(),
126 126 "dpi":dpi,
127 127 "bbox_inches":bbox_inches,
128 128 }
129 129 # **kwargs get higher priority
130 130 kw.update(kwargs)
131 131
132 132 bytes_io = BytesIO()
133 133 if fig.canvas is None:
134 134 from matplotlib.backend_bases import FigureCanvasBase
135 135 FigureCanvasBase(fig)
136 136
137 137 fig.canvas.print_figure(bytes_io, **kw)
138 138 data = bytes_io.getvalue()
139 139 if fmt == 'svg':
140 140 data = data.decode('utf-8')
141 141 return data
142 142
143 143 def retina_figure(fig, **kwargs):
144 144 """format a figure as a pixel-doubled (retina) PNG"""
145 145 pngdata = print_figure(fig, fmt='retina', **kwargs)
146 146 # Make sure that retina_figure acts just like print_figure and returns
147 147 # None when the figure is empty.
148 148 if pngdata is None:
149 149 return
150 150 w, h = _pngxy(pngdata)
151 151 metadata = {"width": w//2, "height":h//2}
152 152 return pngdata, metadata
153 153
154 154 # We need a little factory function here to create the closure where
155 155 # safe_execfile can live.
156 156 def mpl_runner(safe_execfile):
157 157 """Factory to return a matplotlib-enabled runner for %run.
158 158
159 159 Parameters
160 160 ----------
161 161 safe_execfile : function
162 162 This must be a function with the same interface as the
163 163 :meth:`safe_execfile` method of IPython.
164 164
165 165 Returns
166 166 -------
167 167 A function suitable for use as the ``runner`` argument of the %run magic
168 168 function.
169 169 """
170 170
171 171 def mpl_execfile(fname,*where,**kw):
172 172 """matplotlib-aware wrapper around safe_execfile.
173 173
174 174 Its interface is identical to that of the :func:`execfile` builtin.
175 175
176 176 This is ultimately a call to execfile(), but wrapped in safeties to
177 177 properly handle interactive rendering."""
178 178
179 179 import matplotlib
180 180 import matplotlib.pyplot as plt
181 181
182 182 #print '*** Matplotlib runner ***' # dbg
183 183 # turn off rendering until end of script
184 184 is_interactive = matplotlib.rcParams['interactive']
185 185 matplotlib.interactive(False)
186 186 safe_execfile(fname,*where,**kw)
187 187 matplotlib.interactive(is_interactive)
188 188 # make rendering call now, if the user tried to do it
189 189 if plt.draw_if_interactive.called:
190 190 plt.draw()
191 191 plt.draw_if_interactive.called = False
192 192
193 193 # re-draw everything that is stale
194 194 try:
195 195 da = plt.draw_all
196 196 except AttributeError:
197 197 pass
198 198 else:
199 199 da()
200 200
201 201 return mpl_execfile
202 202
203 203
204 204 def _reshow_nbagg_figure(fig):
205 205 """reshow an nbagg figure"""
206 206 try:
207 207 reshow = fig.canvas.manager.reshow
208 208 except AttributeError as e:
209 209 raise NotImplementedError() from e
210 210 else:
211 211 reshow()
212 212
213 213
214 214 def select_figure_formats(shell, formats, **kwargs):
215 215 """Select figure formats for the inline backend.
216 216
217 217 Parameters
218 218 ==========
219 219 shell : InteractiveShell
220 220 The main IPython instance.
221 221 formats : str or set
222 222 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
223 223 **kwargs : any
224 224 Extra keyword arguments to be passed to fig.canvas.print_figure.
225 225 """
226 226 import matplotlib
227 227 from matplotlib.figure import Figure
228 228
229 229 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
230 230 png_formatter = shell.display_formatter.formatters['image/png']
231 231 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
232 232 pdf_formatter = shell.display_formatter.formatters['application/pdf']
233 233
234 234 if isinstance(formats, str):
235 235 formats = {formats}
236 236 # cast in case of list / tuple
237 237 formats = set(formats)
238 238
239 239 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
240 240 mplbackend = matplotlib.get_backend().lower()
241 241 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
242 242 formatter = shell.display_formatter.ipython_display_formatter
243 243 formatter.for_type(Figure, _reshow_nbagg_figure)
244 244
245 245 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
246 246 bad = formats.difference(supported)
247 247 if bad:
248 248 bs = "%s" % ','.join([repr(f) for f in bad])
249 249 gs = "%s" % ','.join([repr(f) for f in supported])
250 250 raise ValueError("supported formats are: %s not %s" % (gs, bs))
251 251
252 252 if 'png' in formats:
253 253 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
254 254 if 'retina' in formats or 'png2x' in formats:
255 255 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
256 256 if 'jpg' in formats or 'jpeg' in formats:
257 257 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
258 258 if 'svg' in formats:
259 259 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
260 260 if 'pdf' in formats:
261 261 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
262 262
263 263 #-----------------------------------------------------------------------------
264 264 # Code for initializing matplotlib and importing pylab
265 265 #-----------------------------------------------------------------------------
266 266
267 267
268 268 def find_gui_and_backend(gui=None, gui_select=None):
269 269 """Given a gui string return the gui and mpl backend.
270 270
271 271 Parameters
272 272 ----------
273 273 gui : str
274 274 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
275 275 gui_select : str
276 276 Can be one of ('tk','gtk','wx','qt','qt4','inline').
277 277 This is any gui already selected by the shell.
278 278
279 279 Returns
280 280 -------
281 281 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
282 282 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
283 283 """
284 284
285 285 import matplotlib
286 286
287 287 if gui and gui != 'auto':
288 288 # select backend based on requested gui
289 289 backend = backends[gui]
290 290 if gui == 'agg':
291 291 gui = None
292 292 else:
293 293 # We need to read the backend from the original data structure, *not*
294 294 # from mpl.rcParams, since a prior invocation of %matplotlib may have
295 295 # overwritten that.
296 296 # WARNING: this assumes matplotlib 1.1 or newer!!
297 297 backend = matplotlib.rcParamsOrig['backend']
298 298 # In this case, we need to find what the appropriate gui selection call
299 299 # should be for IPython, so we can activate inputhook accordingly
300 300 gui = backend2gui.get(backend, None)
301 301
302 302 # If we have already had a gui active, we need it and inline are the
303 303 # ones allowed.
304 304 if gui_select and gui != gui_select:
305 305 gui = gui_select
306 306 backend = backends[gui]
307 307
308 308 return gui, backend
309 309
310 310
311 311 def activate_matplotlib(backend):
312 312 """Activate the given backend and set interactive to True."""
313 313
314 314 import matplotlib
315 315 matplotlib.interactive(True)
316 316
317 317 # Matplotlib had a bug where even switch_backend could not force
318 318 # the rcParam to update. This needs to be set *before* the module
319 319 # magic of switch_backend().
320 320 matplotlib.rcParams['backend'] = backend
321 321
322 322 # Due to circular imports, pyplot may be only partially initialised
323 323 # when this function runs.
324 324 # So avoid needing matplotlib attribute-lookup to access pyplot.
325 325 from matplotlib import pyplot as plt
326 326
327 327 plt.switch_backend(backend)
328 328
329 329 plt.show._needmain = False
330 330 # We need to detect at runtime whether show() is called by the user.
331 331 # For this, we wrap it into a decorator which adds a 'called' flag.
332 332 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
333 333
334 334
335 335 def import_pylab(user_ns, import_all=True):
336 336 """Populate the namespace with pylab-related values.
337 337
338 338 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
339 339
340 340 Also imports a few names from IPython (figsize, display, getfigs)
341 341
342 342 """
343 343
344 344 # Import numpy as np/pyplot as plt are conventions we're trying to
345 345 # somewhat standardize on. Making them available to users by default
346 346 # will greatly help this.
347 347 s = ("import numpy\n"
348 348 "import matplotlib\n"
349 349 "from matplotlib import pylab, mlab, pyplot\n"
350 350 "np = numpy\n"
351 351 "plt = pyplot\n"
352 352 )
353 353 exec(s, user_ns)
354 354
355 355 if import_all:
356 356 s = ("from matplotlib.pylab import *\n"
357 357 "from numpy import *\n")
358 358 exec(s, user_ns)
359 359
360 360 # IPython symbols to add
361 361 user_ns['figsize'] = figsize
362 362 from IPython.display import display
363 363 # Add display and getfigs to the user's namespace
364 364 user_ns['display'] = display
365 365 user_ns['getfigs'] = getfigs
366 366
367 367
368 368 def configure_inline_support(shell, backend):
369 369 """
370 370 .. deprecated: 7.23
371 371
372 372 use `matplotlib_inline.backend_inline.configure_inline_support()`
373 373
374 374 Configure an IPython shell object for matplotlib use.
375 375
376 376 Parameters
377 377 ----------
378 378 shell : InteractiveShell instance
379 379
380 380 backend : matplotlib backend
381 381 """
382 382 warnings.warn(
383 383 "`configure_inline_support` is deprecated since IPython 7.23, directly "
384 384 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
385 385 DeprecationWarning,
386 386 stacklevel=2,
387 387 )
388 388
389 389 from matplotlib_inline.backend_inline import (
390 390 configure_inline_support as configure_inline_support_orig,
391 391 )
392 392
393 393 configure_inline_support_orig(shell, backend)
@@ -1,42 +1,43 b''
1 1 """
2 2 Enable Gtk4 to be used interactively by IPython.
3 3 """
4 #-----------------------------------------------------------------------------
4 # -----------------------------------------------------------------------------
5 5 # Copyright (c) 2021, the IPython Development Team.
6 6 #
7 7 # Distributed under the terms of the Modified BSD License.
8 8 #
9 9 # The full license is in the file COPYING.txt, distributed with this software.
10 #-----------------------------------------------------------------------------
10 # -----------------------------------------------------------------------------
11 11
12 #-----------------------------------------------------------------------------
12 # -----------------------------------------------------------------------------
13 13 # Imports
14 #-----------------------------------------------------------------------------
14 # -----------------------------------------------------------------------------
15 15
16 16 import sys
17 17
18 18 from gi.repository import GLib
19 19
20 #-----------------------------------------------------------------------------
20 # -----------------------------------------------------------------------------
21 21 # Code
22 #-----------------------------------------------------------------------------
22 # -----------------------------------------------------------------------------
23
23 24
24 25 class _InputHook:
25 26 def __init__(self, context):
26 27 self._quit = False
27 28 GLib.io_add_watch(sys.stdin, GLib.PRIORITY_DEFAULT, GLib.IO_IN, self.quit)
28 29
29 30 def quit(self, *args, **kwargs):
30 31 self._quit = True
31 32 return False
32 33
33 34 def run(self):
34 35 context = GLib.MainContext.default()
35 36 while not self._quit:
36 37 context.iteration(True)
37 38
38 39
39 40 def inputhook_gtk4():
40 41 hook = _InputHook()
41 42 hook.run()
42 43 return 0
@@ -1,25 +1,27 b''
1 1 """
2 2 prompt_toolkit input hook for GTK 4.
3 3 """
4 4
5 5 from gi.repository import GLib
6 6
7 7
8 8 class _InputHook:
9 9 def __init__(self, context):
10 10 self._quit = False
11 GLib.io_add_watch(context.fileno(), GLib.PRIORITY_DEFAULT, GLib.IO_IN, self.quit)
11 GLib.io_add_watch(
12 context.fileno(), GLib.PRIORITY_DEFAULT, GLib.IO_IN, self.quit
13 )
12 14
13 15 def quit(self, *args, **kwargs):
14 16 self._quit = True
15 17 return False
16 18
17 19 def run(self):
18 20 context = GLib.MainContext.default()
19 21 while not self._quit:
20 22 context.iteration(True)
21 23
22 24
23 25 def inputhook(context):
24 26 hook = _InputHook(context)
25 27 hook.run()
@@ -1,36 +1,37 b''
1 1 #!/usr/bin/env python
2 2 """Simple Gtk example to manually test event loop integration.
3 3
4 4 This is meant to run tests manually in ipython as:
5 5
6 6 In [1]: %gui gtk4
7 7
8 8 In [2]: %run gui-gtk4.py
9 9 """
10 10
11 11 import gi
12 gi.require_version('Gtk', '4.0')
12
13 gi.require_version("Gtk", "4.0")
13 14 from gi.repository import Gtk, GLib # noqa
14 15
15 16
16 17 def hello_world(wigdet, data=None):
17 18 print("Hello World")
18 19
19 20
20 21 def close_request_cb(widget, data=None):
21 22 global running
22 23 running = False
23 24
24 25
25 26 running = True
26 27 window = Gtk.Window()
27 28 window.connect("close-request", close_request_cb)
28 29 button = Gtk.Button(label="Hello World")
29 30 button.connect("clicked", hello_world, None)
30 31
31 32 window.set_child(button)
32 33 window.show()
33 34
34 35 context = GLib.MainContext.default()
35 36 while running:
36 37 context.iteration(True)
General Comments 0
You need to be logged in to leave comments. Login now