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