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