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