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