##// END OF EJS Templates
Minimal progressbar primitive...
Marius van Niekerk -
Show More
@@ -1,1354 +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 from binascii import b2a_hex, b2a_base64
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):
732 """Progressbar supports displaying a progressbar like element
733 """
734 def __init__(self, total):
735 """Creates a new progressbar
736
737 Parameters
738 ----------
739 total : int
740 maximnum size of the progressbar
741 """
742 self._display_id = hexlify(os.urandom(8)).decode('ascii')
743 self.total = total
744 self._progress = 0
745
746 def _repr_html_(self):
747 return "<progress style='width:100%' max='{}' value='{}'></progress>".format(self.total, self.progress)
748
749 def display(self):
750 display(self, display_id=self._display_id)
751
752 def update(self):
753 display(self, display_id=self._display_id, update=True)
754
755 @property
756 def progress(self):
757 return self._progress
758
759 @progress.setter
760 def progress(self, value):
761 self._progress = value
762 self.update()
731 763
732 764 class JSON(DisplayObject):
733 765 """JSON expects a JSON-able dict or list
734 766
735 767 not an already-serialized JSON string.
736 768
737 769 Scalar types (None, number, string) are not allowed, only dict or list containers.
738 770 """
739 771 # wrap data in a property, which warns about passing already-serialized JSON
740 772 _data = None
741 773 def __init__(self, data=None, url=None, filename=None, expanded=False, metadata=None, **kwargs):
742 774 """Create a JSON display object given raw data.
743 775
744 776 Parameters
745 777 ----------
746 778 data : dict or list
747 779 JSON data to display. Not an already-serialized JSON string.
748 780 Scalar types (None, number, string) are not allowed, only dict
749 781 or list containers.
750 782 url : unicode
751 783 A URL to download the data from.
752 784 filename : unicode
753 785 Path to a local file to load the data from.
754 786 expanded : boolean
755 787 Metadata to control whether a JSON display component is expanded.
756 788 metadata: dict
757 789 Specify extra metadata to attach to the json display object.
758 790 """
759 791 self.metadata = {'expanded': expanded}
760 792 if metadata:
761 793 self.metadata.update(metadata)
762 794 if kwargs:
763 795 self.metadata.update(kwargs)
764 796 super(JSON, self).__init__(data=data, url=url, filename=filename)
765 797
766 798 def _check_data(self):
767 799 if self.data is not None and not isinstance(self.data, (dict, list)):
768 800 raise TypeError("%s expects JSONable dict or list, not %r" % (self.__class__.__name__, self.data))
769 801
770 802 @property
771 803 def data(self):
772 804 return self._data
773 805
774 806 @data.setter
775 807 def data(self, data):
776 808 if isinstance(data, str):
777 809 if getattr(self, 'filename', None) is None:
778 810 warnings.warn("JSON expects JSONable dict or list, not JSON strings")
779 811 data = json.loads(data)
780 812 self._data = data
781 813
782 814 def _data_and_metadata(self):
783 815 return self.data, self.metadata
784 816
785 817 def _repr_json_(self):
786 818 return self._data_and_metadata()
787 819
788 820 _css_t = """$("head").append($("<link/>").attr({
789 821 rel: "stylesheet",
790 822 type: "text/css",
791 823 href: "%s"
792 824 }));
793 825 """
794 826
795 827 _lib_t1 = """$.getScript("%s", function () {
796 828 """
797 829 _lib_t2 = """});
798 830 """
799 831
800 832 class GeoJSON(JSON):
801 833 """GeoJSON expects JSON-able dict
802 834
803 835 not an already-serialized JSON string.
804 836
805 837 Scalar types (None, number, string) are not allowed, only dict containers.
806 838 """
807 839
808 840 def __init__(self, *args, **kwargs):
809 841 """Create a GeoJSON display object given raw data.
810 842
811 843 Parameters
812 844 ----------
813 845 data : dict or list
814 846 VegaLite data. Not an already-serialized JSON string.
815 847 Scalar types (None, number, string) are not allowed, only dict
816 848 or list containers.
817 849 url_template : string
818 850 Leaflet TileLayer URL template: http://leafletjs.com/reference.html#url-template
819 851 layer_options : dict
820 852 Leaflet TileLayer options: http://leafletjs.com/reference.html#tilelayer-options
821 853 url : unicode
822 854 A URL to download the data from.
823 855 filename : unicode
824 856 Path to a local file to load the data from.
825 857 metadata: dict
826 858 Specify extra metadata to attach to the json display object.
827 859
828 860 Examples
829 861 --------
830 862
831 863 The following will display an interactive map of Mars with a point of
832 864 interest on frontend that do support GeoJSON display.
833 865
834 866 >>> from IPython.display import GeoJSON
835 867
836 868 >>> GeoJSON(data={
837 869 ... "type": "Feature",
838 870 ... "geometry": {
839 871 ... "type": "Point",
840 872 ... "coordinates": [-81.327, 296.038]
841 873 ... }
842 874 ... },
843 875 ... url_template="http://s3-eu-west-1.amazonaws.com/whereonmars.cartodb.net/{basemap_id}/{z}/{x}/{y}.png",
844 876 ... layer_options={
845 877 ... "basemap_id": "celestia_mars-shaded-16k_global",
846 878 ... "attribution" : "Celestia/praesepe",
847 879 ... "minZoom" : 0,
848 880 ... "maxZoom" : 18,
849 881 ... })
850 882 <IPython.core.display.GeoJSON object>
851 883
852 884 In the terminal IPython, you will only see the text representation of
853 885 the GeoJSON object.
854 886
855 887 """
856 888
857 889 super(GeoJSON, self).__init__(*args, **kwargs)
858 890
859 891
860 892 def _ipython_display_(self):
861 893 bundle = {
862 894 'application/geo+json': self.data,
863 895 'text/plain': '<IPython.display.GeoJSON object>'
864 896 }
865 897 metadata = {
866 898 'application/geo+json': self.metadata
867 899 }
868 900 display(bundle, metadata=metadata, raw=True)
869 901
870 902 class Javascript(TextDisplayObject):
871 903
872 904 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
873 905 """Create a Javascript display object given raw data.
874 906
875 907 When this object is returned by an expression or passed to the
876 908 display function, it will result in the data being displayed
877 909 in the frontend. If the data is a URL, the data will first be
878 910 downloaded and then displayed.
879 911
880 912 In the Notebook, the containing element will be available as `element`,
881 913 and jQuery will be available. Content appended to `element` will be
882 914 visible in the output area.
883 915
884 916 Parameters
885 917 ----------
886 918 data : unicode, str or bytes
887 919 The Javascript source code or a URL to download it from.
888 920 url : unicode
889 921 A URL to download the data from.
890 922 filename : unicode
891 923 Path to a local file to load the data from.
892 924 lib : list or str
893 925 A sequence of Javascript library URLs to load asynchronously before
894 926 running the source code. The full URLs of the libraries should
895 927 be given. A single Javascript library URL can also be given as a
896 928 string.
897 929 css: : list or str
898 930 A sequence of css files to load before running the source code.
899 931 The full URLs of the css files should be given. A single css URL
900 932 can also be given as a string.
901 933 """
902 934 if isinstance(lib, str):
903 935 lib = [lib]
904 936 elif lib is None:
905 937 lib = []
906 938 if isinstance(css, str):
907 939 css = [css]
908 940 elif css is None:
909 941 css = []
910 942 if not isinstance(lib, (list,tuple)):
911 943 raise TypeError('expected sequence, got: %r' % lib)
912 944 if not isinstance(css, (list,tuple)):
913 945 raise TypeError('expected sequence, got: %r' % css)
914 946 self.lib = lib
915 947 self.css = css
916 948 super(Javascript, self).__init__(data=data, url=url, filename=filename)
917 949
918 950 def _repr_javascript_(self):
919 951 r = ''
920 952 for c in self.css:
921 953 r += _css_t % c
922 954 for l in self.lib:
923 955 r += _lib_t1 % l
924 956 r += self.data
925 957 r += _lib_t2*len(self.lib)
926 958 return r
927 959
928 960 # constants for identifying png/jpeg data
929 961 _PNG = b'\x89PNG\r\n\x1a\n'
930 962 _JPEG = b'\xff\xd8'
931 963
932 964 def _pngxy(data):
933 965 """read the (width, height) from a PNG header"""
934 966 ihdr = data.index(b'IHDR')
935 967 # next 8 bytes are width/height
936 968 return struct.unpack('>ii', data[ihdr+4:ihdr+12])
937 969
938 970 def _jpegxy(data):
939 971 """read the (width, height) from a JPEG header"""
940 972 # adapted from http://www.64lines.com/jpeg-width-height
941 973
942 974 idx = 4
943 975 while True:
944 976 block_size = struct.unpack('>H', data[idx:idx+2])[0]
945 977 idx = idx + block_size
946 978 if data[idx:idx+2] == b'\xFF\xC0':
947 979 # found Start of Frame
948 980 iSOF = idx
949 981 break
950 982 else:
951 983 # read another block
952 984 idx += 2
953 985
954 986 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
955 987 return w, h
956 988
957 989 def _gifxy(data):
958 990 """read the (width, height) from a GIF header"""
959 991 return struct.unpack('<HH', data[6:10])
960 992
961 993
962 994 class Image(DisplayObject):
963 995
964 996 _read_flags = 'rb'
965 997 _FMT_JPEG = u'jpeg'
966 998 _FMT_PNG = u'png'
967 999 _FMT_GIF = u'gif'
968 1000 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG, _FMT_GIF]
969 1001 _MIMETYPES = {
970 1002 _FMT_PNG: 'image/png',
971 1003 _FMT_JPEG: 'image/jpeg',
972 1004 _FMT_GIF: 'image/gif',
973 1005 }
974 1006
975 1007 def __init__(self, data=None, url=None, filename=None, format=None,
976 1008 embed=None, width=None, height=None, retina=False,
977 1009 unconfined=False, metadata=None):
978 1010 """Create a PNG/JPEG/GIF image object given raw data.
979 1011
980 1012 When this object is returned by an input cell or passed to the
981 1013 display function, it will result in the image being displayed
982 1014 in the frontend.
983 1015
984 1016 Parameters
985 1017 ----------
986 1018 data : unicode, str or bytes
987 1019 The raw image data or a URL or filename to load the data from.
988 1020 This always results in embedded image data.
989 1021 url : unicode
990 1022 A URL to download the data from. If you specify `url=`,
991 1023 the image data will not be embedded unless you also specify `embed=True`.
992 1024 filename : unicode
993 1025 Path to a local file to load the data from.
994 1026 Images from a file are always embedded.
995 1027 format : unicode
996 1028 The format of the image data (png/jpeg/jpg/gif). If a filename or URL is given
997 1029 for format will be inferred from the filename extension.
998 1030 embed : bool
999 1031 Should the image data be embedded using a data URI (True) or be
1000 1032 loaded using an <img> tag. Set this to True if you want the image
1001 1033 to be viewable later with no internet connection in the notebook.
1002 1034
1003 1035 Default is `True`, unless the keyword argument `url` is set, then
1004 1036 default value is `False`.
1005 1037
1006 1038 Note that QtConsole is not able to display images if `embed` is set to `False`
1007 1039 width : int
1008 1040 Width in pixels to which to constrain the image in html
1009 1041 height : int
1010 1042 Height in pixels to which to constrain the image in html
1011 1043 retina : bool
1012 1044 Automatically set the width and height to half of the measured
1013 1045 width and height.
1014 1046 This only works for embedded images because it reads the width/height
1015 1047 from image data.
1016 1048 For non-embedded images, you can just set the desired display width
1017 1049 and height directly.
1018 1050 unconfined: bool
1019 1051 Set unconfined=True to disable max-width confinement of the image.
1020 1052 metadata: dict
1021 1053 Specify extra metadata to attach to the image.
1022 1054
1023 1055 Examples
1024 1056 --------
1025 1057 # embedded image data, works in qtconsole and notebook
1026 1058 # when passed positionally, the first arg can be any of raw image data,
1027 1059 # a URL, or a filename from which to load image data.
1028 1060 # The result is always embedding image data for inline images.
1029 1061 Image('http://www.google.fr/images/srpr/logo3w.png')
1030 1062 Image('/path/to/image.jpg')
1031 1063 Image(b'RAW_PNG_DATA...')
1032 1064
1033 1065 # Specifying Image(url=...) does not embed the image data,
1034 1066 # it only generates `<img>` tag with a link to the source.
1035 1067 # This will not work in the qtconsole or offline.
1036 1068 Image(url='http://www.google.fr/images/srpr/logo3w.png')
1037 1069
1038 1070 """
1039 1071 if filename is not None:
1040 1072 ext = self._find_ext(filename)
1041 1073 elif url is not None:
1042 1074 ext = self._find_ext(url)
1043 1075 elif data is None:
1044 1076 raise ValueError("No image data found. Expecting filename, url, or data.")
1045 1077 elif isinstance(data, str) and (
1046 1078 data.startswith('http') or _safe_exists(data)
1047 1079 ):
1048 1080 ext = self._find_ext(data)
1049 1081 else:
1050 1082 ext = None
1051 1083
1052 1084 if format is None:
1053 1085 if ext is not None:
1054 1086 if ext == u'jpg' or ext == u'jpeg':
1055 1087 format = self._FMT_JPEG
1056 1088 if ext == u'png':
1057 1089 format = self._FMT_PNG
1058 1090 if ext == u'gif':
1059 1091 format = self._FMT_GIF
1060 1092 else:
1061 1093 format = ext.lower()
1062 1094 elif isinstance(data, bytes):
1063 1095 # infer image type from image data header,
1064 1096 # only if format has not been specified.
1065 1097 if data[:2] == _JPEG:
1066 1098 format = self._FMT_JPEG
1067 1099
1068 1100 # failed to detect format, default png
1069 1101 if format is None:
1070 1102 format = self._FMT_PNG
1071 1103
1072 1104 if format.lower() == 'jpg':
1073 1105 # jpg->jpeg
1074 1106 format = self._FMT_JPEG
1075 1107
1076 1108 self.format = format.lower()
1077 1109 self.embed = embed if embed is not None else (url is None)
1078 1110
1079 1111 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
1080 1112 raise ValueError("Cannot embed the '%s' image format" % (self.format))
1081 1113 if self.embed:
1082 1114 self._mimetype = self._MIMETYPES.get(self.format)
1083 1115
1084 1116 self.width = width
1085 1117 self.height = height
1086 1118 self.retina = retina
1087 1119 self.unconfined = unconfined
1088 1120 super(Image, self).__init__(data=data, url=url, filename=filename,
1089 1121 metadata=metadata)
1090 1122
1091 1123 if self.width is None and self.metadata.get('width', {}):
1092 1124 self.width = metadata['width']
1093 1125
1094 1126 if self.height is None and self.metadata.get('height', {}):
1095 1127 self.height = metadata['height']
1096 1128
1097 1129 if retina:
1098 1130 self._retina_shape()
1099 1131
1100 1132
1101 1133 def _retina_shape(self):
1102 1134 """load pixel-doubled width and height from image data"""
1103 1135 if not self.embed:
1104 1136 return
1105 1137 if self.format == self._FMT_PNG:
1106 1138 w, h = _pngxy(self.data)
1107 1139 elif self.format == self._FMT_JPEG:
1108 1140 w, h = _jpegxy(self.data)
1109 1141 elif self.format == self._FMT_GIF:
1110 1142 w, h = _gifxy(self.data)
1111 1143 else:
1112 1144 # retina only supports png
1113 1145 return
1114 1146 self.width = w // 2
1115 1147 self.height = h // 2
1116 1148
1117 1149 def reload(self):
1118 1150 """Reload the raw data from file or URL."""
1119 1151 if self.embed:
1120 1152 super(Image,self).reload()
1121 1153 if self.retina:
1122 1154 self._retina_shape()
1123 1155
1124 1156 def _repr_html_(self):
1125 1157 if not self.embed:
1126 1158 width = height = klass = ''
1127 1159 if self.width:
1128 1160 width = ' width="%d"' % self.width
1129 1161 if self.height:
1130 1162 height = ' height="%d"' % self.height
1131 1163 if self.unconfined:
1132 1164 klass = ' class="unconfined"'
1133 1165 return u'<img src="{url}"{width}{height}{klass}/>'.format(
1134 1166 url=self.url,
1135 1167 width=width,
1136 1168 height=height,
1137 1169 klass=klass,
1138 1170 )
1139 1171
1140 1172 def _repr_mimebundle_(self, include=None, exclude=None):
1141 1173 """Return the image as a mimebundle
1142 1174
1143 1175 Any new mimetype support should be implemented here.
1144 1176 """
1145 1177 if self.embed:
1146 1178 mimetype = self._mimetype
1147 1179 data, metadata = self._data_and_metadata(always_both=True)
1148 1180 if metadata:
1149 1181 metadata = {mimetype: metadata}
1150 1182 return {mimetype: data}, metadata
1151 1183 else:
1152 1184 return {'text/html': self._repr_html_()}
1153 1185
1154 1186 def _data_and_metadata(self, always_both=False):
1155 1187 """shortcut for returning metadata with shape information, if defined"""
1156 1188 b64_data = b2a_base64(self.data).decode('ascii')
1157 1189 md = {}
1158 1190 if self.metadata:
1159 1191 md.update(self.metadata)
1160 1192 if self.width:
1161 1193 md['width'] = self.width
1162 1194 if self.height:
1163 1195 md['height'] = self.height
1164 1196 if self.unconfined:
1165 1197 md['unconfined'] = self.unconfined
1166 1198 if md or always_both:
1167 1199 return b64_data, md
1168 1200 else:
1169 1201 return b64_data
1170 1202
1171 1203 def _repr_png_(self):
1172 1204 if self.embed and self.format == self._FMT_PNG:
1173 1205 return self._data_and_metadata()
1174 1206
1175 1207 def _repr_jpeg_(self):
1176 1208 if self.embed and self.format == self._FMT_JPEG:
1177 1209 return self._data_and_metadata()
1178 1210
1179 1211 def _find_ext(self, s):
1180 1212 return s.split('.')[-1].lower()
1181 1213
1182 1214
1183 1215 class Video(DisplayObject):
1184 1216
1185 1217 def __init__(self, data=None, url=None, filename=None, embed=False, mimetype=None):
1186 1218 """Create a video object given raw data or an URL.
1187 1219
1188 1220 When this object is returned by an input cell or passed to the
1189 1221 display function, it will result in the video being displayed
1190 1222 in the frontend.
1191 1223
1192 1224 Parameters
1193 1225 ----------
1194 1226 data : unicode, str or bytes
1195 1227 The raw video data or a URL or filename to load the data from.
1196 1228 Raw data will require passing `embed=True`.
1197 1229 url : unicode
1198 1230 A URL for the video. If you specify `url=`,
1199 1231 the image data will not be embedded.
1200 1232 filename : unicode
1201 1233 Path to a local file containing the video.
1202 1234 Will be interpreted as a local URL unless `embed=True`.
1203 1235 embed : bool
1204 1236 Should the video be embedded using a data URI (True) or be
1205 1237 loaded using a <video> tag (False).
1206 1238
1207 1239 Since videos are large, embedding them should be avoided, if possible.
1208 1240 You must confirm embedding as your intention by passing `embed=True`.
1209 1241
1210 1242 Local files can be displayed with URLs without embedding the content, via::
1211 1243
1212 1244 Video('./video.mp4')
1213 1245
1214 1246 mimetype: unicode
1215 1247 Specify the mimetype for embedded videos.
1216 1248 Default will be guessed from file extension, if available.
1217 1249
1218 1250 Examples
1219 1251 --------
1220 1252
1221 1253 Video('https://archive.org/download/Sita_Sings_the_Blues/Sita_Sings_the_Blues_small.mp4')
1222 1254 Video('path/to/video.mp4')
1223 1255 Video('path/to/video.mp4', embed=True)
1224 1256 Video(b'raw-videodata', embed=True)
1225 1257 """
1226 1258 if url is None and isinstance(data, str) and data.startswith(('http:', 'https:')):
1227 1259 url = data
1228 1260 data = None
1229 1261 elif os.path.exists(data):
1230 1262 filename = data
1231 1263 data = None
1232 1264
1233 1265 if data and not embed:
1234 1266 msg = ''.join([
1235 1267 "To embed videos, you must pass embed=True ",
1236 1268 "(this may make your notebook files huge)\n",
1237 1269 "Consider passing Video(url='...')",
1238 1270 ])
1239 1271 raise ValueError(msg)
1240 1272
1241 1273 self.mimetype = mimetype
1242 1274 self.embed = embed
1243 1275 super(Video, self).__init__(data=data, url=url, filename=filename)
1244 1276
1245 1277 def _repr_html_(self):
1246 1278 # External URLs and potentially local files are not embedded into the
1247 1279 # notebook output.
1248 1280 if not self.embed:
1249 1281 url = self.url if self.url is not None else self.filename
1250 1282 output = """<video src="{0}" controls>
1251 1283 Your browser does not support the <code>video</code> element.
1252 1284 </video>""".format(url)
1253 1285 return output
1254 1286
1255 1287 # Embedded videos are base64-encoded.
1256 1288 mimetype = self.mimetype
1257 1289 if self.filename is not None:
1258 1290 if not mimetype:
1259 1291 mimetype, _ = mimetypes.guess_type(self.filename)
1260 1292
1261 1293 with open(self.filename, 'rb') as f:
1262 1294 video = f.read()
1263 1295 else:
1264 1296 video = self.data
1265 1297 if isinstance(video, str):
1266 1298 # unicode input is already b64-encoded
1267 1299 b64_video = video
1268 1300 else:
1269 1301 b64_video = b2a_base64(video).decode('ascii').rstrip()
1270 1302
1271 1303 output = """<video controls>
1272 1304 <source src="data:{0};base64,{1}" type="{0}">
1273 1305 Your browser does not support the video tag.
1274 1306 </video>""".format(mimetype, b64_video)
1275 1307 return output
1276 1308
1277 1309 def reload(self):
1278 1310 # TODO
1279 1311 pass
1280 1312
1281 1313
1282 1314 def clear_output(wait=False):
1283 1315 """Clear the output of the current cell receiving output.
1284 1316
1285 1317 Parameters
1286 1318 ----------
1287 1319 wait : bool [default: false]
1288 1320 Wait to clear the output until new output is available to replace it."""
1289 1321 from IPython.core.interactiveshell import InteractiveShell
1290 1322 if InteractiveShell.initialized():
1291 1323 InteractiveShell.instance().display_pub.clear_output(wait)
1292 1324 else:
1293 1325 print('\033[2K\r', end='')
1294 1326 sys.stdout.flush()
1295 1327 print('\033[2K\r', end='')
1296 1328 sys.stderr.flush()
1297 1329
1298 1330
1299 1331 @skip_doctest
1300 1332 def set_matplotlib_formats(*formats, **kwargs):
1301 1333 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
1302 1334
1303 1335 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
1304 1336
1305 1337 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
1306 1338
1307 1339 To set this in your config files use the following::
1308 1340
1309 1341 c.InlineBackend.figure_formats = {'png', 'jpeg'}
1310 1342 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
1311 1343
1312 1344 Parameters
1313 1345 ----------
1314 1346 *formats : strs
1315 1347 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
1316 1348 **kwargs :
1317 1349 Keyword args will be relayed to ``figure.canvas.print_figure``.
1318 1350 """
1319 1351 from IPython.core.interactiveshell import InteractiveShell
1320 1352 from IPython.core.pylabtools import select_figure_formats
1321 1353 # build kwargs, starting with InlineBackend config
1322 1354 kw = {}
1323 1355 from ipykernel.pylab.config import InlineBackend
1324 1356 cfg = InlineBackend.instance()
1325 1357 kw.update(cfg.print_figure_kwargs)
1326 1358 kw.update(**kwargs)
1327 1359 shell = InteractiveShell.instance()
1328 1360 select_figure_formats(shell, formats, **kw)
1329 1361
1330 1362 @skip_doctest
1331 1363 def set_matplotlib_close(close=True):
1332 1364 """Set whether the inline backend closes all figures automatically or not.
1333 1365
1334 1366 By default, the inline backend used in the IPython Notebook will close all
1335 1367 matplotlib figures automatically after each cell is run. This means that
1336 1368 plots in different cells won't interfere. Sometimes, you may want to make
1337 1369 a plot in one cell and then refine it in later cells. This can be accomplished
1338 1370 by::
1339 1371
1340 1372 In [1]: set_matplotlib_close(False)
1341 1373
1342 1374 To set this in your config files use the following::
1343 1375
1344 1376 c.InlineBackend.close_figures = False
1345 1377
1346 1378 Parameters
1347 1379 ----------
1348 1380 close : bool
1349 1381 Should all matplotlib figures be automatically closed after each cell is
1350 1382 run?
1351 1383 """
1352 1384 from ipykernel.pylab.config import InlineBackend
1353 1385 cfg = InlineBackend.instance()
1354 1386 cfg.close_figures = close
General Comments 0
You need to be logged in to leave comments. Login now