##// END OF EJS Templates
Merge pull request #11353 from finaiized/master...
Matthias Bussonnier -
r24635:9fd6be2f merge
parent child Browse files
Show More
@@ -0,0 +1,1 b''
1 ``IPython.display.Video`` now supports ``width`` and ``height`` arguments, allowing a custom width and height to be set instead of using the video's width and height No newline at end of file
@@ -1,1439 +1,1454 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Top-level display functions for displaying object in different formats."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7
8 8 from binascii import b2a_hex, b2a_base64, hexlify
9 9 import json
10 10 import mimetypes
11 11 import os
12 12 import struct
13 13 import sys
14 14 import warnings
15 15 from copy import deepcopy
16 16
17 17 from IPython.utils.py3compat import cast_unicode
18 18 from IPython.testing.skipdoctest import skip_doctest
19 19
20 20 __all__ = ['display', 'display_pretty', 'display_html', 'display_markdown',
21 21 'display_svg', 'display_png', 'display_jpeg', 'display_latex', 'display_json',
22 22 'display_javascript', 'display_pdf', 'DisplayObject', 'TextDisplayObject',
23 23 'Pretty', 'HTML', 'Markdown', 'Math', 'Latex', 'SVG', 'ProgressBar', 'JSON',
24 24 'GeoJSON', 'Javascript', 'Image', 'clear_output', 'set_matplotlib_formats',
25 25 'set_matplotlib_close', 'publish_display_data', 'update_display', 'DisplayHandle',
26 26 'Video']
27 27
28 28 #-----------------------------------------------------------------------------
29 29 # utility functions
30 30 #-----------------------------------------------------------------------------
31 31
32 32 def _safe_exists(path):
33 33 """Check path, but don't let exceptions raise"""
34 34 try:
35 35 return os.path.exists(path)
36 36 except Exception:
37 37 return False
38 38
39 39 def _merge(d1, d2):
40 40 """Like update, but merges sub-dicts instead of clobbering at the top level.
41 41
42 42 Updates d1 in-place
43 43 """
44 44
45 45 if not isinstance(d2, dict) or not isinstance(d1, dict):
46 46 return d2
47 47 for key, value in d2.items():
48 48 d1[key] = _merge(d1.get(key), value)
49 49 return d1
50 50
51 51 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
52 52 """internal implementation of all display_foo methods
53 53
54 54 Parameters
55 55 ----------
56 56 mimetype : str
57 57 The mimetype to be published (e.g. 'image/png')
58 58 objs : tuple of objects
59 59 The Python objects to display, or if raw=True raw text data to
60 60 display.
61 61 raw : bool
62 62 Are the data objects raw data or Python objects that need to be
63 63 formatted before display? [default: False]
64 64 metadata : dict (optional)
65 65 Metadata to be associated with the specific mimetype output.
66 66 """
67 67 if metadata:
68 68 metadata = {mimetype: metadata}
69 69 if raw:
70 70 # turn list of pngdata into list of { 'image/png': pngdata }
71 71 objs = [ {mimetype: obj} for obj in objs ]
72 72 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
73 73
74 74 #-----------------------------------------------------------------------------
75 75 # Main functions
76 76 #-----------------------------------------------------------------------------
77 77
78 78 # use * to indicate transient is keyword-only
79 79 def publish_display_data(data, metadata=None, source=None, *, transient=None, **kwargs):
80 80 """Publish data and metadata to all frontends.
81 81
82 82 See the ``display_data`` message in the messaging documentation for
83 83 more details about this message type.
84 84
85 85 Keys of data and metadata can be any mime-type.
86 86
87 87 Parameters
88 88 ----------
89 89 data : dict
90 90 A dictionary having keys that are valid MIME types (like
91 91 'text/plain' or 'image/svg+xml') and values that are the data for
92 92 that MIME type. The data itself must be a JSON'able data
93 93 structure. Minimally all data should have the 'text/plain' data,
94 94 which can be displayed by all frontends. If more than the plain
95 95 text is given, it is up to the frontend to decide which
96 96 representation to use.
97 97 metadata : dict
98 98 A dictionary for metadata related to the data. This can contain
99 99 arbitrary key, value pairs that frontends can use to interpret
100 100 the data. mime-type keys matching those in data can be used
101 101 to specify metadata about particular representations.
102 102 source : str, deprecated
103 103 Unused.
104 104 transient : dict, keyword-only
105 105 A dictionary of transient data, such as display_id.
106 106 """
107 107 from IPython.core.interactiveshell import InteractiveShell
108 108
109 109 display_pub = InteractiveShell.instance().display_pub
110 110
111 111 # only pass transient if supplied,
112 112 # to avoid errors with older ipykernel.
113 113 # TODO: We could check for ipykernel version and provide a detailed upgrade message.
114 114 if transient:
115 115 kwargs['transient'] = transient
116 116
117 117 display_pub.publish(
118 118 data=data,
119 119 metadata=metadata,
120 120 **kwargs
121 121 )
122 122
123 123
124 124 def _new_id():
125 125 """Generate a new random text id with urandom"""
126 126 return b2a_hex(os.urandom(16)).decode('ascii')
127 127
128 128
129 129 def display(*objs, include=None, exclude=None, metadata=None, transient=None, display_id=None, **kwargs):
130 130 """Display a Python object in all frontends.
131 131
132 132 By default all representations will be computed and sent to the frontends.
133 133 Frontends can decide which representation is used and how.
134 134
135 135 In terminal IPython this will be similar to using :func:`print`, for use in richer
136 136 frontends see Jupyter notebook examples with rich display logic.
137 137
138 138 Parameters
139 139 ----------
140 140 objs : tuple of objects
141 141 The Python objects to display.
142 142 raw : bool, optional
143 143 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
144 144 or Python objects that need to be formatted before display? [default: False]
145 145 include : list, tuple or set, optional
146 146 A list of format type strings (MIME types) to include in the
147 147 format data dict. If this is set *only* the format types included
148 148 in this list will be computed.
149 149 exclude : list, tuple or set, optional
150 150 A list of format type strings (MIME types) to exclude in the format
151 151 data dict. If this is set all format types will be computed,
152 152 except for those included in this argument.
153 153 metadata : dict, optional
154 154 A dictionary of metadata to associate with the output.
155 155 mime-type keys in this dictionary will be associated with the individual
156 156 representation formats, if they exist.
157 157 transient : dict, optional
158 158 A dictionary of transient data to associate with the output.
159 159 Data in this dict should not be persisted to files (e.g. notebooks).
160 160 display_id : str, bool optional
161 161 Set an id for the display.
162 162 This id can be used for updating this display area later via update_display.
163 163 If given as `True`, generate a new `display_id`
164 164 kwargs: additional keyword-args, optional
165 165 Additional keyword-arguments are passed through to the display publisher.
166 166
167 167 Returns
168 168 -------
169 169
170 170 handle: DisplayHandle
171 171 Returns a handle on updatable displays for use with :func:`update_display`,
172 172 if `display_id` is given. Returns :any:`None` if no `display_id` is given
173 173 (default).
174 174
175 175 Examples
176 176 --------
177 177
178 178 >>> class Json(object):
179 179 ... def __init__(self, json):
180 180 ... self.json = json
181 181 ... def _repr_pretty_(self, pp, cycle):
182 182 ... import json
183 183 ... pp.text(json.dumps(self.json, indent=2))
184 184 ... def __repr__(self):
185 185 ... return str(self.json)
186 186 ...
187 187
188 188 >>> d = Json({1:2, 3: {4:5}})
189 189
190 190 >>> print(d)
191 191 {1: 2, 3: {4: 5}}
192 192
193 193 >>> display(d)
194 194 {
195 195 "1": 2,
196 196 "3": {
197 197 "4": 5
198 198 }
199 199 }
200 200
201 201 >>> def int_formatter(integer, pp, cycle):
202 202 ... pp.text('I'*integer)
203 203
204 204 >>> plain = get_ipython().display_formatter.formatters['text/plain']
205 205 >>> plain.for_type(int, int_formatter)
206 206 <function _repr_pprint at 0x...>
207 207 >>> display(7-5)
208 208 II
209 209
210 210 >>> del plain.type_printers[int]
211 211 >>> display(7-5)
212 212 2
213 213
214 214 See Also
215 215 --------
216 216
217 217 :func:`update_display`
218 218
219 219 Notes
220 220 -----
221 221
222 222 In Python, objects can declare their textual representation using the
223 223 `__repr__` method. IPython expands on this idea and allows objects to declare
224 224 other, rich representations including:
225 225
226 226 - HTML
227 227 - JSON
228 228 - PNG
229 229 - JPEG
230 230 - SVG
231 231 - LaTeX
232 232
233 233 A single object can declare some or all of these representations; all are
234 234 handled by IPython's display system.
235 235
236 236 The main idea of the first approach is that you have to implement special
237 237 display methods when you define your class, one for each representation you
238 238 want to use. Here is a list of the names of the special methods and the
239 239 values they must return:
240 240
241 241 - `_repr_html_`: return raw HTML as a string, or a tuple (see below).
242 242 - `_repr_json_`: return a JSONable dict, or a tuple (see below).
243 243 - `_repr_jpeg_`: return raw JPEG data, or a tuple (see below).
244 244 - `_repr_png_`: return raw PNG data, or a tuple (see below).
245 245 - `_repr_svg_`: return raw SVG data as a string, or a tuple (see below).
246 246 - `_repr_latex_`: return LaTeX commands in a string surrounded by "$",
247 247 or a tuple (see below).
248 248 - `_repr_mimebundle_`: return a full mimebundle containing the mapping
249 249 from all mimetypes to data.
250 250 Use this for any mime-type not listed above.
251 251
252 252 The above functions may also return the object's metadata alonside the
253 253 data. If the metadata is available, the functions will return a tuple
254 254 containing the data and metadata, in that order. If there is no metadata
255 255 available, then the functions will return the data only.
256 256
257 257 When you are directly writing your own classes, you can adapt them for
258 258 display in IPython by following the above approach. But in practice, you
259 259 often need to work with existing classes that you can't easily modify.
260 260
261 261 You can refer to the documentation on integrating with the display system in
262 262 order to register custom formatters for already existing types
263 263 (:ref:`integrating_rich_display`).
264 264
265 265 .. versionadded:: 5.4 display available without import
266 266 .. versionadded:: 6.1 display available without import
267 267
268 268 Since IPython 5.4 and 6.1 :func:`display` is automatically made available to
269 269 the user without import. If you are using display in a document that might
270 270 be used in a pure python context or with older version of IPython, use the
271 271 following import at the top of your file::
272 272
273 273 from IPython.display import display
274 274
275 275 """
276 276 from IPython.core.interactiveshell import InteractiveShell
277 277
278 278 if not InteractiveShell.initialized():
279 279 # Directly print objects.
280 280 print(*objs)
281 281 return
282 282
283 283 raw = kwargs.pop('raw', False)
284 284 if transient is None:
285 285 transient = {}
286 286 if metadata is None:
287 287 metadata={}
288 288 if display_id:
289 289 if display_id is True:
290 290 display_id = _new_id()
291 291 transient['display_id'] = display_id
292 292 if kwargs.get('update') and 'display_id' not in transient:
293 293 raise TypeError('display_id required for update_display')
294 294 if transient:
295 295 kwargs['transient'] = transient
296 296
297 297 if not raw:
298 298 format = InteractiveShell.instance().display_formatter.format
299 299
300 300 for obj in objs:
301 301 if raw:
302 302 publish_display_data(data=obj, metadata=metadata, **kwargs)
303 303 else:
304 304 format_dict, md_dict = format(obj, include=include, exclude=exclude)
305 305 if not format_dict:
306 306 # nothing to display (e.g. _ipython_display_ took over)
307 307 continue
308 308 if metadata:
309 309 # kwarg-specified metadata gets precedence
310 310 _merge(md_dict, metadata)
311 311 publish_display_data(data=format_dict, metadata=md_dict, **kwargs)
312 312 if display_id:
313 313 return DisplayHandle(display_id)
314 314
315 315
316 316 # use * for keyword-only display_id arg
317 317 def update_display(obj, *, display_id, **kwargs):
318 318 """Update an existing display by id
319 319
320 320 Parameters
321 321 ----------
322 322
323 323 obj:
324 324 The object with which to update the display
325 325 display_id: keyword-only
326 326 The id of the display to update
327 327
328 328 See Also
329 329 --------
330 330
331 331 :func:`display`
332 332 """
333 333 kwargs['update'] = True
334 334 display(obj, display_id=display_id, **kwargs)
335 335
336 336
337 337 class DisplayHandle(object):
338 338 """A handle on an updatable display
339 339
340 340 Call `.update(obj)` to display a new object.
341 341
342 342 Call `.display(obj`) to add a new instance of this display,
343 343 and update existing instances.
344 344
345 345 See Also
346 346 --------
347 347
348 348 :func:`display`, :func:`update_display`
349 349
350 350 """
351 351
352 352 def __init__(self, display_id=None):
353 353 if display_id is None:
354 354 display_id = _new_id()
355 355 self.display_id = display_id
356 356
357 357 def __repr__(self):
358 358 return "<%s display_id=%s>" % (self.__class__.__name__, self.display_id)
359 359
360 360 def display(self, obj, **kwargs):
361 361 """Make a new display with my id, updating existing instances.
362 362
363 363 Parameters
364 364 ----------
365 365
366 366 obj:
367 367 object to display
368 368 **kwargs:
369 369 additional keyword arguments passed to display
370 370 """
371 371 display(obj, display_id=self.display_id, **kwargs)
372 372
373 373 def update(self, obj, **kwargs):
374 374 """Update existing displays with my id
375 375
376 376 Parameters
377 377 ----------
378 378
379 379 obj:
380 380 object to display
381 381 **kwargs:
382 382 additional keyword arguments passed to update_display
383 383 """
384 384 update_display(obj, display_id=self.display_id, **kwargs)
385 385
386 386
387 387 def display_pretty(*objs, **kwargs):
388 388 """Display the pretty (default) representation of an object.
389 389
390 390 Parameters
391 391 ----------
392 392 objs : tuple of objects
393 393 The Python objects to display, or if raw=True raw text data to
394 394 display.
395 395 raw : bool
396 396 Are the data objects raw data or Python objects that need to be
397 397 formatted before display? [default: False]
398 398 metadata : dict (optional)
399 399 Metadata to be associated with the specific mimetype output.
400 400 """
401 401 _display_mimetype('text/plain', objs, **kwargs)
402 402
403 403
404 404 def display_html(*objs, **kwargs):
405 405 """Display the HTML representation of an object.
406 406
407 407 Note: If raw=False and the object does not have a HTML
408 408 representation, no HTML will be shown.
409 409
410 410 Parameters
411 411 ----------
412 412 objs : tuple of objects
413 413 The Python objects to display, or if raw=True raw HTML data to
414 414 display.
415 415 raw : bool
416 416 Are the data objects raw data or Python objects that need to be
417 417 formatted before display? [default: False]
418 418 metadata : dict (optional)
419 419 Metadata to be associated with the specific mimetype output.
420 420 """
421 421 _display_mimetype('text/html', objs, **kwargs)
422 422
423 423
424 424 def display_markdown(*objs, **kwargs):
425 425 """Displays the Markdown representation of an object.
426 426
427 427 Parameters
428 428 ----------
429 429 objs : tuple of objects
430 430 The Python objects to display, or if raw=True raw markdown data to
431 431 display.
432 432 raw : bool
433 433 Are the data objects raw data or Python objects that need to be
434 434 formatted before display? [default: False]
435 435 metadata : dict (optional)
436 436 Metadata to be associated with the specific mimetype output.
437 437 """
438 438
439 439 _display_mimetype('text/markdown', objs, **kwargs)
440 440
441 441
442 442 def display_svg(*objs, **kwargs):
443 443 """Display the SVG representation of an object.
444 444
445 445 Parameters
446 446 ----------
447 447 objs : tuple of objects
448 448 The Python objects to display, or if raw=True raw svg data to
449 449 display.
450 450 raw : bool
451 451 Are the data objects raw data or Python objects that need to be
452 452 formatted before display? [default: False]
453 453 metadata : dict (optional)
454 454 Metadata to be associated with the specific mimetype output.
455 455 """
456 456 _display_mimetype('image/svg+xml', objs, **kwargs)
457 457
458 458
459 459 def display_png(*objs, **kwargs):
460 460 """Display the PNG representation of an object.
461 461
462 462 Parameters
463 463 ----------
464 464 objs : tuple of objects
465 465 The Python objects to display, or if raw=True raw png data to
466 466 display.
467 467 raw : bool
468 468 Are the data objects raw data or Python objects that need to be
469 469 formatted before display? [default: False]
470 470 metadata : dict (optional)
471 471 Metadata to be associated with the specific mimetype output.
472 472 """
473 473 _display_mimetype('image/png', objs, **kwargs)
474 474
475 475
476 476 def display_jpeg(*objs, **kwargs):
477 477 """Display the JPEG representation of an object.
478 478
479 479 Parameters
480 480 ----------
481 481 objs : tuple of objects
482 482 The Python objects to display, or if raw=True raw JPEG data to
483 483 display.
484 484 raw : bool
485 485 Are the data objects raw data or Python objects that need to be
486 486 formatted before display? [default: False]
487 487 metadata : dict (optional)
488 488 Metadata to be associated with the specific mimetype output.
489 489 """
490 490 _display_mimetype('image/jpeg', objs, **kwargs)
491 491
492 492
493 493 def display_latex(*objs, **kwargs):
494 494 """Display the LaTeX representation of an object.
495 495
496 496 Parameters
497 497 ----------
498 498 objs : tuple of objects
499 499 The Python objects to display, or if raw=True raw latex data to
500 500 display.
501 501 raw : bool
502 502 Are the data objects raw data or Python objects that need to be
503 503 formatted before display? [default: False]
504 504 metadata : dict (optional)
505 505 Metadata to be associated with the specific mimetype output.
506 506 """
507 507 _display_mimetype('text/latex', objs, **kwargs)
508 508
509 509
510 510 def display_json(*objs, **kwargs):
511 511 """Display the JSON representation of an object.
512 512
513 513 Note that not many frontends support displaying JSON.
514 514
515 515 Parameters
516 516 ----------
517 517 objs : tuple of objects
518 518 The Python objects to display, or if raw=True raw json data to
519 519 display.
520 520 raw : bool
521 521 Are the data objects raw data or Python objects that need to be
522 522 formatted before display? [default: False]
523 523 metadata : dict (optional)
524 524 Metadata to be associated with the specific mimetype output.
525 525 """
526 526 _display_mimetype('application/json', objs, **kwargs)
527 527
528 528
529 529 def display_javascript(*objs, **kwargs):
530 530 """Display the Javascript representation of an object.
531 531
532 532 Parameters
533 533 ----------
534 534 objs : tuple of objects
535 535 The Python objects to display, or if raw=True raw javascript data to
536 536 display.
537 537 raw : bool
538 538 Are the data objects raw data or Python objects that need to be
539 539 formatted before display? [default: False]
540 540 metadata : dict (optional)
541 541 Metadata to be associated with the specific mimetype output.
542 542 """
543 543 _display_mimetype('application/javascript', objs, **kwargs)
544 544
545 545
546 546 def display_pdf(*objs, **kwargs):
547 547 """Display the PDF representation of an object.
548 548
549 549 Parameters
550 550 ----------
551 551 objs : tuple of objects
552 552 The Python objects to display, or if raw=True raw javascript data to
553 553 display.
554 554 raw : bool
555 555 Are the data objects raw data or Python objects that need to be
556 556 formatted before display? [default: False]
557 557 metadata : dict (optional)
558 558 Metadata to be associated with the specific mimetype output.
559 559 """
560 560 _display_mimetype('application/pdf', objs, **kwargs)
561 561
562 562
563 563 #-----------------------------------------------------------------------------
564 564 # Smart classes
565 565 #-----------------------------------------------------------------------------
566 566
567 567
568 568 class DisplayObject(object):
569 569 """An object that wraps data to be displayed."""
570 570
571 571 _read_flags = 'r'
572 572 _show_mem_addr = False
573 573 metadata = None
574 574
575 575 def __init__(self, data=None, url=None, filename=None, metadata=None):
576 576 """Create a display object given raw data.
577 577
578 578 When this object is returned by an expression or passed to the
579 579 display function, it will result in the data being displayed
580 580 in the frontend. The MIME type of the data should match the
581 581 subclasses used, so the Png subclass should be used for 'image/png'
582 582 data. If the data is a URL, the data will first be downloaded
583 583 and then displayed. If
584 584
585 585 Parameters
586 586 ----------
587 587 data : unicode, str or bytes
588 588 The raw data or a URL or file to load the data from
589 589 url : unicode
590 590 A URL to download the data from.
591 591 filename : unicode
592 592 Path to a local file to load the data from.
593 593 metadata : dict
594 594 Dict of metadata associated to be the object when displayed
595 595 """
596 596 if data is not None and isinstance(data, str):
597 597 if data.startswith('http') and url is None:
598 598 url = data
599 599 filename = None
600 600 data = None
601 601 elif _safe_exists(data) and filename is None:
602 602 url = None
603 603 filename = data
604 604 data = None
605 605
606 606 self.data = data
607 607 self.url = url
608 608 self.filename = filename
609 609
610 610 if metadata is not None:
611 611 self.metadata = metadata
612 612 elif self.metadata is None:
613 613 self.metadata = {}
614 614
615 615 self.reload()
616 616 self._check_data()
617 617
618 618 def __repr__(self):
619 619 if not self._show_mem_addr:
620 620 cls = self.__class__
621 621 r = "<%s.%s object>" % (cls.__module__, cls.__name__)
622 622 else:
623 623 r = super(DisplayObject, self).__repr__()
624 624 return r
625 625
626 626 def _check_data(self):
627 627 """Override in subclasses if there's something to check."""
628 628 pass
629 629
630 630 def _data_and_metadata(self):
631 631 """shortcut for returning metadata with shape information, if defined"""
632 632 if self.metadata:
633 633 return self.data, deepcopy(self.metadata)
634 634 else:
635 635 return self.data
636 636
637 637 def reload(self):
638 638 """Reload the raw data from file or URL."""
639 639 if self.filename is not None:
640 640 with open(self.filename, self._read_flags) as f:
641 641 self.data = f.read()
642 642 elif self.url is not None:
643 643 try:
644 644 # Deferred import
645 645 from urllib.request import urlopen
646 646 response = urlopen(self.url)
647 647 self.data = response.read()
648 648 # extract encoding from header, if there is one:
649 649 encoding = None
650 650 for sub in response.headers['content-type'].split(';'):
651 651 sub = sub.strip()
652 652 if sub.startswith('charset'):
653 653 encoding = sub.split('=')[-1].strip()
654 654 break
655 655 # decode data, if an encoding was specified
656 656 if encoding:
657 657 self.data = self.data.decode(encoding, 'replace')
658 658 except:
659 659 self.data = None
660 660
661 661 class TextDisplayObject(DisplayObject):
662 662 """Validate that display data is text"""
663 663 def _check_data(self):
664 664 if self.data is not None and not isinstance(self.data, str):
665 665 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
666 666
667 667 class Pretty(TextDisplayObject):
668 668
669 669 def _repr_pretty_(self, pp, cycle):
670 670 return pp.text(self.data)
671 671
672 672
673 673 class HTML(TextDisplayObject):
674 674
675 675 def __init__(self, data=None, url=None, filename=None, metadata=None):
676 676 if data and "<iframe " in data and "</iframe>" in data:
677 677 warnings.warn("Consider using IPython.display.IFrame instead")
678 678 super(HTML, self).__init__(data=data, url=url, filename=filename, metadata=metadata)
679 679
680 680 def _repr_html_(self):
681 681 return self._data_and_metadata()
682 682
683 683 def __html__(self):
684 684 """
685 685 This method exists to inform other HTML-using modules (e.g. Markupsafe,
686 686 htmltag, etc) that this object is HTML and does not need things like
687 687 special characters (<>&) escaped.
688 688 """
689 689 return self._repr_html_()
690 690
691 691
692 692 class Markdown(TextDisplayObject):
693 693
694 694 def _repr_markdown_(self):
695 695 return self._data_and_metadata()
696 696
697 697
698 698 class Math(TextDisplayObject):
699 699
700 700 def _repr_latex_(self):
701 701 s = "$$%s$$" % self.data.strip('$')
702 702 if self.metadata:
703 703 return s, deepcopy(self.metadata)
704 704 else:
705 705 return s
706 706
707 707
708 708 class Latex(TextDisplayObject):
709 709
710 710 def _repr_latex_(self):
711 711 return self._data_and_metadata()
712 712
713 713
714 714 class SVG(DisplayObject):
715 715
716 716 _read_flags = 'rb'
717 717 # wrap data in a property, which extracts the <svg> tag, discarding
718 718 # document headers
719 719 _data = None
720 720
721 721 @property
722 722 def data(self):
723 723 return self._data
724 724
725 725 @data.setter
726 726 def data(self, svg):
727 727 if svg is None:
728 728 self._data = None
729 729 return
730 730 # parse into dom object
731 731 from xml.dom import minidom
732 732 x = minidom.parseString(svg)
733 733 # get svg tag (should be 1)
734 734 found_svg = x.getElementsByTagName('svg')
735 735 if found_svg:
736 736 svg = found_svg[0].toxml()
737 737 else:
738 738 # fallback on the input, trust the user
739 739 # but this is probably an error.
740 740 pass
741 741 svg = cast_unicode(svg)
742 742 self._data = svg
743 743
744 744 def _repr_svg_(self):
745 745 return self._data_and_metadata()
746 746
747 747 class ProgressBar(DisplayObject):
748 748 """Progressbar supports displaying a progressbar like element
749 749 """
750 750 def __init__(self, total):
751 751 """Creates a new progressbar
752 752
753 753 Parameters
754 754 ----------
755 755 total : int
756 756 maximum size of the progressbar
757 757 """
758 758 self.total = total
759 759 self._progress = 0
760 760 self.html_width = '60ex'
761 761 self.text_width = 60
762 762 self._display_id = hexlify(os.urandom(8)).decode('ascii')
763 763
764 764 def __repr__(self):
765 765 fraction = self.progress / self.total
766 766 filled = '=' * int(fraction * self.text_width)
767 767 rest = ' ' * (self.text_width - len(filled))
768 768 return '[{}{}] {}/{}'.format(
769 769 filled, rest,
770 770 self.progress, self.total,
771 771 )
772 772
773 773 def _repr_html_(self):
774 774 return "<progress style='width:{}' max='{}' value='{}'></progress>".format(
775 775 self.html_width, self.total, self.progress)
776 776
777 777 def display(self):
778 778 display(self, display_id=self._display_id)
779 779
780 780 def update(self):
781 781 display(self, display_id=self._display_id, update=True)
782 782
783 783 @property
784 784 def progress(self):
785 785 return self._progress
786 786
787 787 @progress.setter
788 788 def progress(self, value):
789 789 self._progress = value
790 790 self.update()
791 791
792 792 def __iter__(self):
793 793 self.display()
794 794 self._progress = -1 # First iteration is 0
795 795 return self
796 796
797 797 def __next__(self):
798 798 """Returns current value and increments display by one."""
799 799 self.progress += 1
800 800 if self.progress < self.total:
801 801 return self.progress
802 802 else:
803 803 raise StopIteration()
804 804
805 805 class JSON(DisplayObject):
806 806 """JSON expects a JSON-able dict or list
807 807
808 808 not an already-serialized JSON string.
809 809
810 810 Scalar types (None, number, string) are not allowed, only dict or list containers.
811 811 """
812 812 # wrap data in a property, which warns about passing already-serialized JSON
813 813 _data = None
814 814 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, root='root', **kwargs):
815 815 """Create a JSON display object given raw data.
816 816
817 817 Parameters
818 818 ----------
819 819 data : dict or list
820 820 JSON data to display. Not an already-serialized JSON string.
821 821 Scalar types (None, number, string) are not allowed, only dict
822 822 or list containers.
823 823 url : unicode
824 824 A URL to download the data from.
825 825 filename : unicode
826 826 Path to a local file to load the data from.
827 827 expanded : boolean
828 828 Metadata to control whether a JSON display component is expanded.
829 829 metadata: dict
830 830 Specify extra metadata to attach to the json display object.
831 831 root : str
832 832 The name of the root element of the JSON tree
833 833 """
834 834 self.metadata = {
835 835 'expanded': expanded,
836 836 'root': root,
837 837 }
838 838 if metadata:
839 839 self.metadata.update(metadata)
840 840 if kwargs:
841 841 self.metadata.update(kwargs)
842 842 super(JSON, self).__init__(data=data, url=url, filename=filename)
843 843
844 844 def _check_data(self):
845 845 if self.data is not None and not isinstance(self.data, (dict, list)):
846 846 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
847 847
848 848 @property
849 849 def data(self):
850 850 return self._data
851 851
852 852 @data.setter
853 853 def data(self, data):
854 854 if isinstance(data, str):
855 855 if getattr(self, 'filename', None) is None:
856 856 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
857 857 data = json.loads(data)
858 858 self._data = data
859 859
860 860 def _data_and_metadata(self):
861 861 return self.data, self.metadata
862 862
863 863 def _repr_json_(self):
864 864 return self._data_and_metadata()
865 865
866 866 _css_t = """var link = document.createElement("link");
867 867 link.ref = "stylesheet";
868 868 link.type = "text/css";
869 869 link.href = "%s";
870 870 document.head.appendChild(link);
871 871 """
872 872
873 873 _lib_t1 = """new Promise(function(resolve, reject) {
874 874 var script = document.createElement("script");
875 875 script.onload = resolve;
876 876 script.onerror = reject;
877 877 script.src = "%s";
878 878 document.head.appendChild(script);
879 879 }).then(() => {
880 880 """
881 881
882 882 _lib_t2 = """
883 883 });"""
884 884
885 885 class GeoJSON(JSON):
886 886 """GeoJSON expects JSON-able dict
887 887
888 888 not an already-serialized JSON string.
889 889
890 890 Scalar types (None, number, string) are not allowed, only dict containers.
891 891 """
892 892
893 893 def __init__(self, *args, **kwargs):
894 894 """Create a GeoJSON display object given raw data.
895 895
896 896 Parameters
897 897 ----------
898 898 data : dict or list
899 899 VegaLite data. Not an already-serialized JSON string.
900 900 Scalar types (None, number, string) are not allowed, only dict
901 901 or list containers.
902 902 url_template : string
903 903 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
904 904 layer_options : dict
905 905 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
906 906 url : unicode
907 907 A URL to download the data from.
908 908 filename : unicode
909 909 Path to a local file to load the data from.
910 910 metadata: dict
911 911 Specify extra metadata to attach to the json display object.
912 912
913 913 Examples
914 914 --------
915 915
916 916 The following will display an interactive map of Mars with a point of
917 917 interest on frontend that do support GeoJSON display.
918 918
919 919 >>> from IPython.display import GeoJSON
920 920
921 921 >>> GeoJSON(data={
922 922 ... "type": "Feature",
923 923 ... "geometry": {
924 924 ... "type": "Point",
925 925 ... "coordinates": [-81.327, 296.038]
926 926 ... }
927 927 ... },
928 928 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
929 929 ... layer_options={
930 930 ... "basemap_id": "celestia_mars-shaded-16k_global",
931 931 ... "attribution" : "Celestia/praesepe",
932 932 ... "minZoom" : 0,
933 933 ... "maxZoom" : 18,
934 934 ... })
935 935 <IPython.core.display.GeoJSON object>
936 936
937 937 In the terminal IPython, you will only see the text representation of
938 938 the GeoJSON object.
939 939
940 940 """
941 941
942 942 super(GeoJSON, self).__init__(*args, **kwargs)
943 943
944 944
945 945 def _ipython_display_(self):
946 946 bundle = {
947 947 'application/geo+json': self.data,
948 948 'text/plain': '<IPython.display.GeoJSON object>'
949 949 }
950 950 metadata = {
951 951 'application/geo+json': self.metadata
952 952 }
953 953 display(bundle, metadata=metadata, raw=True)
954 954
955 955 class Javascript(TextDisplayObject):
956 956
957 957 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
958 958 """Create a Javascript display object given raw data.
959 959
960 960 When this object is returned by an expression or passed to the
961 961 display function, it will result in the data being displayed
962 962 in the frontend. If the data is a URL, the data will first be
963 963 downloaded and then displayed.
964 964
965 965 In the Notebook, the containing element will be available as `element`,
966 966 and jQuery will be available. Content appended to `element` will be
967 967 visible in the output area.
968 968
969 969 Parameters
970 970 ----------
971 971 data : unicode, str or bytes
972 972 The Javascript source code or a URL to download it from.
973 973 url : unicode
974 974 A URL to download the data from.
975 975 filename : unicode
976 976 Path to a local file to load the data from.
977 977 lib : list or str
978 978 A sequence of Javascript library URLs to load asynchronously before
979 979 running the source code. The full URLs of the libraries should
980 980 be given. A single Javascript library URL can also be given as a
981 981 string.
982 982 css: : list or str
983 983 A sequence of css files to load before running the source code.
984 984 The full URLs of the css files should be given. A single css URL
985 985 can also be given as a string.
986 986 """
987 987 if isinstance(lib, str):
988 988 lib = [lib]
989 989 elif lib is None:
990 990 lib = []
991 991 if isinstance(css, str):
992 992 css = [css]
993 993 elif css is None:
994 994 css = []
995 995 if not isinstance(lib, (list,tuple)):
996 996 raise TypeError('expected sequence, got: %r' % lib)
997 997 if not isinstance(css, (list,tuple)):
998 998 raise TypeError('expected sequence, got: %r' % css)
999 999 self.lib = lib
1000 1000 self.css = css
1001 1001 super(Javascript, self).__init__(data=data, url=url, filename=filename)
1002 1002
1003 1003 def _repr_javascript_(self):
1004 1004 r = ''
1005 1005 for c in self.css:
1006 1006 r += _css_t % c
1007 1007 for l in self.lib:
1008 1008 r += _lib_t1 % l
1009 1009 r += self.data
1010 1010 r += _lib_t2*len(self.lib)
1011 1011 return r
1012 1012
1013 1013 # constants for identifying png/jpeg data
1014 1014 _PNG = b'\x89PNG\r\n\x1a\n'
1015 1015 _JPEG = b'\xff\xd8'
1016 1016
1017 1017 def _pngxy(data):
1018 1018 """read the (width, height) from a PNG header"""
1019 1019 ihdr = data.index(b'IHDR')
1020 1020 # next 8 bytes are width/height
1021 1021 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
1022 1022
1023 1023 def _jpegxy(data):
1024 1024 """read the (width, height) from a JPEG header"""
1025 1025 # adapted from http://www.64lines.com/jpeg-width-height
1026 1026
1027 1027 idx = 4
1028 1028 while True:
1029 1029 block_size = struct.unpack('>H', data[idx:idx+2])[0]
1030 1030 idx = idx + block_size
1031 1031 if data[idx:idx+2] == b'\xFF\xC0':
1032 1032 # found Start of Frame
1033 1033 iSOF = idx
1034 1034 break
1035 1035 else:
1036 1036 # read another block
1037 1037 idx += 2
1038 1038
1039 1039 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
1040 1040 return w, h
1041 1041
1042 1042 def _gifxy(data):
1043 1043 """read the (width, height) from a GIF header"""
1044 1044 return struct.unpack('<HH', data[6:10])
1045 1045
1046 1046
1047 1047 class Image(DisplayObject):
1048 1048
1049 1049 _read_flags = 'rb'
1050 1050 _FMT_JPEG = u'jpeg'
1051 1051 _FMT_PNG = u'png'
1052 1052 _FMT_GIF = u'gif'
1053 1053 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
1054 1054 _MIMETYPES = {
1055 1055 _FMT_PNG: 'image/png',
1056 1056 _FMT_JPEG: 'image/jpeg',
1057 1057 _FMT_GIF: 'image/gif',
1058 1058 }
1059 1059
1060 1060 def __init__(self, data=None, url=None, filename=None, format=None,
1061 1061 embed=None, width=None, height=None, retina=False,
1062 1062 unconfined=False, metadata=None):
1063 1063 """Create a PNG/JPEG/GIF image object given raw data.
1064 1064
1065 1065 When this object is returned by an input cell or passed to the
1066 1066 display function, it will result in the image being displayed
1067 1067 in the frontend.
1068 1068
1069 1069 Parameters
1070 1070 ----------
1071 1071 data : unicode, str or bytes
1072 1072 The raw image data or a URL or filename to load the data from.
1073 1073 This always results in embedded image data.
1074 1074 url : unicode
1075 1075 A URL to download the data from. If you specify `url=`,
1076 1076 the image data will not be embedded unless you also specify `embed=True`.
1077 1077 filename : unicode
1078 1078 Path to a local file to load the data from.
1079 1079 Images from a file are always embedded.
1080 1080 format : unicode
1081 1081 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
1082 1082 for format will be inferred from the filename extension.
1083 1083 embed : bool
1084 1084 Should the image data be embedded using a data URI (True) or be
1085 1085 loaded using an <img> tag. Set this to True if you want the image
1086 1086 to be viewable later with no internet connection in the notebook.
1087 1087
1088 1088 Default is `True`, unless the keyword argument `url` is set, then
1089 1089 default value is `False`.
1090 1090
1091 1091 Note that QtConsole is not able to display images if `embed` is set to `False`
1092 1092 width : int
1093 1093 Width in pixels to which to constrain the image in html
1094 1094 height : int
1095 1095 Height in pixels to which to constrain the image in html
1096 1096 retina : bool
1097 1097 Automatically set the width and height to half of the measured
1098 1098 width and height.
1099 1099 This only works for embedded images because it reads the width/height
1100 1100 from image data.
1101 1101 For non-embedded images, you can just set the desired display width
1102 1102 and height directly.
1103 1103 unconfined: bool
1104 1104 Set unconfined=True to disable max-width confinement of the image.
1105 1105 metadata: dict
1106 1106 Specify extra metadata to attach to the image.
1107 1107
1108 1108 Examples
1109 1109 --------
1110 1110 # embedded image data, works in qtconsole and notebook
1111 1111 # when passed positionally, the first arg can be any of raw image data,
1112 1112 # a URL, or a filename from which to load image data.
1113 1113 # The result is always embedding image data for inline images.
1114 1114 Image('http://www.google.fr/images/srpr/logo3w.png')
1115 1115 Image('/path/to/image.jpg')
1116 1116 Image(b'RAW_PNG_DATA...')
1117 1117
1118 1118 # Specifying Image(url=...) does not embed the image data,
1119 1119 # it only generates `<img>` tag with a link to the source.
1120 1120 # This will not work in the qtconsole or offline.
1121 1121 Image(url='http://www.google.fr/images/srpr/logo3w.png')
1122 1122
1123 1123 """
1124 1124 if filename is not None:
1125 1125 ext = self._find_ext(filename)
1126 1126 elif url is not None:
1127 1127 ext = self._find_ext(url)
1128 1128 elif data is None:
1129 1129 raise ValueError("No image data found. Expecting filename, url, or data.")
1130 1130 elif isinstance(data, str) and (
1131 1131 data.startswith('http') or _safe_exists(data)
1132 1132 ):
1133 1133 ext = self._find_ext(data)
1134 1134 else:
1135 1135 ext = None
1136 1136
1137 1137 if format is None:
1138 1138 if ext is not None:
1139 1139 if ext == u'jpg' or ext == u'jpeg':
1140 1140 format = self._FMT_JPEG
1141 1141 elif ext == u'png':
1142 1142 format = self._FMT_PNG
1143 1143 elif ext == u'gif':
1144 1144 format = self._FMT_GIF
1145 1145 else:
1146 1146 format = ext.lower()
1147 1147 elif isinstance(data, bytes):
1148 1148 # infer image type from image data header,
1149 1149 # only if format has not been specified.
1150 1150 if data[:2] == _JPEG:
1151 1151 format = self._FMT_JPEG
1152 1152
1153 1153 # failed to detect format, default png
1154 1154 if format is None:
1155 1155 format = self._FMT_PNG
1156 1156
1157 1157 if format.lower() == 'jpg':
1158 1158 # jpg->jpeg
1159 1159 format = self._FMT_JPEG
1160 1160
1161 1161 self.format = format.lower()
1162 1162 self.embed = embed if embed is not None else (url is None)
1163 1163
1164 1164 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
1165 1165 raise ValueError("Cannot embed the '%s' image format" % (self.format))
1166 1166 if self.embed:
1167 1167 self._mimetype = self._MIMETYPES.get(self.format)
1168 1168
1169 1169 self.width = width
1170 1170 self.height = height
1171 1171 self.retina = retina
1172 1172 self.unconfined = unconfined
1173 1173 super(Image, self).__init__(data=data, url=url, filename=filename,
1174 1174 metadata=metadata)
1175 1175
1176 1176 if self.width is None and self.metadata.get('width', {}):
1177 1177 self.width = metadata['width']
1178 1178
1179 1179 if self.height is None and self.metadata.get('height', {}):
1180 1180 self.height = metadata['height']
1181 1181
1182 1182 if retina:
1183 1183 self._retina_shape()
1184 1184
1185 1185
1186 1186 def _retina_shape(self):
1187 1187 """load pixel-doubled width and height from image data"""
1188 1188 if not self.embed:
1189 1189 return
1190 1190 if self.format == self._FMT_PNG:
1191 1191 w, h = _pngxy(self.data)
1192 1192 elif self.format == self._FMT_JPEG:
1193 1193 w, h = _jpegxy(self.data)
1194 1194 elif self.format == self._FMT_GIF:
1195 1195 w, h = _gifxy(self.data)
1196 1196 else:
1197 1197 # retina only supports png
1198 1198 return
1199 1199 self.width = w // 2
1200 1200 self.height = h // 2
1201 1201
1202 1202 def reload(self):
1203 1203 """Reload the raw data from file or URL."""
1204 1204 if self.embed:
1205 1205 super(Image,self).reload()
1206 1206 if self.retina:
1207 1207 self._retina_shape()
1208 1208
1209 1209 def _repr_html_(self):
1210 1210 if not self.embed:
1211 1211 width = height = klass = ''
1212 1212 if self.width:
1213 1213 width = ' width="%d"' % self.width
1214 1214 if self.height:
1215 1215 height = ' height="%d"' % self.height
1216 1216 if self.unconfined:
1217 1217 klass = ' class="unconfined"'
1218 1218 return u'<img src="{url}"{width}{height}{klass}/>'.format(
1219 1219 url=self.url,
1220 1220 width=width,
1221 1221 height=height,
1222 1222 klass=klass,
1223 1223 )
1224 1224
1225 1225 def _repr_mimebundle_(self, include=None, exclude=None):
1226 1226 """Return the image as a mimebundle
1227 1227
1228 1228 Any new mimetype support should be implemented here.
1229 1229 """
1230 1230 if self.embed:
1231 1231 mimetype = self._mimetype
1232 1232 data, metadata = self._data_and_metadata(always_both=True)
1233 1233 if metadata:
1234 1234 metadata = {mimetype: metadata}
1235 1235 return {mimetype: data}, metadata
1236 1236 else:
1237 1237 return {'text/html': self._repr_html_()}
1238 1238
1239 1239 def _data_and_metadata(self, always_both=False):
1240 1240 """shortcut for returning metadata with shape information, if defined"""
1241 1241 b64_data = b2a_base64(self.data).decode('ascii')
1242 1242 md = {}
1243 1243 if self.metadata:
1244 1244 md.update(self.metadata)
1245 1245 if self.width:
1246 1246 md['width'] = self.width
1247 1247 if self.height:
1248 1248 md['height'] = self.height
1249 1249 if self.unconfined:
1250 1250 md['unconfined'] = self.unconfined
1251 1251 if md or always_both:
1252 1252 return b64_data, md
1253 1253 else:
1254 1254 return b64_data
1255 1255
1256 1256 def _repr_png_(self):
1257 1257 if self.embed and self.format == self._FMT_PNG:
1258 1258 return self._data_and_metadata()
1259 1259
1260 1260 def _repr_jpeg_(self):
1261 1261 if self.embed and self.format == self._FMT_JPEG:
1262 1262 return self._data_and_metadata()
1263 1263
1264 1264 def _find_ext(self, s):
1265 1265 return s.split('.')[-1].lower()
1266 1266
1267 1267
1268 1268 class Video(DisplayObject):
1269 1269
1270 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
1270 def __init__(self, data=None, url=None, filename=None, embed=False,
1271 mimetype=None, width=None, height=None):
1271 1272 """Create a video object given raw data or an URL.
1272 1273
1273 1274 When this object is returned by an input cell or passed to the
1274 1275 display function, it will result in the video being displayed
1275 1276 in the frontend.
1276 1277
1277 1278 Parameters
1278 1279 ----------
1279 1280 data : unicode, str or bytes
1280 1281 The raw video data or a URL or filename to load the data from.
1281 1282 Raw data will require passing `embed=True`.
1282 1283 url : unicode
1283 1284 A URL for the video. If you specify `url=`,
1284 1285 the image data will not be embedded.
1285 1286 filename : unicode
1286 1287 Path to a local file containing the video.
1287 1288 Will be interpreted as a local URL unless `embed=True`.
1288 1289 embed : bool
1289 1290 Should the video be embedded using a data URI (True) or be
1290 1291 loaded using a <video> tag (False).
1291 1292
1292 1293 Since videos are large, embedding them should be avoided, if possible.
1293 1294 You must confirm embedding as your intention by passing `embed=True`.
1294 1295
1295 1296 Local files can be displayed with URLs without embedding the content, via::
1296 1297
1297 1298 Video('./video.mp4')
1298 1299
1299 1300 mimetype: unicode
1300 1301 Specify the mimetype for embedded videos.
1301 1302 Default will be guessed from file extension, if available.
1303 width : int
1304 Width in pixels to which to constrain the video in HTML.
1305 If not supplied, defaults to the width of the video.
1306 height : int
1307 Height in pixels to which to constrain the video in html.
1308 If not supplied, defaults to the height of the video.
1302 1309
1303 1310 Examples
1304 1311 --------
1305 1312
1306 1313 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1307 1314 Video('path/to/video.mp4')
1308 1315 Video('path/to/video.mp4', embed=True)
1309 1316 Video(b'raw-videodata', embed=True)
1310 1317 """
1311 1318 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1312 1319 url = data
1313 1320 data = None
1314 1321 elif os.path.exists(data):
1315 1322 filename = data
1316 1323 data = None
1317 1324
1318 1325 if data and not embed:
1319 1326 msg = ''.join([
1320 1327 "To embed videos, you must pass embed=True ",
1321 1328 "(this may make your notebook files huge)\n",
1322 1329 "Consider passing Video(url='...')",
1323 1330 ])
1324 1331 raise ValueError(msg)
1325 1332
1326 1333 self.mimetype = mimetype
1327 1334 self.embed = embed
1335 self.width = width
1336 self.height = height
1328 1337 super(Video, self).__init__(data=data, url=url, filename=filename)
1329 1338
1330 1339 def _repr_html_(self):
1340 width = height = ''
1341 if self.width:
1342 width = ' width="%d"' % self.width
1343 if self.height:
1344 height = ' height="%d"' % self.height
1345
1331 1346 # External URLs and potentially local files are not embedded into the
1332 1347 # notebook output.
1333 1348 if not self.embed:
1334 1349 url = self.url if self.url is not None else self.filename
1335 output = """<video src="{0}" controls>
1350 output = """<video src="{0}" controls {1} {2}>
1336 1351 Your browser does not support the <code>video</code> element.
1337 </video>""".format(url)
1352 </video>""".format(url, width, height)
1338 1353 return output
1339 1354
1340 1355 # Embedded videos are base64-encoded.
1341 1356 mimetype = self.mimetype
1342 1357 if self.filename is not None:
1343 1358 if not mimetype:
1344 1359 mimetype, _ = mimetypes.guess_type(self.filename)
1345 1360
1346 1361 with open(self.filename, 'rb') as f:
1347 1362 video = f.read()
1348 1363 else:
1349 1364 video = self.data
1350 1365 if isinstance(video, str):
1351 1366 # unicode input is already b64-encoded
1352 1367 b64_video = video
1353 1368 else:
1354 1369 b64_video = b2a_base64(video).decode('ascii').rstrip()
1355 1370
1356 output = """<video controls>
1357 <source src="data:{0};base64,{1}" type="{0}">
1371 output = """<video controls {0} {1}>
1372 <source src="data:{2};base64,{3}" type="{2}">
1358 1373 Your browser does not support the video tag.
1359 </video>""".format(mimetype, b64_video)
1374 </video>""".format(width, height, mimetype, b64_video)
1360 1375 return output
1361 1376
1362 1377 def reload(self):
1363 1378 # TODO
1364 1379 pass
1365 1380
1366 1381
1367 1382 def clear_output(wait=False):
1368 1383 """Clear the output of the current cell receiving output.
1369 1384
1370 1385 Parameters
1371 1386 ----------
1372 1387 wait : bool [default: false]
1373 1388 Wait to clear the output until new output is available to replace it."""
1374 1389 from IPython.core.interactiveshell import InteractiveShell
1375 1390 if InteractiveShell.initialized():
1376 1391 InteractiveShell.instance().display_pub.clear_output(wait)
1377 1392 else:
1378 1393 print('\033[2K\r', end='')
1379 1394 sys.stdout.flush()
1380 1395 print('\033[2K\r', end='')
1381 1396 sys.stderr.flush()
1382 1397
1383 1398
1384 1399 @skip_doctest
1385 1400 def set_matplotlib_formats(*formats, **kwargs):
1386 1401 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1387 1402
1388 1403 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1389 1404
1390 1405 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1391 1406
1392 1407 To set this in your config files use the following::
1393 1408
1394 1409 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1395 1410 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1396 1411
1397 1412 Parameters
1398 1413 ----------
1399 1414 *formats : strs
1400 1415 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1401 1416 **kwargs :
1402 1417 Keyword args will be relayed to ``figure.canvas.print_figure``.
1403 1418 """
1404 1419 from IPython.core.interactiveshell import InteractiveShell
1405 1420 from IPython.core.pylabtools import select_figure_formats
1406 1421 # build kwargs, starting with InlineBackend config
1407 1422 kw = {}
1408 1423 from ipykernel.pylab.config import InlineBackend
1409 1424 cfg = InlineBackend.instance()
1410 1425 kw.update(cfg.print_figure_kwargs)
1411 1426 kw.update(**kwargs)
1412 1427 shell = InteractiveShell.instance()
1413 1428 select_figure_formats(shell, formats, **kw)
1414 1429
1415 1430 @skip_doctest
1416 1431 def set_matplotlib_close(close=True):
1417 1432 """Set whether the inline backend closes all figures automatically or not.
1418 1433
1419 1434 By default, the inline backend used in the IPython Notebook will close all
1420 1435 matplotlib figures automatically after each cell is run. This means that
1421 1436 plots in different cells won't interfere. Sometimes, you may want to make
1422 1437 a plot in one cell and then refine it in later cells. This can be accomplished
1423 1438 by::
1424 1439
1425 1440 In [1]: set_matplotlib_close(False)
1426 1441
1427 1442 To set this in your config files use the following::
1428 1443
1429 1444 c.InlineBackend.close_figures = False
1430 1445
1431 1446 Parameters
1432 1447 ----------
1433 1448 close : bool
1434 1449 Should all matplotlib figures be automatically closed after each cell is
1435 1450 run?
1436 1451 """
1437 1452 from ipykernel.pylab.config import InlineBackend
1438 1453 cfg = InlineBackend.instance()
1439 1454 cfg.close_figures = close
General Comments 0
You need to be logged in to leave comments. Login now