##// END OF EJS Templates
Don't emit a trailng newline in base64-encoded data like 'image/png'
Alexey Zaytsev -
Show More
@@ -1,1290 +1,1290 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Top-level display functions for displaying object in different formats."""
2 """Top-level display functions for displaying object in different formats."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7
7
8 from binascii import b2a_base64, hexlify
8 from binascii import b2a_base64, hexlify
9 import html
9 import html
10 import json
10 import json
11 import mimetypes
11 import mimetypes
12 import os
12 import os
13 import struct
13 import struct
14 import warnings
14 import warnings
15 from copy import deepcopy
15 from copy import deepcopy
16 from os.path import splitext
16 from os.path import splitext
17 from pathlib import Path, PurePath
17 from pathlib import Path, PurePath
18
18
19 from IPython.utils.py3compat import cast_unicode
19 from IPython.utils.py3compat import cast_unicode
20 from IPython.testing.skipdoctest import skip_doctest
20 from IPython.testing.skipdoctest import skip_doctest
21 from . import display_functions
21 from . import display_functions
22
22
23
23
24 __all__ = ['display_pretty', 'display_html', 'display_markdown',
24 __all__ = ['display_pretty', 'display_html', 'display_markdown',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
25 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
26 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
27 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
28 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
28 'GeoJSON', 'Javascript', 'Image', 'set_matplotlib_formats',
29 'set_matplotlib_close',
29 'set_matplotlib_close',
30 'Video']
30 'Video']
31
31
32 _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
32 _deprecated_names = ["display", "clear_output", "publish_display_data", "update_display", "DisplayHandle"]
33
33
34 __all__ = __all__ + _deprecated_names
34 __all__ = __all__ + _deprecated_names
35
35
36
36
37 # ----- warn to import from IPython.display -----
37 # ----- warn to import from IPython.display -----
38
38
39 from warnings import warn
39 from warnings import warn
40
40
41
41
42 def __getattr__(name):
42 def __getattr__(name):
43 if name in _deprecated_names:
43 if name in _deprecated_names:
44 warn(f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython display", DeprecationWarning, stacklevel=2)
44 warn(f"Importing {name} from IPython.core.display is deprecated since IPython 7.14, please import from IPython display", DeprecationWarning, stacklevel=2)
45 return getattr(display_functions, name)
45 return getattr(display_functions, name)
46
46
47 if name in globals().keys():
47 if name in globals().keys():
48 return globals()[name]
48 return globals()[name]
49 else:
49 else:
50 raise AttributeError(f"module {__name__} has no attribute {name}")
50 raise AttributeError(f"module {__name__} has no attribute {name}")
51
51
52
52
53 #-----------------------------------------------------------------------------
53 #-----------------------------------------------------------------------------
54 # utility functions
54 # utility functions
55 #-----------------------------------------------------------------------------
55 #-----------------------------------------------------------------------------
56
56
57 def _safe_exists(path):
57 def _safe_exists(path):
58 """Check path, but don't let exceptions raise"""
58 """Check path, but don't let exceptions raise"""
59 try:
59 try:
60 return os.path.exists(path)
60 return os.path.exists(path)
61 except Exception:
61 except Exception:
62 return False
62 return False
63
63
64
64
65 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
65 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
66 """internal implementation of all display_foo methods
66 """internal implementation of all display_foo methods
67
67
68 Parameters
68 Parameters
69 ----------
69 ----------
70 mimetype : str
70 mimetype : str
71 The mimetype to be published (e.g. 'image/png')
71 The mimetype to be published (e.g. 'image/png')
72 *objs : object
72 *objs : object
73 The Python objects to display, or if raw=True raw text data to
73 The Python objects to display, or if raw=True raw text data to
74 display.
74 display.
75 raw : bool
75 raw : bool
76 Are the data objects raw data or Python objects that need to be
76 Are the data objects raw data or Python objects that need to be
77 formatted before display? [default: False]
77 formatted before display? [default: False]
78 metadata : dict (optional)
78 metadata : dict (optional)
79 Metadata to be associated with the specific mimetype output.
79 Metadata to be associated with the specific mimetype output.
80 """
80 """
81 if metadata:
81 if metadata:
82 metadata = {mimetype: metadata}
82 metadata = {mimetype: metadata}
83 if raw:
83 if raw:
84 # turn list of pngdata into list of { 'image/png': pngdata }
84 # turn list of pngdata into list of { 'image/png': pngdata }
85 objs = [ {mimetype: obj} for obj in objs ]
85 objs = [ {mimetype: obj} for obj in objs ]
86 display_functions.display(*objs, raw=raw, metadata=metadata, include=[mimetype])
86 display_functions.display(*objs, raw=raw, metadata=metadata, include=[mimetype])
87
87
88 #-----------------------------------------------------------------------------
88 #-----------------------------------------------------------------------------
89 # Main functions
89 # Main functions
90 #-----------------------------------------------------------------------------
90 #-----------------------------------------------------------------------------
91
91
92
92
93 def display_pretty(*objs, **kwargs):
93 def display_pretty(*objs, **kwargs):
94 """Display the pretty (default) representation of an object.
94 """Display the pretty (default) representation of an object.
95
95
96 Parameters
96 Parameters
97 ----------
97 ----------
98 *objs : object
98 *objs : object
99 The Python objects to display, or if raw=True raw text data to
99 The Python objects to display, or if raw=True raw text data to
100 display.
100 display.
101 raw : bool
101 raw : bool
102 Are the data objects raw data or Python objects that need to be
102 Are the data objects raw data or Python objects that need to be
103 formatted before display? [default: False]
103 formatted before display? [default: False]
104 metadata : dict (optional)
104 metadata : dict (optional)
105 Metadata to be associated with the specific mimetype output.
105 Metadata to be associated with the specific mimetype output.
106 """
106 """
107 _display_mimetype('text/plain', objs, **kwargs)
107 _display_mimetype('text/plain', objs, **kwargs)
108
108
109
109
110 def display_html(*objs, **kwargs):
110 def display_html(*objs, **kwargs):
111 """Display the HTML representation of an object.
111 """Display the HTML representation of an object.
112
112
113 Note: If raw=False and the object does not have a HTML
113 Note: If raw=False and the object does not have a HTML
114 representation, no HTML will be shown.
114 representation, no HTML will be shown.
115
115
116 Parameters
116 Parameters
117 ----------
117 ----------
118 *objs : object
118 *objs : object
119 The Python objects to display, or if raw=True raw HTML data to
119 The Python objects to display, or if raw=True raw HTML data to
120 display.
120 display.
121 raw : bool
121 raw : bool
122 Are the data objects raw data or Python objects that need to be
122 Are the data objects raw data or Python objects that need to be
123 formatted before display? [default: False]
123 formatted before display? [default: False]
124 metadata : dict (optional)
124 metadata : dict (optional)
125 Metadata to be associated with the specific mimetype output.
125 Metadata to be associated with the specific mimetype output.
126 """
126 """
127 _display_mimetype('text/html', objs, **kwargs)
127 _display_mimetype('text/html', objs, **kwargs)
128
128
129
129
130 def display_markdown(*objs, **kwargs):
130 def display_markdown(*objs, **kwargs):
131 """Displays the Markdown representation of an object.
131 """Displays the Markdown representation of an object.
132
132
133 Parameters
133 Parameters
134 ----------
134 ----------
135 *objs : object
135 *objs : object
136 The Python objects to display, or if raw=True raw markdown data to
136 The Python objects to display, or if raw=True raw markdown data to
137 display.
137 display.
138 raw : bool
138 raw : bool
139 Are the data objects raw data or Python objects that need to be
139 Are the data objects raw data or Python objects that need to be
140 formatted before display? [default: False]
140 formatted before display? [default: False]
141 metadata : dict (optional)
141 metadata : dict (optional)
142 Metadata to be associated with the specific mimetype output.
142 Metadata to be associated with the specific mimetype output.
143 """
143 """
144
144
145 _display_mimetype('text/markdown', objs, **kwargs)
145 _display_mimetype('text/markdown', objs, **kwargs)
146
146
147
147
148 def display_svg(*objs, **kwargs):
148 def display_svg(*objs, **kwargs):
149 """Display the SVG representation of an object.
149 """Display the SVG representation of an object.
150
150
151 Parameters
151 Parameters
152 ----------
152 ----------
153 *objs : object
153 *objs : object
154 The Python objects to display, or if raw=True raw svg data to
154 The Python objects to display, or if raw=True raw svg data to
155 display.
155 display.
156 raw : bool
156 raw : bool
157 Are the data objects raw data or Python objects that need to be
157 Are the data objects raw data or Python objects that need to be
158 formatted before display? [default: False]
158 formatted before display? [default: False]
159 metadata : dict (optional)
159 metadata : dict (optional)
160 Metadata to be associated with the specific mimetype output.
160 Metadata to be associated with the specific mimetype output.
161 """
161 """
162 _display_mimetype('image/svg+xml', objs, **kwargs)
162 _display_mimetype('image/svg+xml', objs, **kwargs)
163
163
164
164
165 def display_png(*objs, **kwargs):
165 def display_png(*objs, **kwargs):
166 """Display the PNG representation of an object.
166 """Display the PNG representation of an object.
167
167
168 Parameters
168 Parameters
169 ----------
169 ----------
170 *objs : object
170 *objs : object
171 The Python objects to display, or if raw=True raw png data to
171 The Python objects to display, or if raw=True raw png data to
172 display.
172 display.
173 raw : bool
173 raw : bool
174 Are the data objects raw data or Python objects that need to be
174 Are the data objects raw data or Python objects that need to be
175 formatted before display? [default: False]
175 formatted before display? [default: False]
176 metadata : dict (optional)
176 metadata : dict (optional)
177 Metadata to be associated with the specific mimetype output.
177 Metadata to be associated with the specific mimetype output.
178 """
178 """
179 _display_mimetype('image/png', objs, **kwargs)
179 _display_mimetype('image/png', objs, **kwargs)
180
180
181
181
182 def display_jpeg(*objs, **kwargs):
182 def display_jpeg(*objs, **kwargs):
183 """Display the JPEG representation of an object.
183 """Display the JPEG representation of an object.
184
184
185 Parameters
185 Parameters
186 ----------
186 ----------
187 *objs : object
187 *objs : object
188 The Python objects to display, or if raw=True raw JPEG data to
188 The Python objects to display, or if raw=True raw JPEG data to
189 display.
189 display.
190 raw : bool
190 raw : bool
191 Are the data objects raw data or Python objects that need to be
191 Are the data objects raw data or Python objects that need to be
192 formatted before display? [default: False]
192 formatted before display? [default: False]
193 metadata : dict (optional)
193 metadata : dict (optional)
194 Metadata to be associated with the specific mimetype output.
194 Metadata to be associated with the specific mimetype output.
195 """
195 """
196 _display_mimetype('image/jpeg', objs, **kwargs)
196 _display_mimetype('image/jpeg', objs, **kwargs)
197
197
198
198
199 def display_latex(*objs, **kwargs):
199 def display_latex(*objs, **kwargs):
200 """Display the LaTeX representation of an object.
200 """Display the LaTeX representation of an object.
201
201
202 Parameters
202 Parameters
203 ----------
203 ----------
204 *objs : object
204 *objs : object
205 The Python objects to display, or if raw=True raw latex data to
205 The Python objects to display, or if raw=True raw latex data to
206 display.
206 display.
207 raw : bool
207 raw : bool
208 Are the data objects raw data or Python objects that need to be
208 Are the data objects raw data or Python objects that need to be
209 formatted before display? [default: False]
209 formatted before display? [default: False]
210 metadata : dict (optional)
210 metadata : dict (optional)
211 Metadata to be associated with the specific mimetype output.
211 Metadata to be associated with the specific mimetype output.
212 """
212 """
213 _display_mimetype('text/latex', objs, **kwargs)
213 _display_mimetype('text/latex', objs, **kwargs)
214
214
215
215
216 def display_json(*objs, **kwargs):
216 def display_json(*objs, **kwargs):
217 """Display the JSON representation of an object.
217 """Display the JSON representation of an object.
218
218
219 Note that not many frontends support displaying JSON.
219 Note that not many frontends support displaying JSON.
220
220
221 Parameters
221 Parameters
222 ----------
222 ----------
223 *objs : object
223 *objs : object
224 The Python objects to display, or if raw=True raw json data to
224 The Python objects to display, or if raw=True raw json data to
225 display.
225 display.
226 raw : bool
226 raw : bool
227 Are the data objects raw data or Python objects that need to be
227 Are the data objects raw data or Python objects that need to be
228 formatted before display? [default: False]
228 formatted before display? [default: False]
229 metadata : dict (optional)
229 metadata : dict (optional)
230 Metadata to be associated with the specific mimetype output.
230 Metadata to be associated with the specific mimetype output.
231 """
231 """
232 _display_mimetype('application/json', objs, **kwargs)
232 _display_mimetype('application/json', objs, **kwargs)
233
233
234
234
235 def display_javascript(*objs, **kwargs):
235 def display_javascript(*objs, **kwargs):
236 """Display the Javascript representation of an object.
236 """Display the Javascript representation of an object.
237
237
238 Parameters
238 Parameters
239 ----------
239 ----------
240 *objs : object
240 *objs : object
241 The Python objects to display, or if raw=True raw javascript data to
241 The Python objects to display, or if raw=True raw javascript data to
242 display.
242 display.
243 raw : bool
243 raw : bool
244 Are the data objects raw data or Python objects that need to be
244 Are the data objects raw data or Python objects that need to be
245 formatted before display? [default: False]
245 formatted before display? [default: False]
246 metadata : dict (optional)
246 metadata : dict (optional)
247 Metadata to be associated with the specific mimetype output.
247 Metadata to be associated with the specific mimetype output.
248 """
248 """
249 _display_mimetype('application/javascript', objs, **kwargs)
249 _display_mimetype('application/javascript', objs, **kwargs)
250
250
251
251
252 def display_pdf(*objs, **kwargs):
252 def display_pdf(*objs, **kwargs):
253 """Display the PDF representation of an object.
253 """Display the PDF representation of an object.
254
254
255 Parameters
255 Parameters
256 ----------
256 ----------
257 *objs : object
257 *objs : object
258 The Python objects to display, or if raw=True raw javascript data to
258 The Python objects to display, or if raw=True raw javascript data to
259 display.
259 display.
260 raw : bool
260 raw : bool
261 Are the data objects raw data or Python objects that need to be
261 Are the data objects raw data or Python objects that need to be
262 formatted before display? [default: False]
262 formatted before display? [default: False]
263 metadata : dict (optional)
263 metadata : dict (optional)
264 Metadata to be associated with the specific mimetype output.
264 Metadata to be associated with the specific mimetype output.
265 """
265 """
266 _display_mimetype('application/pdf', objs, **kwargs)
266 _display_mimetype('application/pdf', objs, **kwargs)
267
267
268
268
269 #-----------------------------------------------------------------------------
269 #-----------------------------------------------------------------------------
270 # Smart classes
270 # Smart classes
271 #-----------------------------------------------------------------------------
271 #-----------------------------------------------------------------------------
272
272
273
273
274 class DisplayObject(object):
274 class DisplayObject(object):
275 """An object that wraps data to be displayed."""
275 """An object that wraps data to be displayed."""
276
276
277 _read_flags = 'r'
277 _read_flags = 'r'
278 _show_mem_addr = False
278 _show_mem_addr = False
279 metadata = None
279 metadata = None
280
280
281 def __init__(self, data=None, url=None, filename=None, metadata=None):
281 def __init__(self, data=None, url=None, filename=None, metadata=None):
282 """Create a display object given raw data.
282 """Create a display object given raw data.
283
283
284 When this object is returned by an expression or passed to the
284 When this object is returned by an expression or passed to the
285 display function, it will result in the data being displayed
285 display function, it will result in the data being displayed
286 in the frontend. The MIME type of the data should match the
286 in the frontend. The MIME type of the data should match the
287 subclasses used, so the Png subclass should be used for 'image/png'
287 subclasses used, so the Png subclass should be used for 'image/png'
288 data. If the data is a URL, the data will first be downloaded
288 data. If the data is a URL, the data will first be downloaded
289 and then displayed. If
289 and then displayed. If
290
290
291 Parameters
291 Parameters
292 ----------
292 ----------
293 data : unicode, str or bytes
293 data : unicode, str or bytes
294 The raw data or a URL or file to load the data from
294 The raw data or a URL or file to load the data from
295 url : unicode
295 url : unicode
296 A URL to download the data from.
296 A URL to download the data from.
297 filename : unicode
297 filename : unicode
298 Path to a local file to load the data from.
298 Path to a local file to load the data from.
299 metadata : dict
299 metadata : dict
300 Dict of metadata associated to be the object when displayed
300 Dict of metadata associated to be the object when displayed
301 """
301 """
302 if isinstance(data, (Path, PurePath)):
302 if isinstance(data, (Path, PurePath)):
303 data = str(data)
303 data = str(data)
304
304
305 if data is not None and isinstance(data, str):
305 if data is not None and isinstance(data, str):
306 if data.startswith('http') and url is None:
306 if data.startswith('http') and url is None:
307 url = data
307 url = data
308 filename = None
308 filename = None
309 data = None
309 data = None
310 elif _safe_exists(data) and filename is None:
310 elif _safe_exists(data) and filename is None:
311 url = None
311 url = None
312 filename = data
312 filename = data
313 data = None
313 data = None
314
314
315 self.url = url
315 self.url = url
316 self.filename = filename
316 self.filename = filename
317 # because of @data.setter methods in
317 # because of @data.setter methods in
318 # subclasses ensure url and filename are set
318 # subclasses ensure url and filename are set
319 # before assigning to self.data
319 # before assigning to self.data
320 self.data = data
320 self.data = data
321
321
322 if metadata is not None:
322 if metadata is not None:
323 self.metadata = metadata
323 self.metadata = metadata
324 elif self.metadata is None:
324 elif self.metadata is None:
325 self.metadata = {}
325 self.metadata = {}
326
326
327 self.reload()
327 self.reload()
328 self._check_data()
328 self._check_data()
329
329
330 def __repr__(self):
330 def __repr__(self):
331 if not self._show_mem_addr:
331 if not self._show_mem_addr:
332 cls = self.__class__
332 cls = self.__class__
333 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
333 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
334 else:
334 else:
335 r = super(DisplayObject, self).__repr__()
335 r = super(DisplayObject, self).__repr__()
336 return r
336 return r
337
337
338 def _check_data(self):
338 def _check_data(self):
339 """Override in subclasses if there's something to check."""
339 """Override in subclasses if there's something to check."""
340 pass
340 pass
341
341
342 def _data_and_metadata(self):
342 def _data_and_metadata(self):
343 """shortcut for returning metadata with shape information, if defined"""
343 """shortcut for returning metadata with shape information, if defined"""
344 if self.metadata:
344 if self.metadata:
345 return self.data, deepcopy(self.metadata)
345 return self.data, deepcopy(self.metadata)
346 else:
346 else:
347 return self.data
347 return self.data
348
348
349 def reload(self):
349 def reload(self):
350 """Reload the raw data from file or URL."""
350 """Reload the raw data from file or URL."""
351 if self.filename is not None:
351 if self.filename is not None:
352 encoding = None if "b" in self._read_flags else "utf-8"
352 encoding = None if "b" in self._read_flags else "utf-8"
353 with open(self.filename, self._read_flags, encoding=encoding) as f:
353 with open(self.filename, self._read_flags, encoding=encoding) as f:
354 self.data = f.read()
354 self.data = f.read()
355 elif self.url is not None:
355 elif self.url is not None:
356 # Deferred import
356 # Deferred import
357 from urllib.request import urlopen
357 from urllib.request import urlopen
358 response = urlopen(self.url)
358 response = urlopen(self.url)
359 data = response.read()
359 data = response.read()
360 # extract encoding from header, if there is one:
360 # extract encoding from header, if there is one:
361 encoding = None
361 encoding = None
362 if 'content-type' in response.headers:
362 if 'content-type' in response.headers:
363 for sub in response.headers['content-type'].split(';'):
363 for sub in response.headers['content-type'].split(';'):
364 sub = sub.strip()
364 sub = sub.strip()
365 if sub.startswith('charset'):
365 if sub.startswith('charset'):
366 encoding = sub.split('=')[-1].strip()
366 encoding = sub.split('=')[-1].strip()
367 break
367 break
368 if 'content-encoding' in response.headers:
368 if 'content-encoding' in response.headers:
369 # TODO: do deflate?
369 # TODO: do deflate?
370 if 'gzip' in response.headers['content-encoding']:
370 if 'gzip' in response.headers['content-encoding']:
371 import gzip
371 import gzip
372 from io import BytesIO
372 from io import BytesIO
373
373
374 # assume utf-8 if encoding is not specified
374 # assume utf-8 if encoding is not specified
375 with gzip.open(
375 with gzip.open(
376 BytesIO(data), "rt", encoding=encoding or "utf-8"
376 BytesIO(data), "rt", encoding=encoding or "utf-8"
377 ) as fp:
377 ) as fp:
378 encoding = None
378 encoding = None
379 data = fp.read()
379 data = fp.read()
380
380
381 # decode data, if an encoding was specified
381 # decode data, if an encoding was specified
382 # We only touch self.data once since
382 # We only touch self.data once since
383 # subclasses such as SVG have @data.setter methods
383 # subclasses such as SVG have @data.setter methods
384 # that transform self.data into ... well svg.
384 # that transform self.data into ... well svg.
385 if encoding:
385 if encoding:
386 self.data = data.decode(encoding, 'replace')
386 self.data = data.decode(encoding, 'replace')
387 else:
387 else:
388 self.data = data
388 self.data = data
389
389
390
390
391 class TextDisplayObject(DisplayObject):
391 class TextDisplayObject(DisplayObject):
392 """Create a text display object given raw data.
392 """Create a text display object given raw data.
393
393
394 Parameters
394 Parameters
395 ----------
395 ----------
396 data : str or unicode
396 data : str or unicode
397 The raw data or a URL or file to load the data from.
397 The raw data or a URL or file to load the data from.
398 url : unicode
398 url : unicode
399 A URL to download the data from.
399 A URL to download the data from.
400 filename : unicode
400 filename : unicode
401 Path to a local file to load the data from.
401 Path to a local file to load the data from.
402 metadata : dict
402 metadata : dict
403 Dict of metadata associated to be the object when displayed
403 Dict of metadata associated to be the object when displayed
404 """
404 """
405 def _check_data(self):
405 def _check_data(self):
406 if self.data is not None and not isinstance(self.data, str):
406 if self.data is not None and not isinstance(self.data, str):
407 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
407 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
408
408
409 class Pretty(TextDisplayObject):
409 class Pretty(TextDisplayObject):
410
410
411 def _repr_pretty_(self, pp, cycle):
411 def _repr_pretty_(self, pp, cycle):
412 return pp.text(self.data)
412 return pp.text(self.data)
413
413
414
414
415 class HTML(TextDisplayObject):
415 class HTML(TextDisplayObject):
416
416
417 def __init__(self, data=None, url=None, filename=None, metadata=None):
417 def __init__(self, data=None, url=None, filename=None, metadata=None):
418 def warn():
418 def warn():
419 if not data:
419 if not data:
420 return False
420 return False
421
421
422 #
422 #
423 # Avoid calling lower() on the entire data, because it could be a
423 # Avoid calling lower() on the entire data, because it could be a
424 # long string and we're only interested in its beginning and end.
424 # long string and we're only interested in its beginning and end.
425 #
425 #
426 prefix = data[:10].lower()
426 prefix = data[:10].lower()
427 suffix = data[-10:].lower()
427 suffix = data[-10:].lower()
428 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
428 return prefix.startswith("<iframe ") and suffix.endswith("</iframe>")
429
429
430 if warn():
430 if warn():
431 warnings.warn("Consider using IPython.display.IFrame instead")
431 warnings.warn("Consider using IPython.display.IFrame instead")
432 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
432 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
433
433
434 def _repr_html_(self):
434 def _repr_html_(self):
435 return self._data_and_metadata()
435 return self._data_and_metadata()
436
436
437 def __html__(self):
437 def __html__(self):
438 """
438 """
439 This method exists to inform other HTML-using modules (e.g. Markupsafe,
439 This method exists to inform other HTML-using modules (e.g. Markupsafe,
440 htmltag, etc) that this object is HTML and does not need things like
440 htmltag, etc) that this object is HTML and does not need things like
441 special characters (<>&) escaped.
441 special characters (<>&) escaped.
442 """
442 """
443 return self._repr_html_()
443 return self._repr_html_()
444
444
445
445
446 class Markdown(TextDisplayObject):
446 class Markdown(TextDisplayObject):
447
447
448 def _repr_markdown_(self):
448 def _repr_markdown_(self):
449 return self._data_and_metadata()
449 return self._data_and_metadata()
450
450
451
451
452 class Math(TextDisplayObject):
452 class Math(TextDisplayObject):
453
453
454 def _repr_latex_(self):
454 def _repr_latex_(self):
455 s = r"$\displaystyle %s$" % self.data.strip('$')
455 s = r"$\displaystyle %s$" % self.data.strip('$')
456 if self.metadata:
456 if self.metadata:
457 return s, deepcopy(self.metadata)
457 return s, deepcopy(self.metadata)
458 else:
458 else:
459 return s
459 return s
460
460
461
461
462 class Latex(TextDisplayObject):
462 class Latex(TextDisplayObject):
463
463
464 def _repr_latex_(self):
464 def _repr_latex_(self):
465 return self._data_and_metadata()
465 return self._data_and_metadata()
466
466
467
467
468 class SVG(DisplayObject):
468 class SVG(DisplayObject):
469 """Embed an SVG into the display.
469 """Embed an SVG into the display.
470
470
471 Note if you just want to view a svg image via a URL use `:class:Image` with
471 Note if you just want to view a svg image via a URL use `:class:Image` with
472 a url=URL keyword argument.
472 a url=URL keyword argument.
473 """
473 """
474
474
475 _read_flags = 'rb'
475 _read_flags = 'rb'
476 # wrap data in a property, which extracts the <svg> tag, discarding
476 # wrap data in a property, which extracts the <svg> tag, discarding
477 # document headers
477 # document headers
478 _data = None
478 _data = None
479
479
480 @property
480 @property
481 def data(self):
481 def data(self):
482 return self._data
482 return self._data
483
483
484 @data.setter
484 @data.setter
485 def data(self, svg):
485 def data(self, svg):
486 if svg is None:
486 if svg is None:
487 self._data = None
487 self._data = None
488 return
488 return
489 # parse into dom object
489 # parse into dom object
490 from xml.dom import minidom
490 from xml.dom import minidom
491 x = minidom.parseString(svg)
491 x = minidom.parseString(svg)
492 # get svg tag (should be 1)
492 # get svg tag (should be 1)
493 found_svg = x.getElementsByTagName('svg')
493 found_svg = x.getElementsByTagName('svg')
494 if found_svg:
494 if found_svg:
495 svg = found_svg[0].toxml()
495 svg = found_svg[0].toxml()
496 else:
496 else:
497 # fallback on the input, trust the user
497 # fallback on the input, trust the user
498 # but this is probably an error.
498 # but this is probably an error.
499 pass
499 pass
500 svg = cast_unicode(svg)
500 svg = cast_unicode(svg)
501 self._data = svg
501 self._data = svg
502
502
503 def _repr_svg_(self):
503 def _repr_svg_(self):
504 return self._data_and_metadata()
504 return self._data_and_metadata()
505
505
506 class ProgressBar(DisplayObject):
506 class ProgressBar(DisplayObject):
507 """Progressbar supports displaying a progressbar like element
507 """Progressbar supports displaying a progressbar like element
508 """
508 """
509 def __init__(self, total):
509 def __init__(self, total):
510 """Creates a new progressbar
510 """Creates a new progressbar
511
511
512 Parameters
512 Parameters
513 ----------
513 ----------
514 total : int
514 total : int
515 maximum size of the progressbar
515 maximum size of the progressbar
516 """
516 """
517 self.total = total
517 self.total = total
518 self._progress = 0
518 self._progress = 0
519 self.html_width = '60ex'
519 self.html_width = '60ex'
520 self.text_width = 60
520 self.text_width = 60
521 self._display_id = hexlify(os.urandom(8)).decode('ascii')
521 self._display_id = hexlify(os.urandom(8)).decode('ascii')
522
522
523 def __repr__(self):
523 def __repr__(self):
524 fraction = self.progress / self.total
524 fraction = self.progress / self.total
525 filled = '=' * int(fraction * self.text_width)
525 filled = '=' * int(fraction * self.text_width)
526 rest = ' ' * (self.text_width - len(filled))
526 rest = ' ' * (self.text_width - len(filled))
527 return '[{}{}] {}/{}'.format(
527 return '[{}{}] {}/{}'.format(
528 filled, rest,
528 filled, rest,
529 self.progress, self.total,
529 self.progress, self.total,
530 )
530 )
531
531
532 def _repr_html_(self):
532 def _repr_html_(self):
533 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
533 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
534 self.html_width, self.total, self.progress)
534 self.html_width, self.total, self.progress)
535
535
536 def display(self):
536 def display(self):
537 display_functions.display(self, display_id=self._display_id)
537 display_functions.display(self, display_id=self._display_id)
538
538
539 def update(self):
539 def update(self):
540 display_functions.display(self, display_id=self._display_id, update=True)
540 display_functions.display(self, display_id=self._display_id, update=True)
541
541
542 @property
542 @property
543 def progress(self):
543 def progress(self):
544 return self._progress
544 return self._progress
545
545
546 @progress.setter
546 @progress.setter
547 def progress(self, value):
547 def progress(self, value):
548 self._progress = value
548 self._progress = value
549 self.update()
549 self.update()
550
550
551 def __iter__(self):
551 def __iter__(self):
552 self.display()
552 self.display()
553 self._progress = -1 # First iteration is 0
553 self._progress = -1 # First iteration is 0
554 return self
554 return self
555
555
556 def __next__(self):
556 def __next__(self):
557 """Returns current value and increments display by one."""
557 """Returns current value and increments display by one."""
558 self.progress += 1
558 self.progress += 1
559 if self.progress < self.total:
559 if self.progress < self.total:
560 return self.progress
560 return self.progress
561 else:
561 else:
562 raise StopIteration()
562 raise StopIteration()
563
563
564 class JSON(DisplayObject):
564 class JSON(DisplayObject):
565 """JSON expects a JSON-able dict or list
565 """JSON expects a JSON-able dict or list
566
566
567 not an already-serialized JSON string.
567 not an already-serialized JSON string.
568
568
569 Scalar types (None, number, string) are not allowed, only dict or list containers.
569 Scalar types (None, number, string) are not allowed, only dict or list containers.
570 """
570 """
571 # wrap data in a property, which warns about passing already-serialized JSON
571 # wrap data in a property, which warns about passing already-serialized JSON
572 _data = None
572 _data = None
573 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
573 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
574 """Create a JSON display object given raw data.
574 """Create a JSON display object given raw data.
575
575
576 Parameters
576 Parameters
577 ----------
577 ----------
578 data : dict or list
578 data : dict or list
579 JSON data to display. Not an already-serialized JSON string.
579 JSON data to display. Not an already-serialized JSON string.
580 Scalar types (None, number, string) are not allowed, only dict
580 Scalar types (None, number, string) are not allowed, only dict
581 or list containers.
581 or list containers.
582 url : unicode
582 url : unicode
583 A URL to download the data from.
583 A URL to download the data from.
584 filename : unicode
584 filename : unicode
585 Path to a local file to load the data from.
585 Path to a local file to load the data from.
586 expanded : boolean
586 expanded : boolean
587 Metadata to control whether a JSON display component is expanded.
587 Metadata to control whether a JSON display component is expanded.
588 metadata : dict
588 metadata : dict
589 Specify extra metadata to attach to the json display object.
589 Specify extra metadata to attach to the json display object.
590 root : str
590 root : str
591 The name of the root element of the JSON tree
591 The name of the root element of the JSON tree
592 """
592 """
593 self.metadata = {
593 self.metadata = {
594 'expanded': expanded,
594 'expanded': expanded,
595 'root': root,
595 'root': root,
596 }
596 }
597 if metadata:
597 if metadata:
598 self.metadata.update(metadata)
598 self.metadata.update(metadata)
599 if kwargs:
599 if kwargs:
600 self.metadata.update(kwargs)
600 self.metadata.update(kwargs)
601 super(JSON, self).__init__(data=data, url=url, filename=filename)
601 super(JSON, self).__init__(data=data, url=url, filename=filename)
602
602
603 def _check_data(self):
603 def _check_data(self):
604 if self.data is not None and not isinstance(self.data, (dict, list)):
604 if self.data is not None and not isinstance(self.data, (dict, list)):
605 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
605 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
606
606
607 @property
607 @property
608 def data(self):
608 def data(self):
609 return self._data
609 return self._data
610
610
611 @data.setter
611 @data.setter
612 def data(self, data):
612 def data(self, data):
613 if isinstance(data, (Path, PurePath)):
613 if isinstance(data, (Path, PurePath)):
614 data = str(data)
614 data = str(data)
615
615
616 if isinstance(data, str):
616 if isinstance(data, str):
617 if self.filename is None and self.url is None:
617 if self.filename is None and self.url is None:
618 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
618 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
619 data = json.loads(data)
619 data = json.loads(data)
620 self._data = data
620 self._data = data
621
621
622 def _data_and_metadata(self):
622 def _data_and_metadata(self):
623 return self.data, self.metadata
623 return self.data, self.metadata
624
624
625 def _repr_json_(self):
625 def _repr_json_(self):
626 return self._data_and_metadata()
626 return self._data_and_metadata()
627
627
628
628
629 _css_t = """var link = document.createElement("link");
629 _css_t = """var link = document.createElement("link");
630 link.rel = "stylesheet";
630 link.rel = "stylesheet";
631 link.type = "text/css";
631 link.type = "text/css";
632 link.href = "%s";
632 link.href = "%s";
633 document.head.appendChild(link);
633 document.head.appendChild(link);
634 """
634 """
635
635
636 _lib_t1 = """new Promise(function(resolve, reject) {
636 _lib_t1 = """new Promise(function(resolve, reject) {
637 var script = document.createElement("script");
637 var script = document.createElement("script");
638 script.onload = resolve;
638 script.onload = resolve;
639 script.onerror = reject;
639 script.onerror = reject;
640 script.src = "%s";
640 script.src = "%s";
641 document.head.appendChild(script);
641 document.head.appendChild(script);
642 }).then(() => {
642 }).then(() => {
643 """
643 """
644
644
645 _lib_t2 = """
645 _lib_t2 = """
646 });"""
646 });"""
647
647
648 class GeoJSON(JSON):
648 class GeoJSON(JSON):
649 """GeoJSON expects JSON-able dict
649 """GeoJSON expects JSON-able dict
650
650
651 not an already-serialized JSON string.
651 not an already-serialized JSON string.
652
652
653 Scalar types (None, number, string) are not allowed, only dict containers.
653 Scalar types (None, number, string) are not allowed, only dict containers.
654 """
654 """
655
655
656 def __init__(self, *args, **kwargs):
656 def __init__(self, *args, **kwargs):
657 """Create a GeoJSON display object given raw data.
657 """Create a GeoJSON display object given raw data.
658
658
659 Parameters
659 Parameters
660 ----------
660 ----------
661 data : dict or list
661 data : dict or list
662 VegaLite data. Not an already-serialized JSON string.
662 VegaLite data. Not an already-serialized JSON string.
663 Scalar types (None, number, string) are not allowed, only dict
663 Scalar types (None, number, string) are not allowed, only dict
664 or list containers.
664 or list containers.
665 url_template : string
665 url_template : string
666 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
666 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
667 layer_options : dict
667 layer_options : dict
668 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
668 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
669 url : unicode
669 url : unicode
670 A URL to download the data from.
670 A URL to download the data from.
671 filename : unicode
671 filename : unicode
672 Path to a local file to load the data from.
672 Path to a local file to load the data from.
673 metadata : dict
673 metadata : dict
674 Specify extra metadata to attach to the json display object.
674 Specify extra metadata to attach to the json display object.
675
675
676 Examples
676 Examples
677 --------
677 --------
678 The following will display an interactive map of Mars with a point of
678 The following will display an interactive map of Mars with a point of
679 interest on frontend that do support GeoJSON display.
679 interest on frontend that do support GeoJSON display.
680
680
681 >>> from IPython.display import GeoJSON
681 >>> from IPython.display import GeoJSON
682
682
683 >>> GeoJSON(data={
683 >>> GeoJSON(data={
684 ... "type": "Feature",
684 ... "type": "Feature",
685 ... "geometry": {
685 ... "geometry": {
686 ... "type": "Point",
686 ... "type": "Point",
687 ... "coordinates": [-81.327, 296.038]
687 ... "coordinates": [-81.327, 296.038]
688 ... }
688 ... }
689 ... },
689 ... },
690 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
690 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
691 ... layer_options={
691 ... layer_options={
692 ... "basemap_id": "celestia_mars-shaded-16k_global",
692 ... "basemap_id": "celestia_mars-shaded-16k_global",
693 ... "attribution" : "Celestia/praesepe",
693 ... "attribution" : "Celestia/praesepe",
694 ... "minZoom" : 0,
694 ... "minZoom" : 0,
695 ... "maxZoom" : 18,
695 ... "maxZoom" : 18,
696 ... })
696 ... })
697 <IPython.core.display.GeoJSON object>
697 <IPython.core.display.GeoJSON object>
698
698
699 In the terminal IPython, you will only see the text representation of
699 In the terminal IPython, you will only see the text representation of
700 the GeoJSON object.
700 the GeoJSON object.
701
701
702 """
702 """
703
703
704 super(GeoJSON, self).__init__(*args, **kwargs)
704 super(GeoJSON, self).__init__(*args, **kwargs)
705
705
706
706
707 def _ipython_display_(self):
707 def _ipython_display_(self):
708 bundle = {
708 bundle = {
709 'application/geo+json': self.data,
709 'application/geo+json': self.data,
710 'text/plain': '<IPython.display.GeoJSON object>'
710 'text/plain': '<IPython.display.GeoJSON object>'
711 }
711 }
712 metadata = {
712 metadata = {
713 'application/geo+json': self.metadata
713 'application/geo+json': self.metadata
714 }
714 }
715 display_functions.display(bundle, metadata=metadata, raw=True)
715 display_functions.display(bundle, metadata=metadata, raw=True)
716
716
717 class Javascript(TextDisplayObject):
717 class Javascript(TextDisplayObject):
718
718
719 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
719 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
720 """Create a Javascript display object given raw data.
720 """Create a Javascript display object given raw data.
721
721
722 When this object is returned by an expression or passed to the
722 When this object is returned by an expression or passed to the
723 display function, it will result in the data being displayed
723 display function, it will result in the data being displayed
724 in the frontend. If the data is a URL, the data will first be
724 in the frontend. If the data is a URL, the data will first be
725 downloaded and then displayed.
725 downloaded and then displayed.
726
726
727 In the Notebook, the containing element will be available as `element`,
727 In the Notebook, the containing element will be available as `element`,
728 and jQuery will be available. Content appended to `element` will be
728 and jQuery will be available. Content appended to `element` will be
729 visible in the output area.
729 visible in the output area.
730
730
731 Parameters
731 Parameters
732 ----------
732 ----------
733 data : unicode, str or bytes
733 data : unicode, str or bytes
734 The Javascript source code or a URL to download it from.
734 The Javascript source code or a URL to download it from.
735 url : unicode
735 url : unicode
736 A URL to download the data from.
736 A URL to download the data from.
737 filename : unicode
737 filename : unicode
738 Path to a local file to load the data from.
738 Path to a local file to load the data from.
739 lib : list or str
739 lib : list or str
740 A sequence of Javascript library URLs to load asynchronously before
740 A sequence of Javascript library URLs to load asynchronously before
741 running the source code. The full URLs of the libraries should
741 running the source code. The full URLs of the libraries should
742 be given. A single Javascript library URL can also be given as a
742 be given. A single Javascript library URL can also be given as a
743 string.
743 string.
744 css : list or str
744 css : list or str
745 A sequence of css files to load before running the source code.
745 A sequence of css files to load before running the source code.
746 The full URLs of the css files should be given. A single css URL
746 The full URLs of the css files should be given. A single css URL
747 can also be given as a string.
747 can also be given as a string.
748 """
748 """
749 if isinstance(lib, str):
749 if isinstance(lib, str):
750 lib = [lib]
750 lib = [lib]
751 elif lib is None:
751 elif lib is None:
752 lib = []
752 lib = []
753 if isinstance(css, str):
753 if isinstance(css, str):
754 css = [css]
754 css = [css]
755 elif css is None:
755 elif css is None:
756 css = []
756 css = []
757 if not isinstance(lib, (list,tuple)):
757 if not isinstance(lib, (list,tuple)):
758 raise TypeError('expected sequence, got: %r' % lib)
758 raise TypeError('expected sequence, got: %r' % lib)
759 if not isinstance(css, (list,tuple)):
759 if not isinstance(css, (list,tuple)):
760 raise TypeError('expected sequence, got: %r' % css)
760 raise TypeError('expected sequence, got: %r' % css)
761 self.lib = lib
761 self.lib = lib
762 self.css = css
762 self.css = css
763 super(Javascript, self).__init__(data=data, url=url, filename=filename)
763 super(Javascript, self).__init__(data=data, url=url, filename=filename)
764
764
765 def _repr_javascript_(self):
765 def _repr_javascript_(self):
766 r = ''
766 r = ''
767 for c in self.css:
767 for c in self.css:
768 r += _css_t % c
768 r += _css_t % c
769 for l in self.lib:
769 for l in self.lib:
770 r += _lib_t1 % l
770 r += _lib_t1 % l
771 r += self.data
771 r += self.data
772 r += _lib_t2*len(self.lib)
772 r += _lib_t2*len(self.lib)
773 return r
773 return r
774
774
775 # constants for identifying png/jpeg data
775 # constants for identifying png/jpeg data
776 _PNG = b'\x89PNG\r\n\x1a\n'
776 _PNG = b'\x89PNG\r\n\x1a\n'
777 _JPEG = b'\xff\xd8'
777 _JPEG = b'\xff\xd8'
778
778
779 def _pngxy(data):
779 def _pngxy(data):
780 """read the (width, height) from a PNG header"""
780 """read the (width, height) from a PNG header"""
781 ihdr = data.index(b'IHDR')
781 ihdr = data.index(b'IHDR')
782 # next 8 bytes are width/height
782 # next 8 bytes are width/height
783 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
783 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
784
784
785 def _jpegxy(data):
785 def _jpegxy(data):
786 """read the (width, height) from a JPEG header"""
786 """read the (width, height) from a JPEG header"""
787 # adapted from http://www.64lines.com/jpeg-width-height
787 # adapted from http://www.64lines.com/jpeg-width-height
788
788
789 idx = 4
789 idx = 4
790 while True:
790 while True:
791 block_size = struct.unpack('>H', data[idx:idx+2])[0]
791 block_size = struct.unpack('>H', data[idx:idx+2])[0]
792 idx = idx + block_size
792 idx = idx + block_size
793 if data[idx:idx+2] == b'\xFF\xC0':
793 if data[idx:idx+2] == b'\xFF\xC0':
794 # found Start of Frame
794 # found Start of Frame
795 iSOF = idx
795 iSOF = idx
796 break
796 break
797 else:
797 else:
798 # read another block
798 # read another block
799 idx += 2
799 idx += 2
800
800
801 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
801 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
802 return w, h
802 return w, h
803
803
804 def _gifxy(data):
804 def _gifxy(data):
805 """read the (width, height) from a GIF header"""
805 """read the (width, height) from a GIF header"""
806 return struct.unpack('<HH', data[6:10])
806 return struct.unpack('<HH', data[6:10])
807
807
808
808
809 class Image(DisplayObject):
809 class Image(DisplayObject):
810
810
811 _read_flags = 'rb'
811 _read_flags = 'rb'
812 _FMT_JPEG = u'jpeg'
812 _FMT_JPEG = u'jpeg'
813 _FMT_PNG = u'png'
813 _FMT_PNG = u'png'
814 _FMT_GIF = u'gif'
814 _FMT_GIF = u'gif'
815 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
815 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
816 _MIMETYPES = {
816 _MIMETYPES = {
817 _FMT_PNG: 'image/png',
817 _FMT_PNG: 'image/png',
818 _FMT_JPEG: 'image/jpeg',
818 _FMT_JPEG: 'image/jpeg',
819 _FMT_GIF: 'image/gif',
819 _FMT_GIF: 'image/gif',
820 }
820 }
821
821
822 def __init__(
822 def __init__(
823 self,
823 self,
824 data=None,
824 data=None,
825 url=None,
825 url=None,
826 filename=None,
826 filename=None,
827 format=None,
827 format=None,
828 embed=None,
828 embed=None,
829 width=None,
829 width=None,
830 height=None,
830 height=None,
831 retina=False,
831 retina=False,
832 unconfined=False,
832 unconfined=False,
833 metadata=None,
833 metadata=None,
834 alt=None,
834 alt=None,
835 ):
835 ):
836 """Create a PNG/JPEG/GIF image object given raw data.
836 """Create a PNG/JPEG/GIF image object given raw data.
837
837
838 When this object is returned by an input cell or passed to the
838 When this object is returned by an input cell or passed to the
839 display function, it will result in the image being displayed
839 display function, it will result in the image being displayed
840 in the frontend.
840 in the frontend.
841
841
842 Parameters
842 Parameters
843 ----------
843 ----------
844 data : unicode, str or bytes
844 data : unicode, str or bytes
845 The raw image data or a URL or filename to load the data from.
845 The raw image data or a URL or filename to load the data from.
846 This always results in embedded image data.
846 This always results in embedded image data.
847
847
848 url : unicode
848 url : unicode
849 A URL to download the data from. If you specify `url=`,
849 A URL to download the data from. If you specify `url=`,
850 the image data will not be embedded unless you also specify `embed=True`.
850 the image data will not be embedded unless you also specify `embed=True`.
851
851
852 filename : unicode
852 filename : unicode
853 Path to a local file to load the data from.
853 Path to a local file to load the data from.
854 Images from a file are always embedded.
854 Images from a file are always embedded.
855
855
856 format : unicode
856 format : unicode
857 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
857 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
858 for format will be inferred from the filename extension.
858 for format will be inferred from the filename extension.
859
859
860 embed : bool
860 embed : bool
861 Should the image data be embedded using a data URI (True) or be
861 Should the image data be embedded using a data URI (True) or be
862 loaded using an <img> tag. Set this to True if you want the image
862 loaded using an <img> tag. Set this to True if you want the image
863 to be viewable later with no internet connection in the notebook.
863 to be viewable later with no internet connection in the notebook.
864
864
865 Default is `True`, unless the keyword argument `url` is set, then
865 Default is `True`, unless the keyword argument `url` is set, then
866 default value is `False`.
866 default value is `False`.
867
867
868 Note that QtConsole is not able to display images if `embed` is set to `False`
868 Note that QtConsole is not able to display images if `embed` is set to `False`
869
869
870 width : int
870 width : int
871 Width in pixels to which to constrain the image in html
871 Width in pixels to which to constrain the image in html
872
872
873 height : int
873 height : int
874 Height in pixels to which to constrain the image in html
874 Height in pixels to which to constrain the image in html
875
875
876 retina : bool
876 retina : bool
877 Automatically set the width and height to half of the measured
877 Automatically set the width and height to half of the measured
878 width and height.
878 width and height.
879 This only works for embedded images because it reads the width/height
879 This only works for embedded images because it reads the width/height
880 from image data.
880 from image data.
881 For non-embedded images, you can just set the desired display width
881 For non-embedded images, you can just set the desired display width
882 and height directly.
882 and height directly.
883
883
884 unconfined : bool
884 unconfined : bool
885 Set unconfined=True to disable max-width confinement of the image.
885 Set unconfined=True to disable max-width confinement of the image.
886
886
887 metadata : dict
887 metadata : dict
888 Specify extra metadata to attach to the image.
888 Specify extra metadata to attach to the image.
889
889
890 alt : unicode
890 alt : unicode
891 Alternative text for the image, for use by screen readers.
891 Alternative text for the image, for use by screen readers.
892
892
893 Examples
893 Examples
894 --------
894 --------
895 embedded image data, works in qtconsole and notebook
895 embedded image data, works in qtconsole and notebook
896 when passed positionally, the first arg can be any of raw image data,
896 when passed positionally, the first arg can be any of raw image data,
897 a URL, or a filename from which to load image data.
897 a URL, or a filename from which to load image data.
898 The result is always embedding image data for inline images.
898 The result is always embedding image data for inline images.
899
899
900 >>> Image('https://www.google.fr/images/srpr/logo3w.png') # doctest: +SKIP
900 >>> Image('https://www.google.fr/images/srpr/logo3w.png') # doctest: +SKIP
901 <IPython.core.display.Image object>
901 <IPython.core.display.Image object>
902
902
903 >>> Image('/path/to/image.jpg')
903 >>> Image('/path/to/image.jpg')
904 <IPython.core.display.Image object>
904 <IPython.core.display.Image object>
905
905
906 >>> Image(b'RAW_PNG_DATA...')
906 >>> Image(b'RAW_PNG_DATA...')
907 <IPython.core.display.Image object>
907 <IPython.core.display.Image object>
908
908
909 Specifying Image(url=...) does not embed the image data,
909 Specifying Image(url=...) does not embed the image data,
910 it only generates ``<img>`` tag with a link to the source.
910 it only generates ``<img>`` tag with a link to the source.
911 This will not work in the qtconsole or offline.
911 This will not work in the qtconsole or offline.
912
912
913 >>> Image(url='https://www.google.fr/images/srpr/logo3w.png')
913 >>> Image(url='https://www.google.fr/images/srpr/logo3w.png')
914 <IPython.core.display.Image object>
914 <IPython.core.display.Image object>
915
915
916 """
916 """
917 if isinstance(data, (Path, PurePath)):
917 if isinstance(data, (Path, PurePath)):
918 data = str(data)
918 data = str(data)
919
919
920 if filename is not None:
920 if filename is not None:
921 ext = self._find_ext(filename)
921 ext = self._find_ext(filename)
922 elif url is not None:
922 elif url is not None:
923 ext = self._find_ext(url)
923 ext = self._find_ext(url)
924 elif data is None:
924 elif data is None:
925 raise ValueError("No image data found. Expecting filename, url, or data.")
925 raise ValueError("No image data found. Expecting filename, url, or data.")
926 elif isinstance(data, str) and (
926 elif isinstance(data, str) and (
927 data.startswith('http') or _safe_exists(data)
927 data.startswith('http') or _safe_exists(data)
928 ):
928 ):
929 ext = self._find_ext(data)
929 ext = self._find_ext(data)
930 else:
930 else:
931 ext = None
931 ext = None
932
932
933 if format is None:
933 if format is None:
934 if ext is not None:
934 if ext is not None:
935 if ext == u'jpg' or ext == u'jpeg':
935 if ext == u'jpg' or ext == u'jpeg':
936 format = self._FMT_JPEG
936 format = self._FMT_JPEG
937 elif ext == u'png':
937 elif ext == u'png':
938 format = self._FMT_PNG
938 format = self._FMT_PNG
939 elif ext == u'gif':
939 elif ext == u'gif':
940 format = self._FMT_GIF
940 format = self._FMT_GIF
941 else:
941 else:
942 format = ext.lower()
942 format = ext.lower()
943 elif isinstance(data, bytes):
943 elif isinstance(data, bytes):
944 # infer image type from image data header,
944 # infer image type from image data header,
945 # only if format has not been specified.
945 # only if format has not been specified.
946 if data[:2] == _JPEG:
946 if data[:2] == _JPEG:
947 format = self._FMT_JPEG
947 format = self._FMT_JPEG
948
948
949 # failed to detect format, default png
949 # failed to detect format, default png
950 if format is None:
950 if format is None:
951 format = self._FMT_PNG
951 format = self._FMT_PNG
952
952
953 if format.lower() == 'jpg':
953 if format.lower() == 'jpg':
954 # jpg->jpeg
954 # jpg->jpeg
955 format = self._FMT_JPEG
955 format = self._FMT_JPEG
956
956
957 self.format = format.lower()
957 self.format = format.lower()
958 self.embed = embed if embed is not None else (url is None)
958 self.embed = embed if embed is not None else (url is None)
959
959
960 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
960 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
961 raise ValueError("Cannot embed the '%s' image format" % (self.format))
961 raise ValueError("Cannot embed the '%s' image format" % (self.format))
962 if self.embed:
962 if self.embed:
963 self._mimetype = self._MIMETYPES.get(self.format)
963 self._mimetype = self._MIMETYPES.get(self.format)
964
964
965 self.width = width
965 self.width = width
966 self.height = height
966 self.height = height
967 self.retina = retina
967 self.retina = retina
968 self.unconfined = unconfined
968 self.unconfined = unconfined
969 self.alt = alt
969 self.alt = alt
970 super(Image, self).__init__(data=data, url=url, filename=filename,
970 super(Image, self).__init__(data=data, url=url, filename=filename,
971 metadata=metadata)
971 metadata=metadata)
972
972
973 if self.width is None and self.metadata.get('width', {}):
973 if self.width is None and self.metadata.get('width', {}):
974 self.width = metadata['width']
974 self.width = metadata['width']
975
975
976 if self.height is None and self.metadata.get('height', {}):
976 if self.height is None and self.metadata.get('height', {}):
977 self.height = metadata['height']
977 self.height = metadata['height']
978
978
979 if self.alt is None and self.metadata.get("alt", {}):
979 if self.alt is None and self.metadata.get("alt", {}):
980 self.alt = metadata["alt"]
980 self.alt = metadata["alt"]
981
981
982 if retina:
982 if retina:
983 self._retina_shape()
983 self._retina_shape()
984
984
985
985
986 def _retina_shape(self):
986 def _retina_shape(self):
987 """load pixel-doubled width and height from image data"""
987 """load pixel-doubled width and height from image data"""
988 if not self.embed:
988 if not self.embed:
989 return
989 return
990 if self.format == self._FMT_PNG:
990 if self.format == self._FMT_PNG:
991 w, h = _pngxy(self.data)
991 w, h = _pngxy(self.data)
992 elif self.format == self._FMT_JPEG:
992 elif self.format == self._FMT_JPEG:
993 w, h = _jpegxy(self.data)
993 w, h = _jpegxy(self.data)
994 elif self.format == self._FMT_GIF:
994 elif self.format == self._FMT_GIF:
995 w, h = _gifxy(self.data)
995 w, h = _gifxy(self.data)
996 else:
996 else:
997 # retina only supports png
997 # retina only supports png
998 return
998 return
999 self.width = w // 2
999 self.width = w // 2
1000 self.height = h // 2
1000 self.height = h // 2
1001
1001
1002 def reload(self):
1002 def reload(self):
1003 """Reload the raw data from file or URL."""
1003 """Reload the raw data from file or URL."""
1004 if self.embed:
1004 if self.embed:
1005 super(Image,self).reload()
1005 super(Image,self).reload()
1006 if self.retina:
1006 if self.retina:
1007 self._retina_shape()
1007 self._retina_shape()
1008
1008
1009 def _repr_html_(self):
1009 def _repr_html_(self):
1010 if not self.embed:
1010 if not self.embed:
1011 width = height = klass = alt = ""
1011 width = height = klass = alt = ""
1012 if self.width:
1012 if self.width:
1013 width = ' width="%d"' % self.width
1013 width = ' width="%d"' % self.width
1014 if self.height:
1014 if self.height:
1015 height = ' height="%d"' % self.height
1015 height = ' height="%d"' % self.height
1016 if self.unconfined:
1016 if self.unconfined:
1017 klass = ' class="unconfined"'
1017 klass = ' class="unconfined"'
1018 if self.alt:
1018 if self.alt:
1019 alt = ' alt="%s"' % html.escape(self.alt)
1019 alt = ' alt="%s"' % html.escape(self.alt)
1020 return '<img src="{url}"{width}{height}{klass}{alt}/>'.format(
1020 return '<img src="{url}"{width}{height}{klass}{alt}/>'.format(
1021 url=self.url,
1021 url=self.url,
1022 width=width,
1022 width=width,
1023 height=height,
1023 height=height,
1024 klass=klass,
1024 klass=klass,
1025 alt=alt,
1025 alt=alt,
1026 )
1026 )
1027
1027
1028 def _repr_mimebundle_(self, include=None, exclude=None):
1028 def _repr_mimebundle_(self, include=None, exclude=None):
1029 """Return the image as a mimebundle
1029 """Return the image as a mimebundle
1030
1030
1031 Any new mimetype support should be implemented here.
1031 Any new mimetype support should be implemented here.
1032 """
1032 """
1033 if self.embed:
1033 if self.embed:
1034 mimetype = self._mimetype
1034 mimetype = self._mimetype
1035 data, metadata = self._data_and_metadata(always_both=True)
1035 data, metadata = self._data_and_metadata(always_both=True)
1036 if metadata:
1036 if metadata:
1037 metadata = {mimetype: metadata}
1037 metadata = {mimetype: metadata}
1038 return {mimetype: data}, metadata
1038 return {mimetype: data}, metadata
1039 else:
1039 else:
1040 return {'text/html': self._repr_html_()}
1040 return {'text/html': self._repr_html_()}
1041
1041
1042 def _data_and_metadata(self, always_both=False):
1042 def _data_and_metadata(self, always_both=False):
1043 """shortcut for returning metadata with shape information, if defined"""
1043 """shortcut for returning metadata with shape information, if defined"""
1044 try:
1044 try:
1045 b64_data = b2a_base64(self.data).decode('ascii')
1045 b64_data = b2a_base64(self.data, newline=False).decode("ascii")
1046 except TypeError as e:
1046 except TypeError as e:
1047 raise FileNotFoundError(
1047 raise FileNotFoundError(
1048 "No such file or directory: '%s'" % (self.data)) from e
1048 "No such file or directory: '%s'" % (self.data)) from e
1049 md = {}
1049 md = {}
1050 if self.metadata:
1050 if self.metadata:
1051 md.update(self.metadata)
1051 md.update(self.metadata)
1052 if self.width:
1052 if self.width:
1053 md['width'] = self.width
1053 md['width'] = self.width
1054 if self.height:
1054 if self.height:
1055 md['height'] = self.height
1055 md['height'] = self.height
1056 if self.unconfined:
1056 if self.unconfined:
1057 md['unconfined'] = self.unconfined
1057 md['unconfined'] = self.unconfined
1058 if self.alt:
1058 if self.alt:
1059 md["alt"] = self.alt
1059 md["alt"] = self.alt
1060 if md or always_both:
1060 if md or always_both:
1061 return b64_data, md
1061 return b64_data, md
1062 else:
1062 else:
1063 return b64_data
1063 return b64_data
1064
1064
1065 def _repr_png_(self):
1065 def _repr_png_(self):
1066 if self.embed and self.format == self._FMT_PNG:
1066 if self.embed and self.format == self._FMT_PNG:
1067 return self._data_and_metadata()
1067 return self._data_and_metadata()
1068
1068
1069 def _repr_jpeg_(self):
1069 def _repr_jpeg_(self):
1070 if self.embed and self.format == self._FMT_JPEG:
1070 if self.embed and self.format == self._FMT_JPEG:
1071 return self._data_and_metadata()
1071 return self._data_and_metadata()
1072
1072
1073 def _find_ext(self, s):
1073 def _find_ext(self, s):
1074 base, ext = splitext(s)
1074 base, ext = splitext(s)
1075
1075
1076 if not ext:
1076 if not ext:
1077 return base
1077 return base
1078
1078
1079 # `splitext` includes leading period, so we skip it
1079 # `splitext` includes leading period, so we skip it
1080 return ext[1:].lower()
1080 return ext[1:].lower()
1081
1081
1082
1082
1083 class Video(DisplayObject):
1083 class Video(DisplayObject):
1084
1084
1085 def __init__(self, data=None, url=None, filename=None, embed=False,
1085 def __init__(self, data=None, url=None, filename=None, embed=False,
1086 mimetype=None, width=None, height=None, html_attributes="controls"):
1086 mimetype=None, width=None, height=None, html_attributes="controls"):
1087 """Create a video object given raw data or an URL.
1087 """Create a video object given raw data or an URL.
1088
1088
1089 When this object is returned by an input cell or passed to the
1089 When this object is returned by an input cell or passed to the
1090 display function, it will result in the video being displayed
1090 display function, it will result in the video being displayed
1091 in the frontend.
1091 in the frontend.
1092
1092
1093 Parameters
1093 Parameters
1094 ----------
1094 ----------
1095 data : unicode, str or bytes
1095 data : unicode, str or bytes
1096 The raw video data or a URL or filename to load the data from.
1096 The raw video data or a URL or filename to load the data from.
1097 Raw data will require passing ``embed=True``.
1097 Raw data will require passing ``embed=True``.
1098
1098
1099 url : unicode
1099 url : unicode
1100 A URL for the video. If you specify ``url=``,
1100 A URL for the video. If you specify ``url=``,
1101 the image data will not be embedded.
1101 the image data will not be embedded.
1102
1102
1103 filename : unicode
1103 filename : unicode
1104 Path to a local file containing the video.
1104 Path to a local file containing the video.
1105 Will be interpreted as a local URL unless ``embed=True``.
1105 Will be interpreted as a local URL unless ``embed=True``.
1106
1106
1107 embed : bool
1107 embed : bool
1108 Should the video be embedded using a data URI (True) or be
1108 Should the video be embedded using a data URI (True) or be
1109 loaded using a <video> tag (False).
1109 loaded using a <video> tag (False).
1110
1110
1111 Since videos are large, embedding them should be avoided, if possible.
1111 Since videos are large, embedding them should be avoided, if possible.
1112 You must confirm embedding as your intention by passing ``embed=True``.
1112 You must confirm embedding as your intention by passing ``embed=True``.
1113
1113
1114 Local files can be displayed with URLs without embedding the content, via::
1114 Local files can be displayed with URLs without embedding the content, via::
1115
1115
1116 Video('./video.mp4')
1116 Video('./video.mp4')
1117
1117
1118 mimetype : unicode
1118 mimetype : unicode
1119 Specify the mimetype for embedded videos.
1119 Specify the mimetype for embedded videos.
1120 Default will be guessed from file extension, if available.
1120 Default will be guessed from file extension, if available.
1121
1121
1122 width : int
1122 width : int
1123 Width in pixels to which to constrain the video in HTML.
1123 Width in pixels to which to constrain the video in HTML.
1124 If not supplied, defaults to the width of the video.
1124 If not supplied, defaults to the width of the video.
1125
1125
1126 height : int
1126 height : int
1127 Height in pixels to which to constrain the video in html.
1127 Height in pixels to which to constrain the video in html.
1128 If not supplied, defaults to the height of the video.
1128 If not supplied, defaults to the height of the video.
1129
1129
1130 html_attributes : str
1130 html_attributes : str
1131 Attributes for the HTML ``<video>`` block.
1131 Attributes for the HTML ``<video>`` block.
1132 Default: ``"controls"`` to get video controls.
1132 Default: ``"controls"`` to get video controls.
1133 Other examples: ``"controls muted"`` for muted video with controls,
1133 Other examples: ``"controls muted"`` for muted video with controls,
1134 ``"loop autoplay"`` for looping autoplaying video without controls.
1134 ``"loop autoplay"`` for looping autoplaying video without controls.
1135
1135
1136 Examples
1136 Examples
1137 --------
1137 --------
1138 ::
1138 ::
1139
1139
1140 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1140 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1141 Video('path/to/video.mp4')
1141 Video('path/to/video.mp4')
1142 Video('path/to/video.mp4', embed=True)
1142 Video('path/to/video.mp4', embed=True)
1143 Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1143 Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1144 Video(b'raw-videodata', embed=True)
1144 Video(b'raw-videodata', embed=True)
1145 """
1145 """
1146 if isinstance(data, (Path, PurePath)):
1146 if isinstance(data, (Path, PurePath)):
1147 data = str(data)
1147 data = str(data)
1148
1148
1149 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1149 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1150 url = data
1150 url = data
1151 data = None
1151 data = None
1152 elif data is not None and os.path.exists(data):
1152 elif data is not None and os.path.exists(data):
1153 filename = data
1153 filename = data
1154 data = None
1154 data = None
1155
1155
1156 if data and not embed:
1156 if data and not embed:
1157 msg = ''.join([
1157 msg = ''.join([
1158 "To embed videos, you must pass embed=True ",
1158 "To embed videos, you must pass embed=True ",
1159 "(this may make your notebook files huge)\n",
1159 "(this may make your notebook files huge)\n",
1160 "Consider passing Video(url='...')",
1160 "Consider passing Video(url='...')",
1161 ])
1161 ])
1162 raise ValueError(msg)
1162 raise ValueError(msg)
1163
1163
1164 self.mimetype = mimetype
1164 self.mimetype = mimetype
1165 self.embed = embed
1165 self.embed = embed
1166 self.width = width
1166 self.width = width
1167 self.height = height
1167 self.height = height
1168 self.html_attributes = html_attributes
1168 self.html_attributes = html_attributes
1169 super(Video, self).__init__(data=data, url=url, filename=filename)
1169 super(Video, self).__init__(data=data, url=url, filename=filename)
1170
1170
1171 def _repr_html_(self):
1171 def _repr_html_(self):
1172 width = height = ''
1172 width = height = ''
1173 if self.width:
1173 if self.width:
1174 width = ' width="%d"' % self.width
1174 width = ' width="%d"' % self.width
1175 if self.height:
1175 if self.height:
1176 height = ' height="%d"' % self.height
1176 height = ' height="%d"' % self.height
1177
1177
1178 # External URLs and potentially local files are not embedded into the
1178 # External URLs and potentially local files are not embedded into the
1179 # notebook output.
1179 # notebook output.
1180 if not self.embed:
1180 if not self.embed:
1181 url = self.url if self.url is not None else self.filename
1181 url = self.url if self.url is not None else self.filename
1182 output = """<video src="{0}" {1} {2} {3}>
1182 output = """<video src="{0}" {1} {2} {3}>
1183 Your browser does not support the <code>video</code> element.
1183 Your browser does not support the <code>video</code> element.
1184 </video>""".format(url, self.html_attributes, width, height)
1184 </video>""".format(url, self.html_attributes, width, height)
1185 return output
1185 return output
1186
1186
1187 # Embedded videos are base64-encoded.
1187 # Embedded videos are base64-encoded.
1188 mimetype = self.mimetype
1188 mimetype = self.mimetype
1189 if self.filename is not None:
1189 if self.filename is not None:
1190 if not mimetype:
1190 if not mimetype:
1191 mimetype, _ = mimetypes.guess_type(self.filename)
1191 mimetype, _ = mimetypes.guess_type(self.filename)
1192
1192
1193 with open(self.filename, 'rb') as f:
1193 with open(self.filename, 'rb') as f:
1194 video = f.read()
1194 video = f.read()
1195 else:
1195 else:
1196 video = self.data
1196 video = self.data
1197 if isinstance(video, str):
1197 if isinstance(video, str):
1198 # unicode input is already b64-encoded
1198 # unicode input is already b64-encoded
1199 b64_video = video
1199 b64_video = video
1200 else:
1200 else:
1201 b64_video = b2a_base64(video).decode('ascii').rstrip()
1201 b64_video = b2a_base64(video, newline=False).decode("ascii").rstrip()
1202
1202
1203 output = """<video {0} {1} {2}>
1203 output = """<video {0} {1} {2}>
1204 <source src="data:{3};base64,{4}" type="{3}">
1204 <source src="data:{3};base64,{4}" type="{3}">
1205 Your browser does not support the video tag.
1205 Your browser does not support the video tag.
1206 </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1206 </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1207 return output
1207 return output
1208
1208
1209 def reload(self):
1209 def reload(self):
1210 # TODO
1210 # TODO
1211 pass
1211 pass
1212
1212
1213
1213
1214 @skip_doctest
1214 @skip_doctest
1215 def set_matplotlib_formats(*formats, **kwargs):
1215 def set_matplotlib_formats(*formats, **kwargs):
1216 """
1216 """
1217 .. deprecated:: 7.23
1217 .. deprecated:: 7.23
1218
1218
1219 use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
1219 use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
1220
1220
1221 Select figure formats for the inline backend. Optionally pass quality for JPEG.
1221 Select figure formats for the inline backend. Optionally pass quality for JPEG.
1222
1222
1223 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1223 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1224
1224
1225 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1225 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1226
1226
1227 To set this in your config files use the following::
1227 To set this in your config files use the following::
1228
1228
1229 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1229 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1230 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1230 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1231
1231
1232 Parameters
1232 Parameters
1233 ----------
1233 ----------
1234 *formats : strs
1234 *formats : strs
1235 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1235 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1236 **kwargs
1236 **kwargs
1237 Keyword args will be relayed to ``figure.canvas.print_figure``.
1237 Keyword args will be relayed to ``figure.canvas.print_figure``.
1238 """
1238 """
1239 warnings.warn(
1239 warnings.warn(
1240 "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
1240 "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
1241 "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
1241 "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
1242 DeprecationWarning,
1242 DeprecationWarning,
1243 stacklevel=2,
1243 stacklevel=2,
1244 )
1244 )
1245
1245
1246 from matplotlib_inline.backend_inline import (
1246 from matplotlib_inline.backend_inline import (
1247 set_matplotlib_formats as set_matplotlib_formats_orig,
1247 set_matplotlib_formats as set_matplotlib_formats_orig,
1248 )
1248 )
1249
1249
1250 set_matplotlib_formats_orig(*formats, **kwargs)
1250 set_matplotlib_formats_orig(*formats, **kwargs)
1251
1251
1252 @skip_doctest
1252 @skip_doctest
1253 def set_matplotlib_close(close=True):
1253 def set_matplotlib_close(close=True):
1254 """
1254 """
1255 .. deprecated:: 7.23
1255 .. deprecated:: 7.23
1256
1256
1257 use `matplotlib_inline.backend_inline.set_matplotlib_close()`
1257 use `matplotlib_inline.backend_inline.set_matplotlib_close()`
1258
1258
1259 Set whether the inline backend closes all figures automatically or not.
1259 Set whether the inline backend closes all figures automatically or not.
1260
1260
1261 By default, the inline backend used in the IPython Notebook will close all
1261 By default, the inline backend used in the IPython Notebook will close all
1262 matplotlib figures automatically after each cell is run. This means that
1262 matplotlib figures automatically after each cell is run. This means that
1263 plots in different cells won't interfere. Sometimes, you may want to make
1263 plots in different cells won't interfere. Sometimes, you may want to make
1264 a plot in one cell and then refine it in later cells. This can be accomplished
1264 a plot in one cell and then refine it in later cells. This can be accomplished
1265 by::
1265 by::
1266
1266
1267 In [1]: set_matplotlib_close(False)
1267 In [1]: set_matplotlib_close(False)
1268
1268
1269 To set this in your config files use the following::
1269 To set this in your config files use the following::
1270
1270
1271 c.InlineBackend.close_figures = False
1271 c.InlineBackend.close_figures = False
1272
1272
1273 Parameters
1273 Parameters
1274 ----------
1274 ----------
1275 close : bool
1275 close : bool
1276 Should all matplotlib figures be automatically closed after each cell is
1276 Should all matplotlib figures be automatically closed after each cell is
1277 run?
1277 run?
1278 """
1278 """
1279 warnings.warn(
1279 warnings.warn(
1280 "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
1280 "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
1281 "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
1281 "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
1282 DeprecationWarning,
1282 DeprecationWarning,
1283 stacklevel=2,
1283 stacklevel=2,
1284 )
1284 )
1285
1285
1286 from matplotlib_inline.backend_inline import (
1286 from matplotlib_inline.backend_inline import (
1287 set_matplotlib_close as set_matplotlib_close_orig,
1287 set_matplotlib_close as set_matplotlib_close_orig,
1288 )
1288 )
1289
1289
1290 set_matplotlib_close_orig(close)
1290 set_matplotlib_close_orig(close)
@@ -1,425 +1,425 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """Pylab (matplotlib) support utilities."""
2 """Pylab (matplotlib) support utilities."""
3
3
4 # Copyright (c) IPython Development Team.
4 # Copyright (c) IPython Development Team.
5 # Distributed under the terms of the Modified BSD License.
5 # Distributed under the terms of the Modified BSD License.
6
6
7 from io import BytesIO
7 from io import BytesIO
8 from binascii import b2a_base64
8 from binascii import b2a_base64
9 from functools import partial
9 from functools import partial
10 import warnings
10 import warnings
11
11
12 from IPython.core.display import _pngxy
12 from IPython.core.display import _pngxy
13 from IPython.utils.decorators import flag_calls
13 from IPython.utils.decorators import flag_calls
14
14
15 # If user specifies a GUI, that dictates the backend, otherwise we read the
15 # If user specifies a GUI, that dictates the backend, otherwise we read the
16 # user's mpl default from the mpl rc structure
16 # user's mpl default from the mpl rc structure
17 backends = {
17 backends = {
18 "tk": "TkAgg",
18 "tk": "TkAgg",
19 "gtk": "GTKAgg",
19 "gtk": "GTKAgg",
20 "gtk3": "GTK3Agg",
20 "gtk3": "GTK3Agg",
21 "gtk4": "GTK4Agg",
21 "gtk4": "GTK4Agg",
22 "wx": "WXAgg",
22 "wx": "WXAgg",
23 "qt4": "Qt4Agg",
23 "qt4": "Qt4Agg",
24 "qt5": "Qt5Agg",
24 "qt5": "Qt5Agg",
25 "qt6": "QtAgg",
25 "qt6": "QtAgg",
26 "qt": "Qt5Agg",
26 "qt": "Qt5Agg",
27 "osx": "MacOSX",
27 "osx": "MacOSX",
28 "nbagg": "nbAgg",
28 "nbagg": "nbAgg",
29 "webagg": "WebAgg",
29 "webagg": "WebAgg",
30 "notebook": "nbAgg",
30 "notebook": "nbAgg",
31 "agg": "agg",
31 "agg": "agg",
32 "svg": "svg",
32 "svg": "svg",
33 "pdf": "pdf",
33 "pdf": "pdf",
34 "ps": "ps",
34 "ps": "ps",
35 "inline": "module://matplotlib_inline.backend_inline",
35 "inline": "module://matplotlib_inline.backend_inline",
36 "ipympl": "module://ipympl.backend_nbagg",
36 "ipympl": "module://ipympl.backend_nbagg",
37 "widget": "module://ipympl.backend_nbagg",
37 "widget": "module://ipympl.backend_nbagg",
38 }
38 }
39
39
40 # We also need a reverse backends2guis mapping that will properly choose which
40 # We also need a reverse backends2guis mapping that will properly choose which
41 # GUI support to activate based on the desired matplotlib backend. For the
41 # GUI support to activate based on the desired matplotlib backend. For the
42 # most part it's just a reverse of the above dict, but we also need to add a
42 # most part it's just a reverse of the above dict, but we also need to add a
43 # few others that map to the same GUI manually:
43 # few others that map to the same GUI manually:
44 backend2gui = dict(zip(backends.values(), backends.keys()))
44 backend2gui = dict(zip(backends.values(), backends.keys()))
45 # In the reverse mapping, there are a few extra valid matplotlib backends that
45 # In the reverse mapping, there are a few extra valid matplotlib backends that
46 # map to the same GUI support
46 # map to the same GUI support
47 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
47 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
48 backend2gui["GTK3Cairo"] = "gtk3"
48 backend2gui["GTK3Cairo"] = "gtk3"
49 backend2gui["GTK4Cairo"] = "gtk4"
49 backend2gui["GTK4Cairo"] = "gtk4"
50 backend2gui["WX"] = "wx"
50 backend2gui["WX"] = "wx"
51 backend2gui["CocoaAgg"] = "osx"
51 backend2gui["CocoaAgg"] = "osx"
52 # There needs to be a hysteresis here as the new QtAgg Matplotlib backend
52 # There needs to be a hysteresis here as the new QtAgg Matplotlib backend
53 # supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
53 # supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
54 # and Qt6.
54 # and Qt6.
55 backend2gui["QtAgg"] = "qt"
55 backend2gui["QtAgg"] = "qt"
56 backend2gui["Qt4Agg"] = "qt"
56 backend2gui["Qt4Agg"] = "qt"
57 backend2gui["Qt5Agg"] = "qt"
57 backend2gui["Qt5Agg"] = "qt"
58
58
59 # And some backends that don't need GUI integration
59 # And some backends that don't need GUI integration
60 del backend2gui["nbAgg"]
60 del backend2gui["nbAgg"]
61 del backend2gui["agg"]
61 del backend2gui["agg"]
62 del backend2gui["svg"]
62 del backend2gui["svg"]
63 del backend2gui["pdf"]
63 del backend2gui["pdf"]
64 del backend2gui["ps"]
64 del backend2gui["ps"]
65 del backend2gui["module://matplotlib_inline.backend_inline"]
65 del backend2gui["module://matplotlib_inline.backend_inline"]
66 del backend2gui["module://ipympl.backend_nbagg"]
66 del backend2gui["module://ipympl.backend_nbagg"]
67
67
68 #-----------------------------------------------------------------------------
68 #-----------------------------------------------------------------------------
69 # Matplotlib utilities
69 # Matplotlib utilities
70 #-----------------------------------------------------------------------------
70 #-----------------------------------------------------------------------------
71
71
72
72
73 def getfigs(*fig_nums):
73 def getfigs(*fig_nums):
74 """Get a list of matplotlib figures by figure numbers.
74 """Get a list of matplotlib figures by figure numbers.
75
75
76 If no arguments are given, all available figures are returned. If the
76 If no arguments are given, all available figures are returned. If the
77 argument list contains references to invalid figures, a warning is printed
77 argument list contains references to invalid figures, a warning is printed
78 but the function continues pasting further figures.
78 but the function continues pasting further figures.
79
79
80 Parameters
80 Parameters
81 ----------
81 ----------
82 figs : tuple
82 figs : tuple
83 A tuple of ints giving the figure numbers of the figures to return.
83 A tuple of ints giving the figure numbers of the figures to return.
84 """
84 """
85 from matplotlib._pylab_helpers import Gcf
85 from matplotlib._pylab_helpers import Gcf
86 if not fig_nums:
86 if not fig_nums:
87 fig_managers = Gcf.get_all_fig_managers()
87 fig_managers = Gcf.get_all_fig_managers()
88 return [fm.canvas.figure for fm in fig_managers]
88 return [fm.canvas.figure for fm in fig_managers]
89 else:
89 else:
90 figs = []
90 figs = []
91 for num in fig_nums:
91 for num in fig_nums:
92 f = Gcf.figs.get(num)
92 f = Gcf.figs.get(num)
93 if f is None:
93 if f is None:
94 print('Warning: figure %s not available.' % num)
94 print('Warning: figure %s not available.' % num)
95 else:
95 else:
96 figs.append(f.canvas.figure)
96 figs.append(f.canvas.figure)
97 return figs
97 return figs
98
98
99
99
100 def figsize(sizex, sizey):
100 def figsize(sizex, sizey):
101 """Set the default figure size to be [sizex, sizey].
101 """Set the default figure size to be [sizex, sizey].
102
102
103 This is just an easy to remember, convenience wrapper that sets::
103 This is just an easy to remember, convenience wrapper that sets::
104
104
105 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
105 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
106 """
106 """
107 import matplotlib
107 import matplotlib
108 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
108 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
109
109
110
110
111 def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
111 def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
112 """Print a figure to an image, and return the resulting file data
112 """Print a figure to an image, and return the resulting file data
113
113
114 Returned data will be bytes unless ``fmt='svg'``,
114 Returned data will be bytes unless ``fmt='svg'``,
115 in which case it will be unicode.
115 in which case it will be unicode.
116
116
117 Any keyword args are passed to fig.canvas.print_figure,
117 Any keyword args are passed to fig.canvas.print_figure,
118 such as ``quality`` or ``bbox_inches``.
118 such as ``quality`` or ``bbox_inches``.
119
119
120 If `base64` is True, return base64-encoded str instead of raw bytes
120 If `base64` is True, return base64-encoded str instead of raw bytes
121 for binary-encoded image formats
121 for binary-encoded image formats
122
122
123 .. versionadded:: 7.29
123 .. versionadded:: 7.29
124 base64 argument
124 base64 argument
125 """
125 """
126 # When there's an empty figure, we shouldn't return anything, otherwise we
126 # When there's an empty figure, we shouldn't return anything, otherwise we
127 # get big blank areas in the qt console.
127 # get big blank areas in the qt console.
128 if not fig.axes and not fig.lines:
128 if not fig.axes and not fig.lines:
129 return
129 return
130
130
131 dpi = fig.dpi
131 dpi = fig.dpi
132 if fmt == 'retina':
132 if fmt == 'retina':
133 dpi = dpi * 2
133 dpi = dpi * 2
134 fmt = 'png'
134 fmt = 'png'
135
135
136 # build keyword args
136 # build keyword args
137 kw = {
137 kw = {
138 "format":fmt,
138 "format":fmt,
139 "facecolor":fig.get_facecolor(),
139 "facecolor":fig.get_facecolor(),
140 "edgecolor":fig.get_edgecolor(),
140 "edgecolor":fig.get_edgecolor(),
141 "dpi":dpi,
141 "dpi":dpi,
142 "bbox_inches":bbox_inches,
142 "bbox_inches":bbox_inches,
143 }
143 }
144 # **kwargs get higher priority
144 # **kwargs get higher priority
145 kw.update(kwargs)
145 kw.update(kwargs)
146
146
147 bytes_io = BytesIO()
147 bytes_io = BytesIO()
148 if fig.canvas is None:
148 if fig.canvas is None:
149 from matplotlib.backend_bases import FigureCanvasBase
149 from matplotlib.backend_bases import FigureCanvasBase
150 FigureCanvasBase(fig)
150 FigureCanvasBase(fig)
151
151
152 fig.canvas.print_figure(bytes_io, **kw)
152 fig.canvas.print_figure(bytes_io, **kw)
153 data = bytes_io.getvalue()
153 data = bytes_io.getvalue()
154 if fmt == 'svg':
154 if fmt == 'svg':
155 data = data.decode('utf-8')
155 data = data.decode('utf-8')
156 elif base64:
156 elif base64:
157 data = b2a_base64(data).decode("ascii")
157 data = b2a_base64(data, newline=False).decode("ascii")
158 return data
158 return data
159
159
160 def retina_figure(fig, base64=False, **kwargs):
160 def retina_figure(fig, base64=False, **kwargs):
161 """format a figure as a pixel-doubled (retina) PNG
161 """format a figure as a pixel-doubled (retina) PNG
162
162
163 If `base64` is True, return base64-encoded str instead of raw bytes
163 If `base64` is True, return base64-encoded str instead of raw bytes
164 for binary-encoded image formats
164 for binary-encoded image formats
165
165
166 .. versionadded:: 7.29
166 .. versionadded:: 7.29
167 base64 argument
167 base64 argument
168 """
168 """
169 pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
169 pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
170 # Make sure that retina_figure acts just like print_figure and returns
170 # Make sure that retina_figure acts just like print_figure and returns
171 # None when the figure is empty.
171 # None when the figure is empty.
172 if pngdata is None:
172 if pngdata is None:
173 return
173 return
174 w, h = _pngxy(pngdata)
174 w, h = _pngxy(pngdata)
175 metadata = {"width": w//2, "height":h//2}
175 metadata = {"width": w//2, "height":h//2}
176 if base64:
176 if base64:
177 pngdata = b2a_base64(pngdata).decode("ascii")
177 pngdata = b2a_base64(pngdata, newline=False).decode("ascii")
178 return pngdata, metadata
178 return pngdata, metadata
179
179
180
180
181 # We need a little factory function here to create the closure where
181 # We need a little factory function here to create the closure where
182 # safe_execfile can live.
182 # safe_execfile can live.
183 def mpl_runner(safe_execfile):
183 def mpl_runner(safe_execfile):
184 """Factory to return a matplotlib-enabled runner for %run.
184 """Factory to return a matplotlib-enabled runner for %run.
185
185
186 Parameters
186 Parameters
187 ----------
187 ----------
188 safe_execfile : function
188 safe_execfile : function
189 This must be a function with the same interface as the
189 This must be a function with the same interface as the
190 :meth:`safe_execfile` method of IPython.
190 :meth:`safe_execfile` method of IPython.
191
191
192 Returns
192 Returns
193 -------
193 -------
194 A function suitable for use as the ``runner`` argument of the %run magic
194 A function suitable for use as the ``runner`` argument of the %run magic
195 function.
195 function.
196 """
196 """
197
197
198 def mpl_execfile(fname,*where,**kw):
198 def mpl_execfile(fname,*where,**kw):
199 """matplotlib-aware wrapper around safe_execfile.
199 """matplotlib-aware wrapper around safe_execfile.
200
200
201 Its interface is identical to that of the :func:`execfile` builtin.
201 Its interface is identical to that of the :func:`execfile` builtin.
202
202
203 This is ultimately a call to execfile(), but wrapped in safeties to
203 This is ultimately a call to execfile(), but wrapped in safeties to
204 properly handle interactive rendering."""
204 properly handle interactive rendering."""
205
205
206 import matplotlib
206 import matplotlib
207 import matplotlib.pyplot as plt
207 import matplotlib.pyplot as plt
208
208
209 #print '*** Matplotlib runner ***' # dbg
209 #print '*** Matplotlib runner ***' # dbg
210 # turn off rendering until end of script
210 # turn off rendering until end of script
211 is_interactive = matplotlib.rcParams['interactive']
211 is_interactive = matplotlib.rcParams['interactive']
212 matplotlib.interactive(False)
212 matplotlib.interactive(False)
213 safe_execfile(fname,*where,**kw)
213 safe_execfile(fname,*where,**kw)
214 matplotlib.interactive(is_interactive)
214 matplotlib.interactive(is_interactive)
215 # make rendering call now, if the user tried to do it
215 # make rendering call now, if the user tried to do it
216 if plt.draw_if_interactive.called:
216 if plt.draw_if_interactive.called:
217 plt.draw()
217 plt.draw()
218 plt.draw_if_interactive.called = False
218 plt.draw_if_interactive.called = False
219
219
220 # re-draw everything that is stale
220 # re-draw everything that is stale
221 try:
221 try:
222 da = plt.draw_all
222 da = plt.draw_all
223 except AttributeError:
223 except AttributeError:
224 pass
224 pass
225 else:
225 else:
226 da()
226 da()
227
227
228 return mpl_execfile
228 return mpl_execfile
229
229
230
230
231 def _reshow_nbagg_figure(fig):
231 def _reshow_nbagg_figure(fig):
232 """reshow an nbagg figure"""
232 """reshow an nbagg figure"""
233 try:
233 try:
234 reshow = fig.canvas.manager.reshow
234 reshow = fig.canvas.manager.reshow
235 except AttributeError as e:
235 except AttributeError as e:
236 raise NotImplementedError() from e
236 raise NotImplementedError() from e
237 else:
237 else:
238 reshow()
238 reshow()
239
239
240
240
241 def select_figure_formats(shell, formats, **kwargs):
241 def select_figure_formats(shell, formats, **kwargs):
242 """Select figure formats for the inline backend.
242 """Select figure formats for the inline backend.
243
243
244 Parameters
244 Parameters
245 ----------
245 ----------
246 shell : InteractiveShell
246 shell : InteractiveShell
247 The main IPython instance.
247 The main IPython instance.
248 formats : str or set
248 formats : str or set
249 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
249 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
250 **kwargs : any
250 **kwargs : any
251 Extra keyword arguments to be passed to fig.canvas.print_figure.
251 Extra keyword arguments to be passed to fig.canvas.print_figure.
252 """
252 """
253 import matplotlib
253 import matplotlib
254 from matplotlib.figure import Figure
254 from matplotlib.figure import Figure
255
255
256 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
256 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
257 png_formatter = shell.display_formatter.formatters['image/png']
257 png_formatter = shell.display_formatter.formatters['image/png']
258 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
258 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
259 pdf_formatter = shell.display_formatter.formatters['application/pdf']
259 pdf_formatter = shell.display_formatter.formatters['application/pdf']
260
260
261 if isinstance(formats, str):
261 if isinstance(formats, str):
262 formats = {formats}
262 formats = {formats}
263 # cast in case of list / tuple
263 # cast in case of list / tuple
264 formats = set(formats)
264 formats = set(formats)
265
265
266 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
266 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
267 mplbackend = matplotlib.get_backend().lower()
267 mplbackend = matplotlib.get_backend().lower()
268 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
268 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
269 formatter = shell.display_formatter.ipython_display_formatter
269 formatter = shell.display_formatter.ipython_display_formatter
270 formatter.for_type(Figure, _reshow_nbagg_figure)
270 formatter.for_type(Figure, _reshow_nbagg_figure)
271
271
272 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
272 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
273 bad = formats.difference(supported)
273 bad = formats.difference(supported)
274 if bad:
274 if bad:
275 bs = "%s" % ','.join([repr(f) for f in bad])
275 bs = "%s" % ','.join([repr(f) for f in bad])
276 gs = "%s" % ','.join([repr(f) for f in supported])
276 gs = "%s" % ','.join([repr(f) for f in supported])
277 raise ValueError("supported formats are: %s not %s" % (gs, bs))
277 raise ValueError("supported formats are: %s not %s" % (gs, bs))
278
278
279 if "png" in formats:
279 if "png" in formats:
280 png_formatter.for_type(
280 png_formatter.for_type(
281 Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
281 Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
282 )
282 )
283 if "retina" in formats or "png2x" in formats:
283 if "retina" in formats or "png2x" in formats:
284 png_formatter.for_type(Figure, partial(retina_figure, base64=True, **kwargs))
284 png_formatter.for_type(Figure, partial(retina_figure, base64=True, **kwargs))
285 if "jpg" in formats or "jpeg" in formats:
285 if "jpg" in formats or "jpeg" in formats:
286 jpg_formatter.for_type(
286 jpg_formatter.for_type(
287 Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
287 Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
288 )
288 )
289 if "svg" in formats:
289 if "svg" in formats:
290 svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", **kwargs))
290 svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", **kwargs))
291 if "pdf" in formats:
291 if "pdf" in formats:
292 pdf_formatter.for_type(
292 pdf_formatter.for_type(
293 Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
293 Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
294 )
294 )
295
295
296 #-----------------------------------------------------------------------------
296 #-----------------------------------------------------------------------------
297 # Code for initializing matplotlib and importing pylab
297 # Code for initializing matplotlib and importing pylab
298 #-----------------------------------------------------------------------------
298 #-----------------------------------------------------------------------------
299
299
300
300
301 def find_gui_and_backend(gui=None, gui_select=None):
301 def find_gui_and_backend(gui=None, gui_select=None):
302 """Given a gui string return the gui and mpl backend.
302 """Given a gui string return the gui and mpl backend.
303
303
304 Parameters
304 Parameters
305 ----------
305 ----------
306 gui : str
306 gui : str
307 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
307 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
308 gui_select : str
308 gui_select : str
309 Can be one of ('tk','gtk','wx','qt','qt4','inline').
309 Can be one of ('tk','gtk','wx','qt','qt4','inline').
310 This is any gui already selected by the shell.
310 This is any gui already selected by the shell.
311
311
312 Returns
312 Returns
313 -------
313 -------
314 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
314 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
315 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
315 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
316 """
316 """
317
317
318 import matplotlib
318 import matplotlib
319
319
320 if gui and gui != 'auto':
320 if gui and gui != 'auto':
321 # select backend based on requested gui
321 # select backend based on requested gui
322 backend = backends[gui]
322 backend = backends[gui]
323 if gui == 'agg':
323 if gui == 'agg':
324 gui = None
324 gui = None
325 else:
325 else:
326 # We need to read the backend from the original data structure, *not*
326 # We need to read the backend from the original data structure, *not*
327 # from mpl.rcParams, since a prior invocation of %matplotlib may have
327 # from mpl.rcParams, since a prior invocation of %matplotlib may have
328 # overwritten that.
328 # overwritten that.
329 # WARNING: this assumes matplotlib 1.1 or newer!!
329 # WARNING: this assumes matplotlib 1.1 or newer!!
330 backend = matplotlib.rcParamsOrig['backend']
330 backend = matplotlib.rcParamsOrig['backend']
331 # In this case, we need to find what the appropriate gui selection call
331 # In this case, we need to find what the appropriate gui selection call
332 # should be for IPython, so we can activate inputhook accordingly
332 # should be for IPython, so we can activate inputhook accordingly
333 gui = backend2gui.get(backend, None)
333 gui = backend2gui.get(backend, None)
334
334
335 # If we have already had a gui active, we need it and inline are the
335 # If we have already had a gui active, we need it and inline are the
336 # ones allowed.
336 # ones allowed.
337 if gui_select and gui != gui_select:
337 if gui_select and gui != gui_select:
338 gui = gui_select
338 gui = gui_select
339 backend = backends[gui]
339 backend = backends[gui]
340
340
341 return gui, backend
341 return gui, backend
342
342
343
343
344 def activate_matplotlib(backend):
344 def activate_matplotlib(backend):
345 """Activate the given backend and set interactive to True."""
345 """Activate the given backend and set interactive to True."""
346
346
347 import matplotlib
347 import matplotlib
348 matplotlib.interactive(True)
348 matplotlib.interactive(True)
349
349
350 # Matplotlib had a bug where even switch_backend could not force
350 # Matplotlib had a bug where even switch_backend could not force
351 # the rcParam to update. This needs to be set *before* the module
351 # the rcParam to update. This needs to be set *before* the module
352 # magic of switch_backend().
352 # magic of switch_backend().
353 matplotlib.rcParams['backend'] = backend
353 matplotlib.rcParams['backend'] = backend
354
354
355 # Due to circular imports, pyplot may be only partially initialised
355 # Due to circular imports, pyplot may be only partially initialised
356 # when this function runs.
356 # when this function runs.
357 # So avoid needing matplotlib attribute-lookup to access pyplot.
357 # So avoid needing matplotlib attribute-lookup to access pyplot.
358 from matplotlib import pyplot as plt
358 from matplotlib import pyplot as plt
359
359
360 plt.switch_backend(backend)
360 plt.switch_backend(backend)
361
361
362 plt.show._needmain = False
362 plt.show._needmain = False
363 # We need to detect at runtime whether show() is called by the user.
363 # We need to detect at runtime whether show() is called by the user.
364 # For this, we wrap it into a decorator which adds a 'called' flag.
364 # For this, we wrap it into a decorator which adds a 'called' flag.
365 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
365 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
366
366
367
367
368 def import_pylab(user_ns, import_all=True):
368 def import_pylab(user_ns, import_all=True):
369 """Populate the namespace with pylab-related values.
369 """Populate the namespace with pylab-related values.
370
370
371 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
371 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
372
372
373 Also imports a few names from IPython (figsize, display, getfigs)
373 Also imports a few names from IPython (figsize, display, getfigs)
374
374
375 """
375 """
376
376
377 # Import numpy as np/pyplot as plt are conventions we're trying to
377 # Import numpy as np/pyplot as plt are conventions we're trying to
378 # somewhat standardize on. Making them available to users by default
378 # somewhat standardize on. Making them available to users by default
379 # will greatly help this.
379 # will greatly help this.
380 s = ("import numpy\n"
380 s = ("import numpy\n"
381 "import matplotlib\n"
381 "import matplotlib\n"
382 "from matplotlib import pylab, mlab, pyplot\n"
382 "from matplotlib import pylab, mlab, pyplot\n"
383 "np = numpy\n"
383 "np = numpy\n"
384 "plt = pyplot\n"
384 "plt = pyplot\n"
385 )
385 )
386 exec(s, user_ns)
386 exec(s, user_ns)
387
387
388 if import_all:
388 if import_all:
389 s = ("from matplotlib.pylab import *\n"
389 s = ("from matplotlib.pylab import *\n"
390 "from numpy import *\n")
390 "from numpy import *\n")
391 exec(s, user_ns)
391 exec(s, user_ns)
392
392
393 # IPython symbols to add
393 # IPython symbols to add
394 user_ns['figsize'] = figsize
394 user_ns['figsize'] = figsize
395 from IPython.display import display
395 from IPython.display import display
396 # Add display and getfigs to the user's namespace
396 # Add display and getfigs to the user's namespace
397 user_ns['display'] = display
397 user_ns['display'] = display
398 user_ns['getfigs'] = getfigs
398 user_ns['getfigs'] = getfigs
399
399
400
400
401 def configure_inline_support(shell, backend):
401 def configure_inline_support(shell, backend):
402 """
402 """
403 .. deprecated:: 7.23
403 .. deprecated:: 7.23
404
404
405 use `matplotlib_inline.backend_inline.configure_inline_support()`
405 use `matplotlib_inline.backend_inline.configure_inline_support()`
406
406
407 Configure an IPython shell object for matplotlib use.
407 Configure an IPython shell object for matplotlib use.
408
408
409 Parameters
409 Parameters
410 ----------
410 ----------
411 shell : InteractiveShell instance
411 shell : InteractiveShell instance
412 backend : matplotlib backend
412 backend : matplotlib backend
413 """
413 """
414 warnings.warn(
414 warnings.warn(
415 "`configure_inline_support` is deprecated since IPython 7.23, directly "
415 "`configure_inline_support` is deprecated since IPython 7.23, directly "
416 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
416 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
417 DeprecationWarning,
417 DeprecationWarning,
418 stacklevel=2,
418 stacklevel=2,
419 )
419 )
420
420
421 from matplotlib_inline.backend_inline import (
421 from matplotlib_inline.backend_inline import (
422 configure_inline_support as configure_inline_support_orig,
422 configure_inline_support as configure_inline_support_orig,
423 )
423 )
424
424
425 configure_inline_support_orig(shell, backend)
425 configure_inline_support_orig(shell, backend)
General Comments 0
You need to be logged in to leave comments. Login now