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