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