##// END OF EJS Templates
better doc
Matthias Bussonnier -
Show More
@@ -1,1228 +1,1233 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 The following will display an interactive map of Mars with a point of
660 660 interest on frontend that do support GeoJSON display.
661 661
662 662 >>> from IPython.display import GeoJSON
663 663
664 664 >>> GeoJSON(data={
665 665 ... "type": "Feature",
666 666 ... "geometry": {
667 667 ... "type": "Point",
668 668 ... "coordinates": [-81.327, 296.038]
669 669 ... }
670 670 ... },
671 671 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
672 672 ... layer_options={
673 673 ... "basemap_id": "celestia_mars-shaded-16k_global",
674 674 ... "attribution" : "Celestia/praesepe",
675 675 ... "minZoom" : 0,
676 676 ... "maxZoom" : 18,
677 677 ... })
678 678 <IPython.core.display.GeoJSON object>
679 679
680 680 In the terminal IPython, you will only see the text representation of
681 681 the GeoJSON object.
682 682
683 683 """
684 684
685 685 super(GeoJSON, self).__init__(*args, **kwargs)
686 686
687 687
688 688 def _ipython_display_(self):
689 689 bundle = {
690 690 'application/geo+json': self.data,
691 691 'text/plain': '<IPython.display.GeoJSON object>'
692 692 }
693 693 metadata = {
694 694 'application/geo+json': self.metadata
695 695 }
696 696 display(bundle, metadata=metadata, raw=True)
697 697
698 698 class Javascript(TextDisplayObject):
699 699
700 700 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
701 701 """Create a Javascript display object given raw data.
702 702
703 703 When this object is returned by an expression or passed to the
704 704 display function, it will result in the data being displayed
705 705 in the frontend. If the data is a URL, the data will first be
706 706 downloaded and then displayed.
707 707
708 708 In the Notebook, the containing element will be available as `element`,
709 709 and jQuery will be available. Content appended to `element` will be
710 710 visible in the output area.
711 711
712 712 Parameters
713 713 ----------
714 714 data : unicode, str or bytes
715 715 The Javascript source code or a URL to download it from.
716 716 url : unicode
717 717 A URL to download the data from.
718 718 filename : unicode
719 719 Path to a local file to load the data from.
720 720 lib : list or str
721 721 A sequence of Javascript library URLs to load asynchronously before
722 722 running the source code. The full URLs of the libraries should
723 723 be given. A single Javascript library URL can also be given as a
724 724 string.
725 725 css : list or str
726 726 A sequence of css files to load before running the source code.
727 727 The full URLs of the css files should be given. A single css URL
728 728 can also be given as a string.
729 729 """
730 730 if isinstance(lib, str):
731 731 lib = [lib]
732 732 elif lib is None:
733 733 lib = []
734 734 if isinstance(css, str):
735 735 css = [css]
736 736 elif css is None:
737 737 css = []
738 738 if not isinstance(lib, (list,tuple)):
739 739 raise TypeError('expected sequence, got: %r' % lib)
740 740 if not isinstance(css, (list,tuple)):
741 741 raise TypeError('expected sequence, got: %r' % css)
742 742 self.lib = lib
743 743 self.css = css
744 744 super(Javascript, self).__init__(data=data, url=url, filename=filename)
745 745
746 746 def _repr_javascript_(self):
747 747 r = ''
748 748 for c in self.css:
749 749 r += _css_t % c
750 750 for l in self.lib:
751 751 r += _lib_t1 % l
752 752 r += self.data
753 753 r += _lib_t2*len(self.lib)
754 754 return r
755 755
756 756 # constants for identifying png/jpeg data
757 757 _PNG = b'\x89PNG\r\n\x1a\n'
758 758 _JPEG = b'\xff\xd8'
759 759
760 760 def _pngxy(data):
761 761 """read the (width, height) from a PNG header"""
762 762 ihdr = data.index(b'IHDR')
763 763 # next 8 bytes are width/height
764 764 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
765 765
766 766 def _jpegxy(data):
767 767 """read the (width, height) from a JPEG header"""
768 768 # adapted from http://www.64lines.com/jpeg-width-height
769 769
770 770 idx = 4
771 771 while True:
772 772 block_size = struct.unpack('>H', data[idx:idx+2])[0]
773 773 idx = idx + block_size
774 774 if data[idx:idx+2] == b'\xFF\xC0':
775 775 # found Start of Frame
776 776 iSOF = idx
777 777 break
778 778 else:
779 779 # read another block
780 780 idx += 2
781 781
782 782 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
783 783 return w, h
784 784
785 785 def _gifxy(data):
786 786 """read the (width, height) from a GIF header"""
787 787 return struct.unpack('<HH', data[6:10])
788 788
789 789
790 790 class Image(DisplayObject):
791 791
792 792 _read_flags = 'rb'
793 793 _FMT_JPEG = u'jpeg'
794 794 _FMT_PNG = u'png'
795 795 _FMT_GIF = u'gif'
796 796 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
797 797 _MIMETYPES = {
798 798 _FMT_PNG: 'image/png',
799 799 _FMT_JPEG: 'image/jpeg',
800 800 _FMT_GIF: 'image/gif',
801 801 }
802 802
803 803 def __init__(self, data=None, url=None, filename=None, format=None,
804 804 embed=None, width=None, height=None, retina=False,
805 805 unconfined=False, metadata=None):
806 806 """Create a PNG/JPEG/GIF image object given raw data.
807 807
808 808 When this object is returned by an input cell or passed to the
809 809 display function, it will result in the image being displayed
810 810 in the frontend.
811 811
812 812 Parameters
813 813 ----------
814 814 data : unicode, str or bytes
815 815 The raw image data or a URL or filename to load the data from.
816 816 This always results in embedded image data.
817 817 url : unicode
818 818 A URL to download the data from. If you specify `url=`,
819 819 the image data will not be embedded unless you also specify `embed=True`.
820 820 filename : unicode
821 821 Path to a local file to load the data from.
822 822 Images from a file are always embedded.
823 823 format : unicode
824 824 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
825 825 for format will be inferred from the filename extension.
826 826 embed : bool
827 827 Should the image data be embedded using a data URI (True) or be
828 828 loaded using an <img> tag. Set this to True if you want the image
829 829 to be viewable later with no internet connection in the notebook.
830 830
831 831 Default is `True`, unless the keyword argument `url` is set, then
832 832 default value is `False`.
833 833
834 834 Note that QtConsole is not able to display images if `embed` is set to `False`
835 835 width : int
836 836 Width in pixels to which to constrain the image in html
837 837 height : int
838 838 Height in pixels to which to constrain the image in html
839 839 retina : bool
840 840 Automatically set the width and height to half of the measured
841 841 width and height.
842 842 This only works for embedded images because it reads the width/height
843 843 from image data.
844 844 For non-embedded images, you can just set the desired display width
845 845 and height directly.
846 846 unconfined : bool
847 847 Set unconfined=True to disable max-width confinement of the image.
848 848 metadata : dict
849 849 Specify extra metadata to attach to the image.
850 850
851 851 Examples
852 852 --------
853 853 embedded image data, works in qtconsole and notebook
854 854 when passed positionally, the first arg can be any of raw image data,
855 855 a URL, or a filename from which to load image data.
856 856 The result is always embedding image data for inline images.
857 857
858 858 >>> Image('http://www.google.fr/images/srpr/logo3w.png')
859 859 <IPython.core.display.Image object>
860 860
861 861 >>> Image('/path/to/image.jpg')
862 862 <IPython.core.display.Image object>
863 863
864 864 >>> Image(b'RAW_PNG_DATA...')
865 865 <IPython.core.display.Image object>
866 866
867 867 Specifying Image(url=...) does not embed the image data,
868 868 it only generates ``<img>`` tag with a link to the source.
869 869 This will not work in the qtconsole or offline.
870 870
871 871 >>> Image(url='http://www.google.fr/images/srpr/logo3w.png')
872 872 <IPython.core.display.Image object>
873 873
874 874 """
875 875 if isinstance(data, (Path, PurePath)):
876 876 data = str(data)
877 877
878 878 if filename is not None:
879 879 ext = self._find_ext(filename)
880 880 elif url is not None:
881 881 ext = self._find_ext(url)
882 882 elif data is None:
883 883 raise ValueError("No image data found. Expecting filename, url, or data.")
884 884 elif isinstance(data, str) and (
885 885 data.startswith('http') or _safe_exists(data)
886 886 ):
887 887 ext = self._find_ext(data)
888 888 else:
889 889 ext = None
890 890
891 891 if format is None:
892 892 if ext is not None:
893 893 if ext == u'jpg' or ext == u'jpeg':
894 894 format = self._FMT_JPEG
895 895 elif ext == u'png':
896 896 format = self._FMT_PNG
897 897 elif ext == u'gif':
898 898 format = self._FMT_GIF
899 899 else:
900 900 format = ext.lower()
901 901 elif isinstance(data, bytes):
902 902 # infer image type from image data header,
903 903 # only if format has not been specified.
904 904 if data[:2] == _JPEG:
905 905 format = self._FMT_JPEG
906 906
907 907 # failed to detect format, default png
908 908 if format is None:
909 909 format = self._FMT_PNG
910 910
911 911 if format.lower() == 'jpg':
912 912 # jpg->jpeg
913 913 format = self._FMT_JPEG
914 914
915 915 self.format = format.lower()
916 916 self.embed = embed if embed is not None else (url is None)
917 917
918 918 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
919 919 raise ValueError("Cannot embed the '%s' image format" % (self.format))
920 920 if self.embed:
921 921 self._mimetype = self._MIMETYPES.get(self.format)
922 922
923 923 self.width = width
924 924 self.height = height
925 925 self.retina = retina
926 926 self.unconfined = unconfined
927 927 super(Image, self).__init__(data=data, url=url, filename=filename,
928 928 metadata=metadata)
929 929
930 930 if self.width is None and self.metadata.get('width', {}):
931 931 self.width = metadata['width']
932 932
933 933 if self.height is None and self.metadata.get('height', {}):
934 934 self.height = metadata['height']
935 935
936 936 if retina:
937 937 self._retina_shape()
938 938
939 939
940 940 def _retina_shape(self):
941 941 """load pixel-doubled width and height from image data"""
942 942 if not self.embed:
943 943 return
944 944 if self.format == self._FMT_PNG:
945 945 w, h = _pngxy(self.data)
946 946 elif self.format == self._FMT_JPEG:
947 947 w, h = _jpegxy(self.data)
948 948 elif self.format == self._FMT_GIF:
949 949 w, h = _gifxy(self.data)
950 950 else:
951 951 # retina only supports png
952 952 return
953 953 self.width = w // 2
954 954 self.height = h // 2
955 955
956 956 def reload(self):
957 957 """Reload the raw data from file or URL."""
958 958 if self.embed:
959 959 super(Image,self).reload()
960 960 if self.retina:
961 961 self._retina_shape()
962 962
963 963 def _repr_html_(self):
964 964 if not self.embed:
965 965 width = height = klass = ''
966 966 if self.width:
967 967 width = ' width="%d"' % self.width
968 968 if self.height:
969 969 height = ' height="%d"' % self.height
970 970 if self.unconfined:
971 971 klass = ' class="unconfined"'
972 972 return u'<img src="{url}"{width}{height}{klass}/>'.format(
973 973 url=self.url,
974 974 width=width,
975 975 height=height,
976 976 klass=klass,
977 977 )
978 978
979 979 def _repr_mimebundle_(self, include=None, exclude=None):
980 980 """Return the image as a mimebundle
981 981
982 982 Any new mimetype support should be implemented here.
983 983 """
984 984 if self.embed:
985 985 mimetype = self._mimetype
986 986 data, metadata = self._data_and_metadata(always_both=True)
987 987 if metadata:
988 988 metadata = {mimetype: metadata}
989 989 return {mimetype: data}, metadata
990 990 else:
991 991 return {'text/html': self._repr_html_()}
992 992
993 993 def _data_and_metadata(self, always_both=False):
994 994 """shortcut for returning metadata with shape information, if defined"""
995 995 try:
996 996 b64_data = b2a_base64(self.data).decode('ascii')
997 997 except TypeError as e:
998 998 raise FileNotFoundError(
999 999 "No such file or directory: '%s'" % (self.data)) from e
1000 1000 md = {}
1001 1001 if self.metadata:
1002 1002 md.update(self.metadata)
1003 1003 if self.width:
1004 1004 md['width'] = self.width
1005 1005 if self.height:
1006 1006 md['height'] = self.height
1007 1007 if self.unconfined:
1008 1008 md['unconfined'] = self.unconfined
1009 1009 if md or always_both:
1010 1010 return b64_data, md
1011 1011 else:
1012 1012 return b64_data
1013 1013
1014 1014 def _repr_png_(self):
1015 1015 if self.embed and self.format == self._FMT_PNG:
1016 1016 return self._data_and_metadata()
1017 1017
1018 1018 def _repr_jpeg_(self):
1019 1019 if self.embed and self.format == self._FMT_JPEG:
1020 1020 return self._data_and_metadata()
1021 1021
1022 1022 def _find_ext(self, s):
1023 1023 base, ext = splitext(s)
1024 1024
1025 1025 if not ext:
1026 1026 return base
1027 1027
1028 1028 # `splitext` includes leading period, so we skip it
1029 1029 return ext[1:].lower()
1030 1030
1031 1031
1032 1032 class Video(DisplayObject):
1033 1033
1034 1034 def __init__(self, data=None, url=None, filename=None, embed=False,
1035 1035 mimetype=None, width=None, height=None, html_attributes="controls"):
1036 1036 """Create a video object given raw data or an URL.
1037 1037
1038 1038 When this object is returned by an input cell or passed to the
1039 1039 display function, it will result in the video being displayed
1040 1040 in the frontend.
1041 1041
1042 1042 Parameters
1043 1043 ----------
1044 1044 data : unicode, str or bytes
1045 1045 The raw video data or a URL or filename to load the data from.
1046 1046 Raw data will require passing ``embed=True``.
1047 1047 url : unicode
1048 1048 A URL for the video. If you specify ``url=``,
1049 1049 the image data will not be embedded.
1050 1050 filename : unicode
1051 1051 Path to a local file containing the video.
1052 1052 Will be interpreted as a local URL unless ``embed=True``.
1053 1053 embed : bool
1054 1054 Should the video be embedded using a data URI (True) or be
1055 1055 loaded using a <video> tag (False).
1056 1056
1057 1057 Since videos are large, embedding them should be avoided, if possible.
1058 1058 You must confirm embedding as your intention by passing ``embed=True``.
1059 1059
1060 1060 Local files can be displayed with URLs without embedding the content, via::
1061 1061
1062 1062 Video('./video.mp4')
1063 1063 mimetype : unicode
1064 1064 Specify the mimetype for embedded videos.
1065 1065 Default will be guessed from file extension, if available.
1066 1066 width : int
1067 1067 Width in pixels to which to constrain the video in HTML.
1068 1068 If not supplied, defaults to the width of the video.
1069 1069 height : int
1070 1070 Height in pixels to which to constrain the video in html.
1071 1071 If not supplied, defaults to the height of the video.
1072 1072 html_attributes : str
1073 1073 Attributes for the HTML ``<video>`` block.
1074 1074 Default: ``"controls"`` to get video controls.
1075 1075 Other examples: ``"controls muted"`` for muted video with controls,
1076 1076 ``"loop autoplay"`` for looping autoplaying video without controls.
1077 1077
1078 1078 Examples
1079 1079 --------
1080 1080 ::
1081 1081
1082 1082 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1083 1083 Video('path/to/video.mp4')
1084 1084 Video('path/to/video.mp4', embed=True)
1085 1085 Video('path/to/video.mp4', embed=True, html_attributes="controls muted autoplay")
1086 1086 Video(b'raw-videodata', embed=True)
1087 1087 """
1088 1088 if isinstance(data, (Path, PurePath)):
1089 1089 data = str(data)
1090 1090
1091 1091 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1092 1092 url = data
1093 1093 data = None
1094 1094 elif data is not None and os.path.exists(data):
1095 1095 filename = data
1096 1096 data = None
1097 1097
1098 1098 if data and not embed:
1099 1099 msg = ''.join([
1100 1100 "To embed videos, you must pass embed=True ",
1101 1101 "(this may make your notebook files huge)\n",
1102 1102 "Consider passing Video(url='...')",
1103 1103 ])
1104 1104 raise ValueError(msg)
1105 1105
1106 1106 self.mimetype = mimetype
1107 1107 self.embed = embed
1108 1108 self.width = width
1109 1109 self.height = height
1110 1110 self.html_attributes = html_attributes
1111 1111 super(Video, self).__init__(data=data, url=url, filename=filename)
1112 1112
1113 1113 def _repr_html_(self):
1114 1114 width = height = ''
1115 1115 if self.width:
1116 1116 width = ' width="%d"' % self.width
1117 1117 if self.height:
1118 1118 height = ' height="%d"' % self.height
1119 1119
1120 1120 # External URLs and potentially local files are not embedded into the
1121 1121 # notebook output.
1122 1122 if not self.embed:
1123 1123 url = self.url if self.url is not None else self.filename
1124 1124 output = """<video src="{0}" {1} {2} {3}>
1125 1125 Your browser does not support the <code>video</code> element.
1126 1126 </video>""".format(url, self.html_attributes, width, height)
1127 1127 return output
1128 1128
1129 1129 # Embedded videos are base64-encoded.
1130 1130 mimetype = self.mimetype
1131 1131 if self.filename is not None:
1132 1132 if not mimetype:
1133 1133 mimetype, _ = mimetypes.guess_type(self.filename)
1134 1134
1135 1135 with open(self.filename, 'rb') as f:
1136 1136 video = f.read()
1137 1137 else:
1138 1138 video = self.data
1139 1139 if isinstance(video, str):
1140 1140 # unicode input is already b64-encoded
1141 1141 b64_video = video
1142 1142 else:
1143 1143 b64_video = b2a_base64(video).decode('ascii').rstrip()
1144 1144
1145 1145 output = """<video {0} {1} {2}>
1146 1146 <source src="data:{3};base64,{4}" type="{3}">
1147 1147 Your browser does not support the video tag.
1148 1148 </video>""".format(self.html_attributes, width, height, mimetype, b64_video)
1149 1149 return output
1150 1150
1151 1151 def reload(self):
1152 1152 # TODO
1153 1153 pass
1154 1154
1155 1155
1156 1156 @skip_doctest
1157 1157 def set_matplotlib_formats(*formats, **kwargs):
1158 1158 """
1159 DEPRECATED
1159 .. deprecated:: 7.23
1160
1161 use `matplotlib_inline.backend_inline.set_matplotlib_formats()`
1160 1162
1161 1163 Select figure formats for the inline backend. Optionally pass quality for JPEG.
1162 1164
1163 1165 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1164 1166
1165 1167 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1166 1168
1167 1169 To set this in your config files use the following::
1168 1170
1169 1171 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1170 1172 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1171 1173
1172 1174 Parameters
1173 1175 ----------
1174 1176 *formats : strs
1175 1177 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1176 1178 **kwargs
1177 1179 Keyword args will be relayed to ``figure.canvas.print_figure``.
1178 1180 """
1179 1181 warnings.warn(
1180 "`set_matplotlib_formats` is deprecated, directly use "
1181 "`matplotlib_inline.backend_inline.set_matplotlib_formats()`",
1182 "`set_matplotlib_formats` is deprecated since IPython 7.23, directly "
1183 "use `matplotlib_inline.backend_inline.set_matplotlib_formats()`",
1182 1184 DeprecationWarning,
1183 1185 stacklevel=2,
1184 1186 )
1185 1187
1186 1188 from matplotlib_inline.backend_inline import (
1187 1189 set_matplotlib_formats as set_matplotlib_formats_orig,
1188 1190 )
1189 1191
1190 1192 set_matplotlib_formats_orig(*formats, **kwargs)
1191 1193
1192 1194 @skip_doctest
1193 1195 def set_matplotlib_close(close=True):
1194 1196 """
1195 DEPRECATED
1197 .. deprecated:: 7.23
1198
1199 use `matplotlib_inline.backend_inline.set_matplotlib_close()`
1200
1196 1201
1197 1202 Set whether the inline backend closes all figures automatically or not.
1198 1203
1199 1204 By default, the inline backend used in the IPython Notebook will close all
1200 1205 matplotlib figures automatically after each cell is run. This means that
1201 1206 plots in different cells won't interfere. Sometimes, you may want to make
1202 1207 a plot in one cell and then refine it in later cells. This can be accomplished
1203 1208 by::
1204 1209
1205 1210 In [1]: set_matplotlib_close(False)
1206 1211
1207 1212 To set this in your config files use the following::
1208 1213
1209 1214 c.InlineBackend.close_figures = False
1210 1215
1211 1216 Parameters
1212 1217 ----------
1213 1218 close : bool
1214 1219 Should all matplotlib figures be automatically closed after each cell is
1215 1220 run?
1216 1221 """
1217 1222 warnings.warn(
1218 "`set_matplotlib_close` is deprecated, directly use "
1219 "`matplotlib_inline.backend_inline.set_matplotlib_close()`",
1223 "`set_matplotlib_close` is deprecated since IPython 7.23, directly "
1224 "use `matplotlib_inline.backend_inline.set_matplotlib_close()`",
1220 1225 DeprecationWarning,
1221 1226 stacklevel=2,
1222 1227 )
1223 1228
1224 1229 from matplotlib_inline.backend_inline import (
1225 1230 set_matplotlib_close as set_matplotlib_close_orig,
1226 1231 )
1227 1232
1228 1233 set_matplotlib_close_orig(close)
@@ -1,386 +1,388 b''
1 1 # -*- coding: utf-8 -*-
2 2 """Pylab (matplotlib) support utilities."""
3 3
4 4 # Copyright (c) IPython Development Team.
5 5 # Distributed under the terms of the Modified BSD License.
6 6
7 7 from io import BytesIO
8 8 import warnings
9 9
10 10 from IPython.core.display import _pngxy
11 11 from IPython.utils.decorators import flag_calls
12 12
13 13 # If user specifies a GUI, that dictates the backend, otherwise we read the
14 14 # user's mpl default from the mpl rc structure
15 15 backends = {
16 16 "tk": "TkAgg",
17 17 "gtk": "GTKAgg",
18 18 "gtk3": "GTK3Agg",
19 19 "wx": "WXAgg",
20 20 "qt4": "Qt4Agg",
21 21 "qt5": "Qt5Agg",
22 22 "qt": "Qt5Agg",
23 23 "osx": "MacOSX",
24 24 "nbagg": "nbAgg",
25 25 "notebook": "nbAgg",
26 26 "agg": "agg",
27 27 "svg": "svg",
28 28 "pdf": "pdf",
29 29 "ps": "ps",
30 30 "inline": "module://matplotlib_inline.backend_inline",
31 31 "ipympl": "module://ipympl.backend_nbagg",
32 32 "widget": "module://ipympl.backend_nbagg",
33 33 }
34 34
35 35 # We also need a reverse backends2guis mapping that will properly choose which
36 36 # GUI support to activate based on the desired matplotlib backend. For the
37 37 # most part it's just a reverse of the above dict, but we also need to add a
38 38 # few others that map to the same GUI manually:
39 39 backend2gui = dict(zip(backends.values(), backends.keys()))
40 40 # Our tests expect backend2gui to just return 'qt'
41 41 backend2gui['Qt4Agg'] = 'qt'
42 42 # In the reverse mapping, there are a few extra valid matplotlib backends that
43 43 # map to the same GUI support
44 44 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
45 45 backend2gui['GTK3Cairo'] = 'gtk3'
46 46 backend2gui['WX'] = 'wx'
47 47 backend2gui['CocoaAgg'] = 'osx'
48 48 # And some backends that don't need GUI integration
49 49 del backend2gui["nbAgg"]
50 50 del backend2gui["agg"]
51 51 del backend2gui["svg"]
52 52 del backend2gui["pdf"]
53 53 del backend2gui["ps"]
54 54 del backend2gui["module://matplotlib_inline.backend_inline"]
55 55
56 56 #-----------------------------------------------------------------------------
57 57 # Matplotlib utilities
58 58 #-----------------------------------------------------------------------------
59 59
60 60
61 61 def getfigs(*fig_nums):
62 62 """Get a list of matplotlib figures by figure numbers.
63 63
64 64 If no arguments are given, all available figures are returned. If the
65 65 argument list contains references to invalid figures, a warning is printed
66 66 but the function continues pasting further figures.
67 67
68 68 Parameters
69 69 ----------
70 70 figs : tuple
71 71 A tuple of ints giving the figure numbers of the figures to return.
72 72 """
73 73 from matplotlib._pylab_helpers import Gcf
74 74 if not fig_nums:
75 75 fig_managers = Gcf.get_all_fig_managers()
76 76 return [fm.canvas.figure for fm in fig_managers]
77 77 else:
78 78 figs = []
79 79 for num in fig_nums:
80 80 f = Gcf.figs.get(num)
81 81 if f is None:
82 82 print('Warning: figure %s not available.' % num)
83 83 else:
84 84 figs.append(f.canvas.figure)
85 85 return figs
86 86
87 87
88 88 def figsize(sizex, sizey):
89 89 """Set the default figure size to be [sizex, sizey].
90 90
91 91 This is just an easy to remember, convenience wrapper that sets::
92 92
93 93 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
94 94 """
95 95 import matplotlib
96 96 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
97 97
98 98
99 99 def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
100 100 """Print a figure to an image, and return the resulting file data
101 101
102 102 Returned data will be bytes unless ``fmt='svg'``,
103 103 in which case it will be unicode.
104 104
105 105 Any keyword args are passed to fig.canvas.print_figure,
106 106 such as ``quality`` or ``bbox_inches``.
107 107 """
108 108 # When there's an empty figure, we shouldn't return anything, otherwise we
109 109 # get big blank areas in the qt console.
110 110 if not fig.axes and not fig.lines:
111 111 return
112 112
113 113 dpi = fig.dpi
114 114 if fmt == 'retina':
115 115 dpi = dpi * 2
116 116 fmt = 'png'
117 117
118 118 # build keyword args
119 119 kw = {
120 120 "format":fmt,
121 121 "facecolor":fig.get_facecolor(),
122 122 "edgecolor":fig.get_edgecolor(),
123 123 "dpi":dpi,
124 124 "bbox_inches":bbox_inches,
125 125 }
126 126 # **kwargs get higher priority
127 127 kw.update(kwargs)
128 128
129 129 bytes_io = BytesIO()
130 130 if fig.canvas is None:
131 131 from matplotlib.backend_bases import FigureCanvasBase
132 132 FigureCanvasBase(fig)
133 133
134 134 fig.canvas.print_figure(bytes_io, **kw)
135 135 data = bytes_io.getvalue()
136 136 if fmt == 'svg':
137 137 data = data.decode('utf-8')
138 138 return data
139 139
140 140 def retina_figure(fig, **kwargs):
141 141 """format a figure as a pixel-doubled (retina) PNG"""
142 142 pngdata = print_figure(fig, fmt='retina', **kwargs)
143 143 # Make sure that retina_figure acts just like print_figure and returns
144 144 # None when the figure is empty.
145 145 if pngdata is None:
146 146 return
147 147 w, h = _pngxy(pngdata)
148 148 metadata = {"width": w//2, "height":h//2}
149 149 return pngdata, metadata
150 150
151 151 # We need a little factory function here to create the closure where
152 152 # safe_execfile can live.
153 153 def mpl_runner(safe_execfile):
154 154 """Factory to return a matplotlib-enabled runner for %run.
155 155
156 156 Parameters
157 157 ----------
158 158 safe_execfile : function
159 159 This must be a function with the same interface as the
160 160 :meth:`safe_execfile` method of IPython.
161 161
162 162 Returns
163 163 -------
164 164 A function suitable for use as the ``runner`` argument of the %run magic
165 165 function.
166 166 """
167 167
168 168 def mpl_execfile(fname,*where,**kw):
169 169 """matplotlib-aware wrapper around safe_execfile.
170 170
171 171 Its interface is identical to that of the :func:`execfile` builtin.
172 172
173 173 This is ultimately a call to execfile(), but wrapped in safeties to
174 174 properly handle interactive rendering."""
175 175
176 176 import matplotlib
177 177 import matplotlib.pyplot as plt
178 178
179 179 #print '*** Matplotlib runner ***' # dbg
180 180 # turn off rendering until end of script
181 181 is_interactive = matplotlib.rcParams['interactive']
182 182 matplotlib.interactive(False)
183 183 safe_execfile(fname,*where,**kw)
184 184 matplotlib.interactive(is_interactive)
185 185 # make rendering call now, if the user tried to do it
186 186 if plt.draw_if_interactive.called:
187 187 plt.draw()
188 188 plt.draw_if_interactive.called = False
189 189
190 190 # re-draw everything that is stale
191 191 try:
192 192 da = plt.draw_all
193 193 except AttributeError:
194 194 pass
195 195 else:
196 196 da()
197 197
198 198 return mpl_execfile
199 199
200 200
201 201 def _reshow_nbagg_figure(fig):
202 202 """reshow an nbagg figure"""
203 203 try:
204 204 reshow = fig.canvas.manager.reshow
205 205 except AttributeError as e:
206 206 raise NotImplementedError() from e
207 207 else:
208 208 reshow()
209 209
210 210
211 211 def select_figure_formats(shell, formats, **kwargs):
212 212 """Select figure formats for the inline backend.
213 213
214 214 Parameters
215 215 ==========
216 216 shell : InteractiveShell
217 217 The main IPython instance.
218 218 formats : str or set
219 219 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
220 220 **kwargs : any
221 221 Extra keyword arguments to be passed to fig.canvas.print_figure.
222 222 """
223 223 import matplotlib
224 224 from matplotlib.figure import Figure
225 225
226 226 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
227 227 png_formatter = shell.display_formatter.formatters['image/png']
228 228 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
229 229 pdf_formatter = shell.display_formatter.formatters['application/pdf']
230 230
231 231 if isinstance(formats, str):
232 232 formats = {formats}
233 233 # cast in case of list / tuple
234 234 formats = set(formats)
235 235
236 236 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
237 237 mplbackend = matplotlib.get_backend().lower()
238 238 if mplbackend == 'nbagg' or mplbackend == 'module://ipympl.backend_nbagg':
239 239 formatter = shell.display_formatter.ipython_display_formatter
240 240 formatter.for_type(Figure, _reshow_nbagg_figure)
241 241
242 242 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
243 243 bad = formats.difference(supported)
244 244 if bad:
245 245 bs = "%s" % ','.join([repr(f) for f in bad])
246 246 gs = "%s" % ','.join([repr(f) for f in supported])
247 247 raise ValueError("supported formats are: %s not %s" % (gs, bs))
248 248
249 249 if 'png' in formats:
250 250 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
251 251 if 'retina' in formats or 'png2x' in formats:
252 252 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
253 253 if 'jpg' in formats or 'jpeg' in formats:
254 254 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
255 255 if 'svg' in formats:
256 256 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
257 257 if 'pdf' in formats:
258 258 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
259 259
260 260 #-----------------------------------------------------------------------------
261 261 # Code for initializing matplotlib and importing pylab
262 262 #-----------------------------------------------------------------------------
263 263
264 264
265 265 def find_gui_and_backend(gui=None, gui_select=None):
266 266 """Given a gui string return the gui and mpl backend.
267 267
268 268 Parameters
269 269 ----------
270 270 gui : str
271 271 Can be one of ('tk','gtk','wx','qt','qt4','inline','agg').
272 272 gui_select : str
273 273 Can be one of ('tk','gtk','wx','qt','qt4','inline').
274 274 This is any gui already selected by the shell.
275 275
276 276 Returns
277 277 -------
278 278 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
279 279 'WXAgg','Qt4Agg','module://matplotlib_inline.backend_inline','agg').
280 280 """
281 281
282 282 import matplotlib
283 283
284 284 if gui and gui != 'auto':
285 285 # select backend based on requested gui
286 286 backend = backends[gui]
287 287 if gui == 'agg':
288 288 gui = None
289 289 else:
290 290 # We need to read the backend from the original data structure, *not*
291 291 # from mpl.rcParams, since a prior invocation of %matplotlib may have
292 292 # overwritten that.
293 293 # WARNING: this assumes matplotlib 1.1 or newer!!
294 294 backend = matplotlib.rcParamsOrig['backend']
295 295 # In this case, we need to find what the appropriate gui selection call
296 296 # should be for IPython, so we can activate inputhook accordingly
297 297 gui = backend2gui.get(backend, None)
298 298
299 299 # If we have already had a gui active, we need it and inline are the
300 300 # ones allowed.
301 301 if gui_select and gui != gui_select:
302 302 gui = gui_select
303 303 backend = backends[gui]
304 304
305 305 return gui, backend
306 306
307 307
308 308 def activate_matplotlib(backend):
309 309 """Activate the given backend and set interactive to True."""
310 310
311 311 import matplotlib
312 312 matplotlib.interactive(True)
313 313
314 314 # Matplotlib had a bug where even switch_backend could not force
315 315 # the rcParam to update. This needs to be set *before* the module
316 316 # magic of switch_backend().
317 317 matplotlib.rcParams['backend'] = backend
318 318
319 319 # Due to circular imports, pyplot may be only partially initialised
320 320 # when this function runs.
321 321 # So avoid needing matplotlib attribute-lookup to access pyplot.
322 322 from matplotlib import pyplot as plt
323 323
324 324 plt.switch_backend(backend)
325 325
326 326 plt.show._needmain = False
327 327 # We need to detect at runtime whether show() is called by the user.
328 328 # For this, we wrap it into a decorator which adds a 'called' flag.
329 329 plt.draw_if_interactive = flag_calls(plt.draw_if_interactive)
330 330
331 331
332 332 def import_pylab(user_ns, import_all=True):
333 333 """Populate the namespace with pylab-related values.
334 334
335 335 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
336 336
337 337 Also imports a few names from IPython (figsize, display, getfigs)
338 338
339 339 """
340 340
341 341 # Import numpy as np/pyplot as plt are conventions we're trying to
342 342 # somewhat standardize on. Making them available to users by default
343 343 # will greatly help this.
344 344 s = ("import numpy\n"
345 345 "import matplotlib\n"
346 346 "from matplotlib import pylab, mlab, pyplot\n"
347 347 "np = numpy\n"
348 348 "plt = pyplot\n"
349 349 )
350 350 exec(s, user_ns)
351 351
352 352 if import_all:
353 353 s = ("from matplotlib.pylab import *\n"
354 354 "from numpy import *\n")
355 355 exec(s, user_ns)
356 356
357 357 # IPython symbols to add
358 358 user_ns['figsize'] = figsize
359 359 from IPython.display import display
360 360 # Add display and getfigs to the user's namespace
361 361 user_ns['display'] = display
362 362 user_ns['getfigs'] = getfigs
363 363
364 364
365 365 def configure_inline_support(shell, backend):
366 366 """
367 DEPRECATED
367 .. deprecated: 7.23
368
369 use `matplotlib_inline.backend_inline.configure_inline_support()`
368 370
369 371 Configure an IPython shell object for matplotlib use.
370 372
371 373 Parameters
372 374 ----------
373 375 shell : InteractiveShell instance
374 376
375 377 backend : matplotlib backend
376 378 """
377 379 warnings.warn(
378 "`configure_inline_support` is deprecated, directly use "
379 "`matplotlib_inline.backend_inline.configure_inline_support()`",
380 "`configure_inline_support` is deprecated since IPython 7.23, directly "
381 "use `matplotlib_inline.backend_inline.configure_inline_support()`",
380 382 DeprecationWarning,
381 383 stacklevel=2,
382 384 )
383 385
384 386 from matplotlib_inline.backend_inline import configure_inline_support_orig
385 387
386 388 configure_inline_support_orig(shell, backend)
General Comments 0
You need to be logged in to leave comments. Login now