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