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