##// END OF EJS Templates
Merge pull request #5110 from minrk/bbox_inches...
Brian E. Granger -
r15412:3d365194 merge
parent child Browse files
Show More
@@ -0,0 +1,3
1 * added ``InlineBackend.print_figure_kwargs`` to allow passing keyword arguments
2 to matplotlib's ``Canvas.print_figure``. This can be used to change the value of
3 ``bbox_inches``, which is 'tight' by default, or set the quality of JPEG figures.
@@ -1,772 +1,778
1 1 # -*- coding: utf-8 -*-
2 2 """Top-level display functions for displaying object in different formats.
3 3
4 4 Authors:
5 5
6 6 * Brian Granger
7 7 """
8 8
9 9 #-----------------------------------------------------------------------------
10 10 # Copyright (C) 2013 The IPython Development Team
11 11 #
12 12 # Distributed under the terms of the BSD License. The full license is in
13 13 # the file COPYING, distributed as part of this software.
14 14 #-----------------------------------------------------------------------------
15 15
16 16 #-----------------------------------------------------------------------------
17 17 # Imports
18 18 #-----------------------------------------------------------------------------
19 19
20 20 from __future__ import print_function
21 21
22 22 import os
23 23 import struct
24 24
25 25 from IPython.utils.py3compat import (string_types, cast_bytes_py2, cast_unicode,
26 26 unicode_type)
27 27 from IPython.testing.skipdoctest import skip_doctest
28 28 from .displaypub import publish_display_data
29 29
30 30 #-----------------------------------------------------------------------------
31 31 # utility functions
32 32 #-----------------------------------------------------------------------------
33 33
34 34 def _safe_exists(path):
35 35 """Check path, but don't let exceptions raise"""
36 36 try:
37 37 return os.path.exists(path)
38 38 except Exception:
39 39 return False
40 40
41 41 def _merge(d1, d2):
42 42 """Like update, but merges sub-dicts instead of clobbering at the top level.
43 43
44 44 Updates d1 in-place
45 45 """
46 46
47 47 if not isinstance(d2, dict) or not isinstance(d1, dict):
48 48 return d2
49 49 for key, value in d2.items():
50 50 d1[key] = _merge(d1.get(key), value)
51 51 return d1
52 52
53 53 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
54 54 """internal implementation of all display_foo methods
55 55
56 56 Parameters
57 57 ----------
58 58 mimetype : str
59 59 The mimetype to be published (e.g. 'image/png')
60 60 objs : tuple of objects
61 61 The Python objects to display, or if raw=True raw text data to
62 62 display.
63 63 raw : bool
64 64 Are the data objects raw data or Python objects that need to be
65 65 formatted before display? [default: False]
66 66 metadata : dict (optional)
67 67 Metadata to be associated with the specific mimetype output.
68 68 """
69 69 if metadata:
70 70 metadata = {mimetype: metadata}
71 71 if raw:
72 72 # turn list of pngdata into list of { 'image/png': pngdata }
73 73 objs = [ {mimetype: obj} for obj in objs ]
74 74 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
75 75
76 76 #-----------------------------------------------------------------------------
77 77 # Main functions
78 78 #-----------------------------------------------------------------------------
79 79
80 80 def display(*objs, **kwargs):
81 81 """Display a Python object in all frontends.
82 82
83 83 By default all representations will be computed and sent to the frontends.
84 84 Frontends can decide which representation is used and how.
85 85
86 86 Parameters
87 87 ----------
88 88 objs : tuple of objects
89 89 The Python objects to display.
90 90 raw : bool, optional
91 91 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
92 92 or Python objects that need to be formatted before display? [default: False]
93 93 include : list or tuple, optional
94 94 A list of format type strings (MIME types) to include in the
95 95 format data dict. If this is set *only* the format types included
96 96 in this list will be computed.
97 97 exclude : list or tuple, optional
98 98 A list of format type strings (MIME types) to exclude in the format
99 99 data dict. If this is set all format types will be computed,
100 100 except for those included in this argument.
101 101 metadata : dict, optional
102 102 A dictionary of metadata to associate with the output.
103 103 mime-type keys in this dictionary will be associated with the individual
104 104 representation formats, if they exist.
105 105 """
106 106 raw = kwargs.get('raw', False)
107 107 include = kwargs.get('include')
108 108 exclude = kwargs.get('exclude')
109 109 metadata = kwargs.get('metadata')
110 110
111 111 from IPython.core.interactiveshell import InteractiveShell
112 112
113 113 if not raw:
114 114 format = InteractiveShell.instance().display_formatter.format
115 115
116 116 for obj in objs:
117 117
118 118 # If _ipython_display_ is defined, use that to display this object.
119 119 display_method = getattr(obj, '_ipython_display_', None)
120 120 if display_method is not None:
121 121 try:
122 122 display_method(**kwargs)
123 123 except NotImplementedError:
124 124 pass
125 125 else:
126 126 continue
127 127 if raw:
128 128 publish_display_data('display', obj, metadata)
129 129 else:
130 130 format_dict, md_dict = format(obj, include=include, exclude=exclude)
131 131 if metadata:
132 132 # kwarg-specified metadata gets precedence
133 133 _merge(md_dict, metadata)
134 134 publish_display_data('display', format_dict, md_dict)
135 135
136 136
137 137 def display_pretty(*objs, **kwargs):
138 138 """Display the pretty (default) representation of an object.
139 139
140 140 Parameters
141 141 ----------
142 142 objs : tuple of objects
143 143 The Python objects to display, or if raw=True raw text data to
144 144 display.
145 145 raw : bool
146 146 Are the data objects raw data or Python objects that need to be
147 147 formatted before display? [default: False]
148 148 metadata : dict (optional)
149 149 Metadata to be associated with the specific mimetype output.
150 150 """
151 151 _display_mimetype('text/plain', objs, **kwargs)
152 152
153 153
154 154 def display_html(*objs, **kwargs):
155 155 """Display the HTML representation of an object.
156 156
157 157 Parameters
158 158 ----------
159 159 objs : tuple of objects
160 160 The Python objects to display, or if raw=True raw HTML data to
161 161 display.
162 162 raw : bool
163 163 Are the data objects raw data or Python objects that need to be
164 164 formatted before display? [default: False]
165 165 metadata : dict (optional)
166 166 Metadata to be associated with the specific mimetype output.
167 167 """
168 168 _display_mimetype('text/html', objs, **kwargs)
169 169
170 170
171 171 def display_svg(*objs, **kwargs):
172 172 """Display the SVG representation of an object.
173 173
174 174 Parameters
175 175 ----------
176 176 objs : tuple of objects
177 177 The Python objects to display, or if raw=True raw svg data to
178 178 display.
179 179 raw : bool
180 180 Are the data objects raw data or Python objects that need to be
181 181 formatted before display? [default: False]
182 182 metadata : dict (optional)
183 183 Metadata to be associated with the specific mimetype output.
184 184 """
185 185 _display_mimetype('image/svg+xml', objs, **kwargs)
186 186
187 187
188 188 def display_png(*objs, **kwargs):
189 189 """Display the PNG representation of an object.
190 190
191 191 Parameters
192 192 ----------
193 193 objs : tuple of objects
194 194 The Python objects to display, or if raw=True raw png data to
195 195 display.
196 196 raw : bool
197 197 Are the data objects raw data or Python objects that need to be
198 198 formatted before display? [default: False]
199 199 metadata : dict (optional)
200 200 Metadata to be associated with the specific mimetype output.
201 201 """
202 202 _display_mimetype('image/png', objs, **kwargs)
203 203
204 204
205 205 def display_jpeg(*objs, **kwargs):
206 206 """Display the JPEG representation of an object.
207 207
208 208 Parameters
209 209 ----------
210 210 objs : tuple of objects
211 211 The Python objects to display, or if raw=True raw JPEG data to
212 212 display.
213 213 raw : bool
214 214 Are the data objects raw data or Python objects that need to be
215 215 formatted before display? [default: False]
216 216 metadata : dict (optional)
217 217 Metadata to be associated with the specific mimetype output.
218 218 """
219 219 _display_mimetype('image/jpeg', objs, **kwargs)
220 220
221 221
222 222 def display_latex(*objs, **kwargs):
223 223 """Display the LaTeX representation of an object.
224 224
225 225 Parameters
226 226 ----------
227 227 objs : tuple of objects
228 228 The Python objects to display, or if raw=True raw latex data to
229 229 display.
230 230 raw : bool
231 231 Are the data objects raw data or Python objects that need to be
232 232 formatted before display? [default: False]
233 233 metadata : dict (optional)
234 234 Metadata to be associated with the specific mimetype output.
235 235 """
236 236 _display_mimetype('text/latex', objs, **kwargs)
237 237
238 238
239 239 def display_json(*objs, **kwargs):
240 240 """Display the JSON representation of an object.
241 241
242 242 Note that not many frontends support displaying JSON.
243 243
244 244 Parameters
245 245 ----------
246 246 objs : tuple of objects
247 247 The Python objects to display, or if raw=True raw json data to
248 248 display.
249 249 raw : bool
250 250 Are the data objects raw data or Python objects that need to be
251 251 formatted before display? [default: False]
252 252 metadata : dict (optional)
253 253 Metadata to be associated with the specific mimetype output.
254 254 """
255 255 _display_mimetype('application/json', objs, **kwargs)
256 256
257 257
258 258 def display_javascript(*objs, **kwargs):
259 259 """Display the Javascript representation of an object.
260 260
261 261 Parameters
262 262 ----------
263 263 objs : tuple of objects
264 264 The Python objects to display, or if raw=True raw javascript data to
265 265 display.
266 266 raw : bool
267 267 Are the data objects raw data or Python objects that need to be
268 268 formatted before display? [default: False]
269 269 metadata : dict (optional)
270 270 Metadata to be associated with the specific mimetype output.
271 271 """
272 272 _display_mimetype('application/javascript', objs, **kwargs)
273 273
274 274
275 275 def display_pdf(*objs, **kwargs):
276 276 """Display the PDF representation of an object.
277 277
278 278 Parameters
279 279 ----------
280 280 objs : tuple of objects
281 281 The Python objects to display, or if raw=True raw javascript data to
282 282 display.
283 283 raw : bool
284 284 Are the data objects raw data or Python objects that need to be
285 285 formatted before display? [default: False]
286 286 metadata : dict (optional)
287 287 Metadata to be associated with the specific mimetype output.
288 288 """
289 289 _display_mimetype('application/pdf', objs, **kwargs)
290 290
291 291
292 292 #-----------------------------------------------------------------------------
293 293 # Smart classes
294 294 #-----------------------------------------------------------------------------
295 295
296 296
297 297 class DisplayObject(object):
298 298 """An object that wraps data to be displayed."""
299 299
300 300 _read_flags = 'r'
301 301
302 302 def __init__(self, data=None, url=None, filename=None):
303 303 """Create a display object given raw data.
304 304
305 305 When this object is returned by an expression or passed to the
306 306 display function, it will result in the data being displayed
307 307 in the frontend. The MIME type of the data should match the
308 308 subclasses used, so the Png subclass should be used for 'image/png'
309 309 data. If the data is a URL, the data will first be downloaded
310 310 and then displayed. If
311 311
312 312 Parameters
313 313 ----------
314 314 data : unicode, str or bytes
315 315 The raw data or a URL or file to load the data from
316 316 url : unicode
317 317 A URL to download the data from.
318 318 filename : unicode
319 319 Path to a local file to load the data from.
320 320 """
321 321 if data is not None and isinstance(data, string_types):
322 322 if data.startswith('http') and url is None:
323 323 url = data
324 324 filename = None
325 325 data = None
326 326 elif _safe_exists(data) and filename is None:
327 327 url = None
328 328 filename = data
329 329 data = None
330 330
331 331 self.data = data
332 332 self.url = url
333 333 self.filename = None if filename is None else unicode_type(filename)
334 334
335 335 self.reload()
336 336 self._check_data()
337 337
338 338 def _check_data(self):
339 339 """Override in subclasses if there's something to check."""
340 340 pass
341 341
342 342 def reload(self):
343 343 """Reload the raw data from file or URL."""
344 344 if self.filename is not None:
345 345 with open(self.filename, self._read_flags) as f:
346 346 self.data = f.read()
347 347 elif self.url is not None:
348 348 try:
349 349 try:
350 350 from urllib.request import urlopen # Py3
351 351 except ImportError:
352 352 from urllib2 import urlopen
353 353 response = urlopen(self.url)
354 354 self.data = response.read()
355 355 # extract encoding from header, if there is one:
356 356 encoding = None
357 357 for sub in response.headers['content-type'].split(';'):
358 358 sub = sub.strip()
359 359 if sub.startswith('charset'):
360 360 encoding = sub.split('=')[-1].strip()
361 361 break
362 362 # decode data, if an encoding was specified
363 363 if encoding:
364 364 self.data = self.data.decode(encoding, 'replace')
365 365 except:
366 366 self.data = None
367 367
368 368 class TextDisplayObject(DisplayObject):
369 369 """Validate that display data is text"""
370 370 def _check_data(self):
371 371 if self.data is not None and not isinstance(self.data, string_types):
372 372 raise TypeError("%s expects text, not %r" % (self.__class__.__name__, self.data))
373 373
374 374 class Pretty(TextDisplayObject):
375 375
376 376 def _repr_pretty_(self):
377 377 return self.data
378 378
379 379
380 380 class HTML(TextDisplayObject):
381 381
382 382 def _repr_html_(self):
383 383 return self.data
384 384
385 385 def __html__(self):
386 386 """
387 387 This method exists to inform other HTML-using modules (e.g. Markupsafe,
388 388 htmltag, etc) that this object is HTML and does not need things like
389 389 special characters (<>&) escaped.
390 390 """
391 391 return self._repr_html_()
392 392
393 393
394 394 class Math(TextDisplayObject):
395 395
396 396 def _repr_latex_(self):
397 397 s = self.data.strip('$')
398 398 return "$$%s$$" % s
399 399
400 400
401 401 class Latex(TextDisplayObject):
402 402
403 403 def _repr_latex_(self):
404 404 return self.data
405 405
406 406
407 407 class SVG(DisplayObject):
408 408
409 409 # wrap data in a property, which extracts the <svg> tag, discarding
410 410 # document headers
411 411 _data = None
412 412
413 413 @property
414 414 def data(self):
415 415 return self._data
416 416
417 417 @data.setter
418 418 def data(self, svg):
419 419 if svg is None:
420 420 self._data = None
421 421 return
422 422 # parse into dom object
423 423 from xml.dom import minidom
424 424 svg = cast_bytes_py2(svg)
425 425 x = minidom.parseString(svg)
426 426 # get svg tag (should be 1)
427 427 found_svg = x.getElementsByTagName('svg')
428 428 if found_svg:
429 429 svg = found_svg[0].toxml()
430 430 else:
431 431 # fallback on the input, trust the user
432 432 # but this is probably an error.
433 433 pass
434 434 svg = cast_unicode(svg)
435 435 self._data = svg
436 436
437 437 def _repr_svg_(self):
438 438 return self.data
439 439
440 440
441 441 class JSON(TextDisplayObject):
442 442
443 443 def _repr_json_(self):
444 444 return self.data
445 445
446 446 css_t = """$("head").append($("<link/>").attr({
447 447 rel: "stylesheet",
448 448 type: "text/css",
449 449 href: "%s"
450 450 }));
451 451 """
452 452
453 453 lib_t1 = """$.getScript("%s", function () {
454 454 """
455 455 lib_t2 = """});
456 456 """
457 457
458 458 class Javascript(TextDisplayObject):
459 459
460 460 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
461 461 """Create a Javascript display object given raw data.
462 462
463 463 When this object is returned by an expression or passed to the
464 464 display function, it will result in the data being displayed
465 465 in the frontend. If the data is a URL, the data will first be
466 466 downloaded and then displayed.
467 467
468 468 In the Notebook, the containing element will be available as `element`,
469 469 and jQuery will be available. The output area starts hidden, so if
470 470 the js appends content to `element` that should be visible, then
471 471 it must call `container.show()` to unhide the area.
472 472
473 473 Parameters
474 474 ----------
475 475 data : unicode, str or bytes
476 476 The Javascript source code or a URL to download it from.
477 477 url : unicode
478 478 A URL to download the data from.
479 479 filename : unicode
480 480 Path to a local file to load the data from.
481 481 lib : list or str
482 482 A sequence of Javascript library URLs to load asynchronously before
483 483 running the source code. The full URLs of the libraries should
484 484 be given. A single Javascript library URL can also be given as a
485 485 string.
486 486 css: : list or str
487 487 A sequence of css files to load before running the source code.
488 488 The full URLs of the css files should be given. A single css URL
489 489 can also be given as a string.
490 490 """
491 491 if isinstance(lib, string_types):
492 492 lib = [lib]
493 493 elif lib is None:
494 494 lib = []
495 495 if isinstance(css, string_types):
496 496 css = [css]
497 497 elif css is None:
498 498 css = []
499 499 if not isinstance(lib, (list,tuple)):
500 500 raise TypeError('expected sequence, got: %r' % lib)
501 501 if not isinstance(css, (list,tuple)):
502 502 raise TypeError('expected sequence, got: %r' % css)
503 503 self.lib = lib
504 504 self.css = css
505 505 super(Javascript, self).__init__(data=data, url=url, filename=filename)
506 506
507 507 def _repr_javascript_(self):
508 508 r = ''
509 509 for c in self.css:
510 510 r += css_t % c
511 511 for l in self.lib:
512 512 r += lib_t1 % l
513 513 r += self.data
514 514 r += lib_t2*len(self.lib)
515 515 return r
516 516
517 517 # constants for identifying png/jpeg data
518 518 _PNG = b'\x89PNG\r\n\x1a\n'
519 519 _JPEG = b'\xff\xd8'
520 520
521 521 def _pngxy(data):
522 522 """read the (width, height) from a PNG header"""
523 523 ihdr = data.index(b'IHDR')
524 524 # next 8 bytes are width/height
525 525 w4h4 = data[ihdr+4:ihdr+12]
526 526 return struct.unpack('>ii', w4h4)
527 527
528 528 def _jpegxy(data):
529 529 """read the (width, height) from a JPEG header"""
530 530 # adapted from http://www.64lines.com/jpeg-width-height
531 531
532 532 idx = 4
533 533 while True:
534 534 block_size = struct.unpack('>H', data[idx:idx+2])[0]
535 535 idx = idx + block_size
536 536 if data[idx:idx+2] == b'\xFF\xC0':
537 537 # found Start of Frame
538 538 iSOF = idx
539 539 break
540 540 else:
541 541 # read another block
542 542 idx += 2
543 543
544 544 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
545 545 return w, h
546 546
547 547 class Image(DisplayObject):
548 548
549 549 _read_flags = 'rb'
550 550 _FMT_JPEG = u'jpeg'
551 551 _FMT_PNG = u'png'
552 552 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
553 553
554 554 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None, retina=False):
555 555 """Create a PNG/JPEG image object given raw data.
556 556
557 557 When this object is returned by an input cell or passed to the
558 558 display function, it will result in the image being displayed
559 559 in the frontend.
560 560
561 561 Parameters
562 562 ----------
563 563 data : unicode, str or bytes
564 564 The raw image data or a URL or filename to load the data from.
565 565 This always results in embedded image data.
566 566 url : unicode
567 567 A URL to download the data from. If you specify `url=`,
568 568 the image data will not be embedded unless you also specify `embed=True`.
569 569 filename : unicode
570 570 Path to a local file to load the data from.
571 571 Images from a file are always embedded.
572 572 format : unicode
573 573 The format of the image data (png/jpeg/jpg). If a filename or URL is given
574 574 for format will be inferred from the filename extension.
575 575 embed : bool
576 576 Should the image data be embedded using a data URI (True) or be
577 577 loaded using an <img> tag. Set this to True if you want the image
578 578 to be viewable later with no internet connection in the notebook.
579 579
580 580 Default is `True`, unless the keyword argument `url` is set, then
581 581 default value is `False`.
582 582
583 583 Note that QtConsole is not able to display images if `embed` is set to `False`
584 584 width : int
585 585 Width to which to constrain the image in html
586 586 height : int
587 587 Height to which to constrain the image in html
588 588 retina : bool
589 589 Automatically set the width and height to half of the measured
590 590 width and height.
591 591 This only works for embedded images because it reads the width/height
592 592 from image data.
593 593 For non-embedded images, you can just set the desired display width
594 594 and height directly.
595 595
596 596 Examples
597 597 --------
598 598 # embedded image data, works in qtconsole and notebook
599 599 # when passed positionally, the first arg can be any of raw image data,
600 600 # a URL, or a filename from which to load image data.
601 601 # The result is always embedding image data for inline images.
602 602 Image('http://www.google.fr/images/srpr/logo3w.png')
603 603 Image('/path/to/image.jpg')
604 604 Image(b'RAW_PNG_DATA...')
605 605
606 606 # Specifying Image(url=...) does not embed the image data,
607 607 # it only generates `<img>` tag with a link to the source.
608 608 # This will not work in the qtconsole or offline.
609 609 Image(url='http://www.google.fr/images/srpr/logo3w.png')
610 610
611 611 """
612 612 if filename is not None:
613 613 ext = self._find_ext(filename)
614 614 elif url is not None:
615 615 ext = self._find_ext(url)
616 616 elif data is None:
617 617 raise ValueError("No image data found. Expecting filename, url, or data.")
618 618 elif isinstance(data, string_types) and (
619 619 data.startswith('http') or _safe_exists(data)
620 620 ):
621 621 ext = self._find_ext(data)
622 622 else:
623 623 ext = None
624 624
625 625 if ext is not None:
626 626 format = ext.lower()
627 627 if ext == u'jpg' or ext == u'jpeg':
628 628 format = self._FMT_JPEG
629 629 if ext == u'png':
630 630 format = self._FMT_PNG
631 631 elif isinstance(data, bytes) and format == 'png':
632 632 # infer image type from image data header,
633 633 # only if format might not have been specified.
634 634 if data[:2] == _JPEG:
635 635 format = 'jpeg'
636 636
637 637 self.format = unicode_type(format).lower()
638 638 self.embed = embed if embed is not None else (url is None)
639 639
640 640 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
641 641 raise ValueError("Cannot embed the '%s' image format" % (self.format))
642 642 self.width = width
643 643 self.height = height
644 644 self.retina = retina
645 645 super(Image, self).__init__(data=data, url=url, filename=filename)
646 646
647 647 if retina:
648 648 self._retina_shape()
649 649
650 650 def _retina_shape(self):
651 651 """load pixel-doubled width and height from image data"""
652 652 if not self.embed:
653 653 return
654 654 if self.format == 'png':
655 655 w, h = _pngxy(self.data)
656 656 elif self.format == 'jpeg':
657 657 w, h = _jpegxy(self.data)
658 658 else:
659 659 # retina only supports png
660 660 return
661 661 self.width = w // 2
662 662 self.height = h // 2
663 663
664 664 def reload(self):
665 665 """Reload the raw data from file or URL."""
666 666 if self.embed:
667 667 super(Image,self).reload()
668 668 if self.retina:
669 669 self._retina_shape()
670 670
671 671 def _repr_html_(self):
672 672 if not self.embed:
673 673 width = height = ''
674 674 if self.width:
675 675 width = ' width="%d"' % self.width
676 676 if self.height:
677 677 height = ' height="%d"' % self.height
678 678 return u'<img src="%s"%s%s/>' % (self.url, width, height)
679 679
680 680 def _data_and_metadata(self):
681 681 """shortcut for returning metadata with shape information, if defined"""
682 682 md = {}
683 683 if self.width:
684 684 md['width'] = self.width
685 685 if self.height:
686 686 md['height'] = self.height
687 687 if md:
688 688 return self.data, md
689 689 else:
690 690 return self.data
691 691
692 692 def _repr_png_(self):
693 693 if self.embed and self.format == u'png':
694 694 return self._data_and_metadata()
695 695
696 696 def _repr_jpeg_(self):
697 697 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
698 698 return self._data_and_metadata()
699 699
700 700 def _find_ext(self, s):
701 701 return unicode_type(s.split('.')[-1].lower())
702 702
703 703
704 704 def clear_output(wait=False):
705 705 """Clear the output of the current cell receiving output.
706 706
707 707 Parameters
708 708 ----------
709 709 wait : bool [default: false]
710 710 Wait to clear the output until new output is available to replace it."""
711 711 from IPython.core.interactiveshell import InteractiveShell
712 712 if InteractiveShell.initialized():
713 713 InteractiveShell.instance().display_pub.clear_output(wait)
714 714 else:
715 715 from IPython.utils import io
716 716 print('\033[2K\r', file=io.stdout, end='')
717 717 io.stdout.flush()
718 718 print('\033[2K\r', file=io.stderr, end='')
719 719 io.stderr.flush()
720 720
721 721
722 722 @skip_doctest
723 723 def set_matplotlib_formats(*formats, **kwargs):
724 724 """Select figure formats for the inline backend. Optionally pass quality for JPEG.
725 725
726 726 For example, this enables PNG and JPEG output with a JPEG quality of 90%::
727 727
728 728 In [1]: set_matplotlib_formats('png', 'jpeg', quality=90)
729 729
730 730 To set this in your config files use the following::
731 731
732 c.InlineBackend.figure_formats = {'pdf', 'png', 'svg'}
733 c.InlineBackend.quality = 90
732 c.InlineBackend.figure_formats = {'png', 'jpeg'}
733 c.InlineBackend.print_figure_kwargs.update({'quality' : 90})
734 734
735 735 Parameters
736 736 ----------
737 *formats : list, tuple
738 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
739 quality : int
740 A percentage for the quality of JPEG figures. Defaults to 90.
737 *formats : strs
738 One or more figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
739 **kwargs :
740 Keyword args will be relayed to ``figure.canvas.print_figure``.
741 741 """
742 742 from IPython.core.interactiveshell import InteractiveShell
743 743 from IPython.core.pylabtools import select_figure_formats
744 from IPython.kernel.zmq.pylab.config import InlineBackend
745 # build kwargs, starting with InlineBackend config
746 kw = {}
747 cfg = InlineBackend.instance()
748 kw.update(cfg.print_figure_kwargs)
749 kw.update(**kwargs)
744 750 shell = InteractiveShell.instance()
745 select_figure_formats(shell, formats, quality=90)
751 select_figure_formats(shell, formats, **kw)
746 752
747 753 @skip_doctest
748 def set_matplotlib_close(close):
754 def set_matplotlib_close(close=True):
749 755 """Set whether the inline backend closes all figures automatically or not.
750 756
751 757 By default, the inline backend used in the IPython Notebook will close all
752 758 matplotlib figures automatically after each cell is run. This means that
753 759 plots in different cells won't interfere. Sometimes, you may want to make
754 760 a plot in one cell and then refine it in later cells. This can be accomplished
755 761 by::
756 762
757 763 In [1]: set_matplotlib_close(False)
758 764
759 765 To set this in your config files use the following::
760 766
761 767 c.InlineBackend.close_figures = False
762 768
763 769 Parameters
764 770 ----------
765 771 close : bool
766 772 Should all matplotlib figures be automatically closed after each cell is
767 773 run?
768 774 """
769 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
770 ilbe = InlineBackend.instance()
771 ilbe.close_figures = close
775 from IPython.kernel.zmq.pylab.config import InlineBackend
776 cfg = InlineBackend.instance()
777 cfg.close_figures = close
772 778
@@ -1,358 +1,374
1 1 # -*- coding: utf-8 -*-
2 2 """Pylab (matplotlib) support utilities.
3 3
4 4 Authors
5 5 -------
6 6
7 7 * Fernando Perez.
8 8 * Brian Granger
9 9 """
10 10 from __future__ import print_function
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Copyright (C) 2009 The IPython Development Team
14 14 #
15 15 # Distributed under the terms of the BSD License. The full license is in
16 16 # the file COPYING, distributed as part of this software.
17 17 #-----------------------------------------------------------------------------
18 18
19 19 #-----------------------------------------------------------------------------
20 20 # Imports
21 21 #-----------------------------------------------------------------------------
22 22
23 23 import sys
24 24 from io import BytesIO
25 25
26 26 from IPython.core.display import _pngxy
27 27 from IPython.utils.decorators import flag_calls
28 28 from IPython.utils import py3compat
29 29
30 30 # If user specifies a GUI, that dictates the backend, otherwise we read the
31 31 # user's mpl default from the mpl rc structure
32 32 backends = {'tk': 'TkAgg',
33 33 'gtk': 'GTKAgg',
34 34 'gtk3': 'GTK3Agg',
35 35 'wx': 'WXAgg',
36 36 'qt': 'Qt4Agg', # qt3 not supported
37 37 'qt4': 'Qt4Agg',
38 38 'osx': 'MacOSX',
39 39 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
40 40
41 41 # We also need a reverse backends2guis mapping that will properly choose which
42 42 # GUI support to activate based on the desired matplotlib backend. For the
43 43 # most part it's just a reverse of the above dict, but we also need to add a
44 44 # few others that map to the same GUI manually:
45 45 backend2gui = dict(zip(backends.values(), backends.keys()))
46 46 # Our tests expect backend2gui to just return 'qt'
47 47 backend2gui['Qt4Agg'] = 'qt'
48 48 # In the reverse mapping, there are a few extra valid matplotlib backends that
49 49 # map to the same GUI support
50 50 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
51 51 backend2gui['GTK3Cairo'] = 'gtk3'
52 52 backend2gui['WX'] = 'wx'
53 53 backend2gui['CocoaAgg'] = 'osx'
54 54
55 55 #-----------------------------------------------------------------------------
56 56 # Matplotlib utilities
57 57 #-----------------------------------------------------------------------------
58 58
59 59
60 60 def getfigs(*fig_nums):
61 61 """Get a list of matplotlib figures by figure numbers.
62 62
63 63 If no arguments are given, all available figures are returned. If the
64 64 argument list contains references to invalid figures, a warning is printed
65 65 but the function continues pasting further figures.
66 66
67 67 Parameters
68 68 ----------
69 69 figs : tuple
70 70 A tuple of ints giving the figure numbers of the figures to return.
71 71 """
72 72 from matplotlib._pylab_helpers import Gcf
73 73 if not fig_nums:
74 74 fig_managers = Gcf.get_all_fig_managers()
75 75 return [fm.canvas.figure for fm in fig_managers]
76 76 else:
77 77 figs = []
78 78 for num in fig_nums:
79 79 f = Gcf.figs.get(num)
80 80 if f is None:
81 81 print('Warning: figure %s not available.' % num)
82 82 else:
83 83 figs.append(f.canvas.figure)
84 84 return figs
85 85
86 86
87 87 def figsize(sizex, sizey):
88 88 """Set the default figure size to be [sizex, sizey].
89 89
90 90 This is just an easy to remember, convenience wrapper that sets::
91 91
92 92 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
93 93 """
94 94 import matplotlib
95 95 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
96 96
97 97
98 def print_figure(fig, fmt='png', quality=90):
99 """Convert a figure to svg, png or jpg for inline display.
100 Quality is only relevant for jpg.
98 def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
99 """Print a figure to an image, and return the resulting bytes
100
101 Any keyword args are passed to fig.canvas.print_figure,
102 such as ``quality`` or ``bbox_inches``.
101 103 """
102 104 from matplotlib import rcParams
103 105 # When there's an empty figure, we shouldn't return anything, otherwise we
104 106 # get big blank areas in the qt console.
105 107 if not fig.axes and not fig.lines:
106 108 return
107 109
108 fc = fig.get_facecolor()
109 ec = fig.get_edgecolor()
110 bytes_io = BytesIO()
111 110 dpi = rcParams['savefig.dpi']
112 111 if fmt == 'retina':
113 112 dpi = dpi * 2
114 113 fmt = 'png'
115 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
116 facecolor=fc, edgecolor=ec, dpi=dpi, quality=quality)
117 data = bytes_io.getvalue()
118 return data
119 114
120 def retina_figure(fig):
115 # build keyword args
116 kw = dict(
117 format=fmt,
118 fc=fig.get_facecolor(),
119 ec=fig.get_edgecolor(),
120 dpi=dpi,
121 bbox_inches=bbox_inches,
122 )
123 # **kwargs get higher priority
124 kw.update(kwargs)
125
126 bytes_io = BytesIO()
127 fig.canvas.print_figure(bytes_io, **kw)
128 return bytes_io.getvalue()
129
130 def retina_figure(fig, **kwargs):
121 131 """format a figure as a pixel-doubled (retina) PNG"""
122 pngdata = print_figure(fig, fmt='retina')
132 pngdata = print_figure(fig, fmt='retina', **kwargs)
123 133 w, h = _pngxy(pngdata)
124 134 metadata = dict(width=w//2, height=h//2)
125 135 return pngdata, metadata
126 136
127 137 # We need a little factory function here to create the closure where
128 138 # safe_execfile can live.
129 139 def mpl_runner(safe_execfile):
130 140 """Factory to return a matplotlib-enabled runner for %run.
131 141
132 142 Parameters
133 143 ----------
134 144 safe_execfile : function
135 145 This must be a function with the same interface as the
136 146 :meth:`safe_execfile` method of IPython.
137 147
138 148 Returns
139 149 -------
140 150 A function suitable for use as the ``runner`` argument of the %run magic
141 151 function.
142 152 """
143 153
144 154 def mpl_execfile(fname,*where,**kw):
145 155 """matplotlib-aware wrapper around safe_execfile.
146 156
147 157 Its interface is identical to that of the :func:`execfile` builtin.
148 158
149 159 This is ultimately a call to execfile(), but wrapped in safeties to
150 160 properly handle interactive rendering."""
151 161
152 162 import matplotlib
153 163 import matplotlib.pylab as pylab
154 164
155 165 #print '*** Matplotlib runner ***' # dbg
156 166 # turn off rendering until end of script
157 167 is_interactive = matplotlib.rcParams['interactive']
158 168 matplotlib.interactive(False)
159 169 safe_execfile(fname,*where,**kw)
160 170 matplotlib.interactive(is_interactive)
161 171 # make rendering call now, if the user tried to do it
162 172 if pylab.draw_if_interactive.called:
163 173 pylab.draw()
164 174 pylab.draw_if_interactive.called = False
165 175
166 176 return mpl_execfile
167 177
168 178
169 def select_figure_formats(shell, formats, quality=90):
179 def select_figure_formats(shell, formats, **kwargs):
170 180 """Select figure formats for the inline backend.
171 181
172 182 Parameters
173 183 ==========
174 184 shell : InteractiveShell
175 185 The main IPython instance.
176 formats : list
186 formats : str or set
177 187 One or a set of figure formats to enable: 'png', 'retina', 'jpeg', 'svg', 'pdf'.
178 quality : int
179 A percentage for the quality of JPEG figures.
188 **kwargs : any
189 Extra keyword arguments to be passed to fig.canvas.print_figure.
180 190 """
181 191 from matplotlib.figure import Figure
182 192 from IPython.kernel.zmq.pylab import backend_inline
183 193
184 194 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
185 195 png_formatter = shell.display_formatter.formatters['image/png']
186 196 jpg_formatter = shell.display_formatter.formatters['image/jpeg']
187 197 pdf_formatter = shell.display_formatter.formatters['application/pdf']
188 198
189 199 if isinstance(formats, py3compat.string_types):
190 200 formats = {formats}
191
192 [ f.type_printers.pop(Figure, None) for f in {svg_formatter, png_formatter, jpg_formatter} ]
193
194 for fmt in formats:
195 if fmt == 'png':
196 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
197 elif fmt in ('png2x', 'retina'):
198 png_formatter.for_type(Figure, retina_figure)
199 elif fmt in ('jpg', 'jpeg'):
200 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality))
201 elif fmt == 'svg':
202 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
203 elif fmt == 'pdf':
204 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf'))
205 else:
206 raise ValueError("supported formats are: 'png', 'retina', 'svg', 'jpg', 'pdf' not %r" % fmt)
201 # cast in case of list / tuple
202 formats = set(formats)
203
204 [ f.pop(Figure, None) for f in shell.display_formatter.formatters.values() ]
205
206 supported = {'png', 'png2x', 'retina', 'jpg', 'jpeg', 'svg', 'pdf'}
207 bad = formats.difference(supported)
208 if bad:
209 bs = "%s" % ','.join([repr(f) for f in bad])
210 gs = "%s" % ','.join([repr(f) for f in supported])
211 raise ValueError("supported formats are: %s not %s" % (gs, bs))
212
213 if 'png' in formats:
214 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', **kwargs))
215 if 'retina' in formats or 'png2x' in formats:
216 png_formatter.for_type(Figure, lambda fig: retina_figure(fig, **kwargs))
217 if 'jpg' in formats or 'jpeg' in formats:
218 jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', **kwargs))
219 if 'svg' in formats:
220 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', **kwargs))
221 if 'pdf' in formats:
222 pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', **kwargs))
207 223
208 224 #-----------------------------------------------------------------------------
209 225 # Code for initializing matplotlib and importing pylab
210 226 #-----------------------------------------------------------------------------
211 227
212 228
213 229 def find_gui_and_backend(gui=None, gui_select=None):
214 230 """Given a gui string return the gui and mpl backend.
215 231
216 232 Parameters
217 233 ----------
218 234 gui : str
219 235 Can be one of ('tk','gtk','wx','qt','qt4','inline').
220 236 gui_select : str
221 237 Can be one of ('tk','gtk','wx','qt','qt4','inline').
222 238 This is any gui already selected by the shell.
223 239
224 240 Returns
225 241 -------
226 242 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
227 243 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
228 244 """
229 245
230 246 import matplotlib
231 247
232 248 if gui and gui != 'auto':
233 249 # select backend based on requested gui
234 250 backend = backends[gui]
235 251 else:
236 252 # We need to read the backend from the original data structure, *not*
237 253 # from mpl.rcParams, since a prior invocation of %matplotlib may have
238 254 # overwritten that.
239 255 # WARNING: this assumes matplotlib 1.1 or newer!!
240 256 backend = matplotlib.rcParamsOrig['backend']
241 257 # In this case, we need to find what the appropriate gui selection call
242 258 # should be for IPython, so we can activate inputhook accordingly
243 259 gui = backend2gui.get(backend, None)
244 260
245 261 # If we have already had a gui active, we need it and inline are the
246 262 # ones allowed.
247 263 if gui_select and gui != gui_select:
248 264 gui = gui_select
249 265 backend = backends[gui]
250 266
251 267 return gui, backend
252 268
253 269
254 270 def activate_matplotlib(backend):
255 271 """Activate the given backend and set interactive to True."""
256 272
257 273 import matplotlib
258 274 matplotlib.interactive(True)
259 275
260 276 # Matplotlib had a bug where even switch_backend could not force
261 277 # the rcParam to update. This needs to be set *before* the module
262 278 # magic of switch_backend().
263 279 matplotlib.rcParams['backend'] = backend
264 280
265 281 import matplotlib.pyplot
266 282 matplotlib.pyplot.switch_backend(backend)
267 283
268 284 # This must be imported last in the matplotlib series, after
269 285 # backend/interactivity choices have been made
270 286 import matplotlib.pylab as pylab
271 287
272 288 pylab.show._needmain = False
273 289 # We need to detect at runtime whether show() is called by the user.
274 290 # For this, we wrap it into a decorator which adds a 'called' flag.
275 291 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
276 292
277 293
278 294 def import_pylab(user_ns, import_all=True):
279 295 """Populate the namespace with pylab-related values.
280 296
281 297 Imports matplotlib, pylab, numpy, and everything from pylab and numpy.
282 298
283 299 Also imports a few names from IPython (figsize, display, getfigs)
284 300
285 301 """
286 302
287 303 # Import numpy as np/pyplot as plt are conventions we're trying to
288 304 # somewhat standardize on. Making them available to users by default
289 305 # will greatly help this.
290 306 s = ("import numpy\n"
291 307 "import matplotlib\n"
292 308 "from matplotlib import pylab, mlab, pyplot\n"
293 309 "np = numpy\n"
294 310 "plt = pyplot\n"
295 311 )
296 312 exec(s, user_ns)
297 313
298 314 if import_all:
299 315 s = ("from matplotlib.pylab import *\n"
300 316 "from numpy import *\n")
301 317 exec(s, user_ns)
302 318
303 319 # IPython symbols to add
304 320 user_ns['figsize'] = figsize
305 321 from IPython.core.display import display
306 322 # Add display and getfigs to the user's namespace
307 323 user_ns['display'] = display
308 324 user_ns['getfigs'] = getfigs
309 325
310 326
311 327 def configure_inline_support(shell, backend):
312 328 """Configure an IPython shell object for matplotlib use.
313 329
314 330 Parameters
315 331 ----------
316 332 shell : InteractiveShell instance
317 333
318 334 backend : matplotlib backend
319 335 """
320 336 # If using our svg payload backend, register the post-execution
321 337 # function that will pick up the results for display. This can only be
322 338 # done with access to the real shell object.
323 339
324 340 # Note: if we can't load the inline backend, then there's no point
325 341 # continuing (such as in terminal-only shells in environments without
326 342 # zeromq available).
327 343 try:
328 344 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
329 345 except ImportError:
330 346 return
331 347 from matplotlib import pyplot
332 348
333 349 cfg = InlineBackend.instance(parent=shell)
334 350 cfg.shell = shell
335 351 if cfg not in shell.configurables:
336 352 shell.configurables.append(cfg)
337 353
338 354 if backend == backends['inline']:
339 355 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
340 356 shell.register_post_execute(flush_figures)
341 357
342 358 # Save rcParams that will be overwrittern
343 359 shell._saved_rcParams = dict()
344 360 for k in cfg.rc:
345 361 shell._saved_rcParams[k] = pyplot.rcParams[k]
346 362 # load inline_rc
347 363 pyplot.rcParams.update(cfg.rc)
348 364 else:
349 365 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
350 366 if flush_figures in shell._post_execute:
351 367 shell._post_execute.pop(flush_figures)
352 368 if hasattr(shell, '_saved_rcParams'):
353 369 pyplot.rcParams.update(shell._saved_rcParams)
354 370 del shell._saved_rcParams
355 371
356 372 # Setup the default figure format
357 select_figure_formats(shell, cfg.figure_formats, cfg.quality)
373 select_figure_formats(shell, cfg.figure_formats, **cfg.print_figure_kwargs)
358 374
@@ -1,60 +1,118
1 1 #-----------------------------------------------------------------------------
2 2 # Copyright (C) 2010-2011 The IPython Development Team.
3 3 #
4 4 # Distributed under the terms of the BSD License.
5 5 #
6 6 # The full license is in the file COPYING.txt, distributed with this software.
7 7 #-----------------------------------------------------------------------------
8 8 import os
9 9
10 10 import nose.tools as nt
11 11
12 12 from IPython.core import display
13 from IPython.core.getipython import get_ipython
13 14 from IPython.utils import path as ipath
14 15
16 import IPython.testing.decorators as dec
17
15 18 def test_image_size():
16 19 """Simple test for display.Image(args, width=x,height=y)"""
17 20 thisurl = 'http://www.google.fr/images/srpr/logo3w.png'
18 21 img = display.Image(url=thisurl, width=200, height=200)
19 22 nt.assert_equal(u'<img src="%s" width="200" height="200"/>' % (thisurl), img._repr_html_())
20 23 img = display.Image(url=thisurl, width=200)
21 24 nt.assert_equal(u'<img src="%s" width="200"/>' % (thisurl), img._repr_html_())
22 25 img = display.Image(url=thisurl)
23 26 nt.assert_equal(u'<img src="%s"/>' % (thisurl), img._repr_html_())
24 27
25 28 def test_retina_png():
26 29 here = os.path.dirname(__file__)
27 30 img = display.Image(os.path.join(here, "2x2.png"), retina=True)
28 31 nt.assert_equal(img.height, 1)
29 32 nt.assert_equal(img.width, 1)
30 33 data, md = img._repr_png_()
31 34 nt.assert_equal(md['width'], 1)
32 35 nt.assert_equal(md['height'], 1)
33 36
34 37 def test_retina_jpeg():
35 38 here = os.path.dirname(__file__)
36 39 img = display.Image(os.path.join(here, "2x2.jpg"), retina=True)
37 40 nt.assert_equal(img.height, 1)
38 41 nt.assert_equal(img.width, 1)
39 42 data, md = img._repr_jpeg_()
40 43 nt.assert_equal(md['width'], 1)
41 44 nt.assert_equal(md['height'], 1)
42 45
43 46 def test_image_filename_defaults():
44 47 '''test format constraint, and validity of jpeg and png'''
45 48 tpath = ipath.get_ipython_package_dir()
46 49 nt.assert_raises(ValueError, display.Image, filename=os.path.join(tpath, 'testing/tests/badformat.gif'),
47 50 embed=True)
48 51 nt.assert_raises(ValueError, display.Image)
49 52 nt.assert_raises(ValueError, display.Image, data='this is not an image', format='badformat', embed=True)
50 53 from IPython.html import DEFAULT_STATIC_FILES_PATH
51 54 # check boths paths to allow packages to test at build and install time
52 55 imgfile = os.path.join(tpath, 'html/static/base/images/ipynblogo.png')
53 56 if not os.path.exists(imgfile):
54 57 imgfile = os.path.join(DEFAULT_STATIC_FILES_PATH, 'base/images/ipynblogo.png')
55 58 img = display.Image(filename=imgfile)
56 59 nt.assert_equal('png', img.format)
57 60 nt.assert_is_not_none(img._repr_png_())
58 61 img = display.Image(filename=os.path.join(tpath, 'testing/tests/logo.jpg'), embed=False)
59 62 nt.assert_equal('jpeg', img.format)
60 63 nt.assert_is_none(img._repr_jpeg_())
64
65 def _get_inline_config():
66 from IPython.kernel.zmq.pylab.config import InlineBackend
67 return InlineBackend.instance()
68
69 @dec.skip_without('matplotlib')
70 def test_set_matplotlib_close():
71 cfg = _get_inline_config()
72 cfg.close_figures = False
73 display.set_matplotlib_close()
74 assert cfg.close_figures
75 display.set_matplotlib_close(False)
76 assert not cfg.close_figures
77
78 _fmt_mime_map = {
79 'png': 'image/png',
80 'jpeg': 'image/jpeg',
81 'pdf': 'application/pdf',
82 'retina': 'image/png',
83 'svg': 'image/svg+xml',
84 }
85
86 @dec.skip_without('matplotlib')
87 def test_set_matplotlib_formats():
88 from matplotlib.figure import Figure
89 formatters = get_ipython().display_formatter.formatters
90 for formats in [
91 ('png',),
92 ('pdf', 'svg'),
93 ('jpeg', 'retina', 'png'),
94 (),
95 ]:
96 active_mimes = {_fmt_mime_map[fmt] for fmt in formats}
97 display.set_matplotlib_formats(*formats)
98 for mime, f in formatters.items():
99 if mime in active_mimes:
100 nt.assert_in(Figure, f)
101 else:
102 nt.assert_not_in(Figure, f)
103
104 @dec.skip_without('matplotlib')
105 def test_set_matplotlib_formats_kwargs():
106 from matplotlib.figure import Figure
107 ip = get_ipython()
108 cfg = _get_inline_config()
109 cfg.print_figure_kwargs.update(dict(foo='bar'))
110 kwargs = dict(quality=10)
111 display.set_matplotlib_formats('png', **kwargs)
112 formatter = ip.display_formatter.formatters['image/png']
113 f = formatter.lookup_by_type(Figure)
114 cell = f.__closure__[0].cell_contents
115 expected = kwargs
116 expected.update(cfg.print_figure_kwargs)
117 nt.assert_equal(cell, expected)
118
@@ -1,153 +1,224
1 1 """Tests for pylab tools module.
2 2 """
3 3 #-----------------------------------------------------------------------------
4 4 # Copyright (c) 2011, the IPython Development Team.
5 5 #
6 6 # Distributed under the terms of the Modified BSD License.
7 7 #
8 8 # The full license is in the file COPYING.txt, distributed with this software.
9 9 #-----------------------------------------------------------------------------
10 10
11 11 #-----------------------------------------------------------------------------
12 12 # Imports
13 13 #-----------------------------------------------------------------------------
14 14 from __future__ import print_function
15 15
16 # Stdlib imports
16 import matplotlib
17 matplotlib.use('Agg')
18 from matplotlib.figure import Figure
17 19
18 # Third-party imports
19 import matplotlib; matplotlib.use('Agg')
20 20 import nose.tools as nt
21 21
22 22 from matplotlib import pyplot as plt
23 23 import numpy as np
24 24
25 25 # Our own imports
26 from IPython.core.getipython import get_ipython
26 27 from IPython.core.interactiveshell import InteractiveShell
28 from IPython.core.display import _PNG, _JPEG
27 29 from .. import pylabtools as pt
28 30
29 31 from IPython.testing import decorators as dec
30 32
31 33 #-----------------------------------------------------------------------------
32 34 # Globals and constants
33 35 #-----------------------------------------------------------------------------
34 36
35 37 #-----------------------------------------------------------------------------
36 38 # Local utilities
37 39 #-----------------------------------------------------------------------------
38 40
39 41 #-----------------------------------------------------------------------------
40 42 # Classes and functions
41 43 #-----------------------------------------------------------------------------
42 44
43 45 def test_figure_to_svg():
44 46 # simple empty-figure test
45 47 fig = plt.figure()
46 48 nt.assert_equal(pt.print_figure(fig, 'svg'), None)
47 49
48 50 plt.close('all')
49 51
50 52 # simple check for at least svg-looking output
51 53 fig = plt.figure()
52 54 ax = fig.add_subplot(1,1,1)
53 55 ax.plot([1,2,3])
54 56 plt.draw()
55 57 svg = pt.print_figure(fig, 'svg')[:100].lower()
56 58 nt.assert_in(b'doctype svg', svg)
57 59
58 60 @dec.skip_without("PIL.Image")
59 61 def test_figure_to_jpg():
60 62 # simple check for at least jpg-looking output
61 63 fig = plt.figure()
62 64 ax = fig.add_subplot(1,1,1)
63 65 ax.plot([1,2,3])
64 66 plt.draw()
65 jpg = pt.print_figure(fig, 'jpg')[:100].lower()
66 assert jpg.startswith(b'\xff\xd8')
67 jpg = pt.print_figure(fig, 'jpg', quality=50)[:100].lower()
68 assert jpg.startswith(_JPEG)
67 69
70 def test_retina_figure():
71 fig = plt.figure()
72 ax = fig.add_subplot(1,1,1)
73 ax.plot([1,2,3])
74 plt.draw()
75 png, md = pt.retina_figure(fig)
76 assert png.startswith(_PNG)
77 nt.assert_in('width', md)
78 nt.assert_in('height', md)
79
80 _fmt_mime_map = {
81 'png': 'image/png',
82 'jpeg': 'image/jpeg',
83 'pdf': 'application/pdf',
84 'retina': 'image/png',
85 'svg': 'image/svg+xml',
86 }
87
88 def test_select_figure_formats_str():
89 ip = get_ipython()
90 for fmt, active_mime in _fmt_mime_map.items():
91 pt.select_figure_formats(ip, fmt)
92 for mime, f in ip.display_formatter.formatters.items():
93 if mime == active_mime:
94 nt.assert_in(Figure, f)
95 else:
96 nt.assert_not_in(Figure, f)
97
98 def test_select_figure_formats_kwargs():
99 ip = get_ipython()
100 kwargs = dict(quality=10, bbox_inches='tight')
101 pt.select_figure_formats(ip, 'png', **kwargs)
102 formatter = ip.display_formatter.formatters['image/png']
103 f = formatter.lookup_by_type(Figure)
104 cell = f.__closure__[0].cell_contents
105 nt.assert_equal(cell, kwargs)
106
107 # check that the formatter doesn't raise
108 fig = plt.figure()
109 ax = fig.add_subplot(1,1,1)
110 ax.plot([1,2,3])
111 plt.draw()
112 formatter.enabled = True
113 png = formatter(fig)
114 assert png.startswith(_PNG)
68 115
69 def test_import_pylab():
116 def test_select_figure_formats_set():
70 117 ip = get_ipython()
118 for fmts in [
119 {'png', 'svg'},
120 ['png'],
121 ('jpeg', 'pdf', 'retina'),
122 {'svg'},
123 ]:
124 active_mimes = {_fmt_mime_map[fmt] for fmt in fmts}
125 pt.select_figure_formats(ip, fmts)
126 for mime, f in ip.display_formatter.formatters.items():
127 if mime in active_mimes:
128 nt.assert_in(Figure, f)
129 else:
130 nt.assert_not_in(Figure, f)
131
132 def test_select_figure_formats_bad():
133 ip = get_ipython()
134 with nt.assert_raises(ValueError):
135 pt.select_figure_formats(ip, 'foo')
136 with nt.assert_raises(ValueError):
137 pt.select_figure_formats(ip, {'png', 'foo'})
138 with nt.assert_raises(ValueError):
139 pt.select_figure_formats(ip, ['retina', 'pdf', 'bar', 'bad'])
140
141 def test_import_pylab():
71 142 ns = {}
72 143 pt.import_pylab(ns, import_all=False)
73 144 nt.assert_true('plt' in ns)
74 145 nt.assert_equal(ns['np'], np)
75 146
76 147 class TestPylabSwitch(object):
77 148 class Shell(InteractiveShell):
78 149 def enable_gui(self, gui):
79 150 pass
80 151
81 152 def setup(self):
82 153 import matplotlib
83 154 def act_mpl(backend):
84 155 matplotlib.rcParams['backend'] = backend
85 156
86 157 # Save rcParams since they get modified
87 158 self._saved_rcParams = matplotlib.rcParams
88 159 self._saved_rcParamsOrig = matplotlib.rcParamsOrig
89 160 matplotlib.rcParams = dict(backend='Qt4Agg')
90 161 matplotlib.rcParamsOrig = dict(backend='Qt4Agg')
91 162
92 163 # Mock out functions
93 164 self._save_am = pt.activate_matplotlib
94 165 pt.activate_matplotlib = act_mpl
95 166 self._save_ip = pt.import_pylab
96 167 pt.import_pylab = lambda *a,**kw:None
97 168 self._save_cis = pt.configure_inline_support
98 169 pt.configure_inline_support = lambda *a,**kw:None
99 170
100 171 def teardown(self):
101 172 pt.activate_matplotlib = self._save_am
102 173 pt.import_pylab = self._save_ip
103 174 pt.configure_inline_support = self._save_cis
104 175 import matplotlib
105 176 matplotlib.rcParams = self._saved_rcParams
106 177 matplotlib.rcParamsOrig = self._saved_rcParamsOrig
107 178
108 179 def test_qt(self):
109 180 s = self.Shell()
110 181 gui, backend = s.enable_matplotlib(None)
111 182 nt.assert_equal(gui, 'qt')
112 183 nt.assert_equal(s.pylab_gui_select, 'qt')
113 184
114 185 gui, backend = s.enable_matplotlib('inline')
115 186 nt.assert_equal(gui, 'inline')
116 187 nt.assert_equal(s.pylab_gui_select, 'qt')
117 188
118 189 gui, backend = s.enable_matplotlib('qt')
119 190 nt.assert_equal(gui, 'qt')
120 191 nt.assert_equal(s.pylab_gui_select, 'qt')
121 192
122 193 gui, backend = s.enable_matplotlib('inline')
123 194 nt.assert_equal(gui, 'inline')
124 195 nt.assert_equal(s.pylab_gui_select, 'qt')
125 196
126 197 gui, backend = s.enable_matplotlib()
127 198 nt.assert_equal(gui, 'qt')
128 199 nt.assert_equal(s.pylab_gui_select, 'qt')
129 200
130 201 def test_inline(self):
131 202 s = self.Shell()
132 203 gui, backend = s.enable_matplotlib('inline')
133 204 nt.assert_equal(gui, 'inline')
134 205 nt.assert_equal(s.pylab_gui_select, None)
135 206
136 207 gui, backend = s.enable_matplotlib('inline')
137 208 nt.assert_equal(gui, 'inline')
138 209 nt.assert_equal(s.pylab_gui_select, None)
139 210
140 211 gui, backend = s.enable_matplotlib('qt')
141 212 nt.assert_equal(gui, 'qt')
142 213 nt.assert_equal(s.pylab_gui_select, 'qt')
143 214
144 215 def test_qt_gtk(self):
145 216 s = self.Shell()
146 217 gui, backend = s.enable_matplotlib('qt')
147 218 nt.assert_equal(gui, 'qt')
148 219 nt.assert_equal(s.pylab_gui_select, 'qt')
149 220
150 221 gui, backend = s.enable_matplotlib('gtk')
151 222 nt.assert_equal(gui, 'qt')
152 223 nt.assert_equal(s.pylab_gui_select, 'qt')
153 224
@@ -1,115 +1,117
1 1 """Configurable for configuring the IPython inline backend
2 2
3 3 This module does not import anything from matplotlib.
4 4 """
5 5 #-----------------------------------------------------------------------------
6 6 # Copyright (C) 2011 The IPython Development Team
7 7 #
8 8 # Distributed under the terms of the BSD License. The full license is in
9 9 # the file COPYING, distributed as part of this software.
10 10 #-----------------------------------------------------------------------------
11 11
12 12 #-----------------------------------------------------------------------------
13 13 # Imports
14 14 #-----------------------------------------------------------------------------
15 15
16 16 from IPython.config.configurable import SingletonConfigurable
17 17 from IPython.utils.traitlets import (
18 18 Dict, Instance, CaselessStrEnum, Set, Bool, Int, TraitError, Unicode
19 19 )
20 20 from IPython.utils.warn import warn
21 21
22 22 #-----------------------------------------------------------------------------
23 23 # Configurable for inline backend options
24 24 #-----------------------------------------------------------------------------
25 25
26 26 def pil_available():
27 27 """Test if PIL/Pillow is available"""
28 28 out = False
29 29 try:
30 30 from PIL import Image
31 31 out = True
32 32 except:
33 33 pass
34 34 return out
35 35
36 36 # inherit from InlineBackendConfig for deprecation purposes
37 37 class InlineBackendConfig(SingletonConfigurable):
38 38 pass
39 39
40 40 class InlineBackend(InlineBackendConfig):
41 41 """An object to store configuration of the inline backend."""
42 42
43 43 def _config_changed(self, name, old, new):
44 44 # warn on change of renamed config section
45 45 if new.InlineBackendConfig != old.InlineBackendConfig:
46 46 warn("InlineBackendConfig has been renamed to InlineBackend")
47 47 super(InlineBackend, self)._config_changed(name, old, new)
48 48
49 49 # The typical default figure size is too large for inline use,
50 50 # so we shrink the figure size to 6x4, and tweak fonts to
51 51 # make that fit.
52 52 rc = Dict({'figure.figsize': (6.0,4.0),
53 53 # play nicely with white background in the Qt and notebook frontend
54 54 'figure.facecolor': (1,1,1,0),
55 55 'figure.edgecolor': (1,1,1,0),
56 56 # 12pt labels get cutoff on 6x4 logplots, so use 10pt.
57 57 'font.size': 10,
58 58 # 72 dpi matches SVG/qtconsole
59 59 # this only affects PNG export, as SVG has no dpi setting
60 60 'savefig.dpi': 72,
61 61 # 10pt still needs a little more room on the xlabel:
62 62 'figure.subplot.bottom' : .125
63 63 }, config=True,
64 64 help="""Subset of matplotlib rcParams that should be different for the
65 65 inline backend."""
66 66 )
67 67
68 68 figure_formats = Set({'png'}, config=True,
69 69 help="""A set of figure formats to enable: 'png',
70 70 'retina', 'jpeg', 'svg', 'pdf'.""")
71 71
72 def _update_figure_formatters(self):
73 if self.shell is not None:
74 select_figure_formats(self.shell, self.figure_formats, **self.print_figure_kwargs)
75
72 76 def _figure_formats_changed(self, name, old, new):
73 77 from IPython.core.pylabtools import select_figure_formats
74 78 if 'jpg' in new or 'jpeg' in new:
75 79 if not pil_available():
76 80 raise TraitError("Requires PIL/Pillow for JPG figures")
77 if self.shell is None:
78 return
79 else:
80 select_figure_formats(self.shell, new)
81 self._update_figure_formatters()
81 82
82 83 figure_format = Unicode(config=True, help="""The figure format to enable (deprecated
83 84 use `figure_formats` instead)""")
84 85
85 86 def _figure_format_changed(self, name, old, new):
86 87 if new:
87 88 self.figure_formats = {new}
88 89
89 quality = Int(default_value=90, config=True,
90 help="Quality of compression [10-100], currently for lossy JPEG only.")
90 print_figure_kwargs = Dict({'bbox_inches' : 'tight'}, config=True,
91 help="""Extra kwargs to be passed to fig.canvas.print_figure.
91 92
92 def _quality_changed(self, name, old, new):
93 if new < 10 or new > 100:
94 raise TraitError("figure JPEG quality must be in [10-100] range.")
93 Logical examples include: bbox_inches, quality (for jpeg figures), etc.
94 """
95 )
96 _print_figure_kwargs_changed = _update_figure_formatters
95 97
96 98 close_figures = Bool(True, config=True,
97 99 help="""Close all figures at the end of each cell.
98 100
99 101 When True, ensures that each cell starts with no active figures, but it
100 102 also means that one must keep track of references in order to edit or
101 103 redraw figures in subsequent cells. This mode is ideal for the notebook,
102 104 where residual plots from other cells might be surprising.
103 105
104 106 When False, one must call figure() to create new figures. This means
105 107 that gcf() and getfigs() can reference figures created in other cells,
106 108 and the active figure can continue to be edited with pylab/pyplot
107 109 methods that reference the current active figure. This mode facilitates
108 110 iterative editing of figures, and behaves most consistently with
109 111 other matplotlib backends, but figure barriers between cells must
110 112 be explicit.
111 113 """)
112 114
113 115 shell = Instance('IPython.core.interactiveshell.InteractiveShellABC')
114 116
115 117
@@ -1,285 +1,283
1 1 =====================
2 2 Development version
3 3 =====================
4 4
5 5 This document describes in-flight development work.
6 6
7 7 .. warning::
8 8
9 9 Please do not edit this file by hand (doing so will likely cause merge
10 10 conflicts for other Pull Requests). Instead, create a new file in the
11 11 `docs/source/whatsnew/pr` folder
12 12
13 13 Select Notebook Name When Renaming a Notebook
14 14 ---------------------------------------------
15 15
16 16 The default notebook name is Untitled. It's unlikely you want to keep this name
17 17 or part of it when naming your notebook. Instead, IPython will select the text
18 18 in the input field so the user can easily type over the name and change it.
19 19
20 20 clear_output changes
21 21 --------------------
22 22
23 23 * There is no longer a 500ms delay when calling ``clear_output``.
24 24 * The ability to clear stderr and stdout individually was removed.
25 25 * A new ``wait`` flag that prevents ``clear_output`` from being executed until new
26 26 output is available. This eliminates animation flickering by allowing the
27 27 user to double buffer the output.
28 28 * The output div height is remembered when the ``wait=True`` flag is used.
29 29
30 30 Extending Configurable Containers
31 31 ---------------------------------
32 32
33 33 Some configurable traits are containers (list, dict, set)
34 34 Config objects now support calling ``extend``, ``update``, ``insert``, etc.
35 35 on traits in config files, which will ultimately result in calling
36 36 those methods on the original object.
37 37
38 38 The effect being that you can now add to containers without having to copy/paste
39 39 the initial value::
40 40
41 41 c = get_config()
42 42 c.InlineBackend.rc.update({ 'figure.figsize' : (6, 4) })
43 43
44 44 Single codebase Python 3 support
45 45 --------------------------------
46 46
47 47 IPython previously supported Python 3 by running 2to3 during setup. We
48 48 have now switched to a single codebase which runs natively on Python 2.7
49 49 and 3.3.
50 50
51 51 For notes on how to maintain this, see :doc:`/development/pycompat`.
52 52
53 53 changes to hidden namespace on startup
54 54 --------------------------------------
55 55
56 56 Previously, all names declared in code run at startup
57 57 (startup files, ``ipython -i script.py``, etc.)
58 58 were added to the hidden namespace, which hides the names from tools like ``%whos``.
59 59 There are two changes to this behavior:
60 60
61 61 1. Scripts run on the command-line ``ipython -i script.py``now behave the same as if they were
62 62 passed to ``%run``, so their variables are never hidden.
63 63 2. A boolean config flag ``InteractiveShellApp.hide_initial_ns`` has been added to optionally
64 64 disable the hidden behavior altogether. The default behavior is unchanged.
65 65
66 66 Using dill to expand serialization support
67 67 ------------------------------------------
68 68
69 69 adds :func:`~IPython.utils.pickleutil.use_dill` for allowing
70 70 dill to extend serialization support in :mod:`IPython.parallel` (closures, etc.).
71 71 Also adds :meth:`DirectView.use_dill` convenience method for enabling dill
72 72 locally and on all engines with one call.
73 73
74 74 New IPython Console Lexer
75 75 -------------------------
76 76
77 77 The IPython console lexer has been rewritten and now supports tracebacks
78 78 and customized input/output prompts. An entire suite of lexers is now
79 79 available at :mod:`IPython.nbconvert.utils.lexers`. These include:
80 80
81 81 IPythonLexer & IPython3Lexer
82 82 Lexers for pure IPython (python + magic/shell commands)
83 83
84 84 IPythonPartialTracebackLexer & IPythonTracebackLexer
85 85 Supports 2.x and 3.x via the keyword `python3`. The partial traceback
86 86 lexer reads everything but the Python code appearing in a traceback.
87 87 The full lexer combines the partial lexer with an IPython lexer.
88 88
89 89 IPythonConsoleLexer
90 90 A lexer for IPython console sessions, with support for tracebacks.
91 91 Supports 2.x and 3.x via the keyword `python3`.
92 92
93 93 IPyLexer
94 94 A friendly lexer which examines the first line of text and from it,
95 95 decides whether to use an IPython lexer or an IPython console lexer.
96 96 Supports 2.x and 3.x via the keyword `python3`.
97 97
98 98 Previously, the :class:`IPythonConsoleLexer` class was available at
99 99 :mod:`IPython.sphinxext.ipython_console_hightlight`. It was inserted
100 100 into Pygments' list of available lexers under the name `ipython`. It should
101 101 be mentioned that this name is inaccurate, since an IPython console session
102 102 is not the same as IPython code (which itself is a superset of the Python
103 103 language).
104 104
105 105 Now, the Sphinx extension inserts two console lexers into Pygments' list of
106 106 available lexers. Both are IPyLexer instances under the names: `ipython` and
107 107 `ipython3`. Although the names can be confusing (as mentioned above), their
108 108 continued use is, in part, to maintain backwards compatibility and to
109 109 aid typical usage. If a project needs to make Pygments aware of more than just
110 110 the IPyLexer class, then one should not make the IPyLexer class available under
111 111 the name `ipython` and use `ipy` or some other non-conflicting value.
112 112
113 113 Code blocks such as:
114 114
115 115 .. code-block:: rst
116 116
117 117 .. code-block:: ipython
118 118
119 119 In [1]: 2**2
120 120 Out[1]: 4
121 121
122 122 will continue to work as before, but now, they will also properly highlight
123 123 tracebacks. For pure IPython code, the same lexer will also work:
124 124
125 125 .. code-block:: rst
126 126
127 127 .. code-block:: ipython
128 128
129 129 x = ''.join(map(str, range(10)))
130 130 !echo $x
131 131
132 132 Since the first line of the block did not begin with a standard IPython console
133 133 prompt, the entire block is assumed to consist of IPython code instead.
134 134
135 135 DisplayFormatter changes
136 136 ------------------------
137 137
138 138 There was no official way to query or remove callbacks in the Formatter API.
139 139 To remedy this, the following methods are added to :class:`BaseFormatter`:
140 140
141 141 - ``lookup(instance)`` - return appropriate callback or a given object
142 142 - ``lookup_by_type(type_or_str)`` - return appropriate callback for a given type or ``'mod.name'`` type string
143 143 - ``pop(type_or_str)`` - remove a type (by type or string).
144 144 Pass a second argument to avoid KeyError (like dict).
145 145
146 146 All of the above methods raise a KeyError if no match is found.
147 147
148 148 And the following methods are changed:
149 149
150 150 - ``for_type(type_or_str)`` - behaves the same as before, only adding support for ``'mod.name'``
151 151 type strings in addition to plain types. This removes the need for ``for_type_by_name()``,
152 152 but it remains for backward compatibility.
153 153
154 154 Notebook Widgets
155 155 ----------------
156 156
157 157 Available in the new `IPython.html.widgets` namespace, widgets provide an easy
158 158 way for IPython notebook users to display GUI controls in the IPython notebook.
159 159 IPython comes with bundle of built-in widgets and also the ability for users
160 160 to define their own widgets. A widget is displayed in the front-end using
161 161 using a view. For example, a FloatRangeWidget can be displayed using a
162 162 FloatSliderView (which is the default if no view is specified when displaying
163 163 the widget). IPython also comes with a bundle of views and the ability for the
164 164 user to define custom views. One widget can be displayed multiple times, in on
165 165 or more cells, using one or more views. All views will automatically remain in
166 166 sync with the widget which is accessible in the back-end.
167 167
168 168 The widget layer provides an MVC-like architecture on top of the comm layer.
169 169 It's useful for widgets that can be expressed via a list of properties.
170 170 Widgets work by synchronizing IPython traitlet models in the back-end with
171 171 backbone models in the front-end. The widget layer automatically handles
172 172
173 173 * delta compression (only sending the state information that has changed)
174 174 * wiring the message callbacks to the correct cells automatically
175 175 * inter-view synchronization (handled by backbone)
176 176 * message throttling (to avoid flooding the kernel)
177 177 * parent/child relationships between views (which one can override to specify custom parent/child relationships)
178 178 * ability to manipulate the widget view's DOM from python using CSS, $().addClass, and $().removeClass methods
179 179
180 180 Signing Notebooks
181 181 -----------------
182 182
183 183 To prevent untrusted code from executing on users' behalf when notebooks open,
184 184 we have added a signature to the notebook, stored in metadata.
185 185
186 186 For more information, see :ref:`signing_notebooks`.
187 187
188 188 Other changes
189 189 -------------
190 190
191 191 * `%%capture` cell magic now captures the rich display output, not just
192 192 stdout/stderr
193 193
194 194 * In notebook, Showing tooltip on tab has been disables to avoid conflict with
195 195 completion, Shift-Tab could still be used to invoke tooltip when inside
196 196 function signature and/or on selection.
197 197
198 198 * ``object_info_request`` as been replaced by ``object_info`` for consistency in the javascript API.
199 199 ``object_info`` as a simpler interface to register callback that is incompatible with ``object_info_request``.
200 200
201 201 * Previous versions of IPython on Linux would use the XDG config directory,
202 202 creating :file:`~/.config/ipython` by default. We have decided to go
203 203 back to :file:`~/.ipython` for consistency among systems. IPython will
204 204 issue a warning if it finds the XDG location, and will move it to the new
205 205 location if there isn't already a directory there.
206 206
207 207 * Equations, images and tables are now centered in Markdown cells.
208 208 * Multiline equations are now centered in output areas; single line equations
209 209 remain left justified.
210 210
211 211 * IPython config objects can be loaded from and serialized to JSON.
212 212 JSON config file have the same base name as their ``.py`` counterpart,
213 213 and will be loaded with higher priority if found.
214 214
215 215 * bash completion updated with support for all ipython subcommands and flags, including nbconvert
216 216
217 217 * ``ipython history trim``: added ``--keep=<N>`` as an alias for the more verbose
218 218 ``--HistoryTrim.keep=<N>``
219 219 * new ``ipython history clear`` subcommand, which is the same as the newly supported
220 220 ``ipython history trim --keep=0``
221 221
222 222 * You can now run notebooks in an interactive session via ``%run notebook.ipynb``.
223 223
224 224 * Print preview is back in the notebook menus, along with options to
225 225 download the open notebook in various formats. This is powered by
226 226 nbconvert.
227 227
228 228 * :exc:`~IPython.nbconvert.utils.pandoc.PandocMissing` exceptions will be
229 229 raised if Pandoc is unavailable, and warnings will be printed if the version
230 230 found is too old. The recommended Pandoc version for use with nbconvert is
231 231 1.12.1.
232 232
233 233 * The InlineBackend.figure_format flag now supports JPEG output if PIL/Pillow is available.
234 * The new ``InlineBackend.quality`` flag is a Integer in the range [10, 100] which controls
235 the quality of figures where higher values give nicer images (currently JPEG only).
236 234
237 235 * Input transformers (see :doc:`/config/inputtransforms`) may now raise
238 236 :exc:`SyntaxError` if they determine that input is invalid. The input
239 237 transformation machinery in IPython will handle displaying the exception to
240 238 the user and resetting state.
241 239
242 240 .. DO NOT EDIT THIS LINE BEFORE RELEASE. FEATURE INSERTION POINT.
243 241
244 242 Backwards incompatible changes
245 243 ------------------------------
246 244
247 245 * Python 2.6 and 3.2 are no longer supported: the minimum required
248 246 Python versions are now 2.7 and 3.3.
249 247 * The Transformer classes have been renamed to Preprocessor in nbconvert and
250 248 their `call` methods for them have been renamed to `preprocess`.
251 249 * The `call` methods of nbconvert post-processsors have been renamed to
252 250 `postprocess`.
253 251
254 252 * The module ``IPython.core.fakemodule`` has been removed.
255 253
256 254 * The alias system has been reimplemented to use magic functions. There should be little
257 255 visible difference while automagics are enabled, as they are by default, but parts of the
258 256 :class:`~IPython.core.alias.AliasManager` API have been removed.
259 257
260 258 * We fixed an issue with switching between matplotlib inline and GUI backends,
261 259 but the fix requires matplotlib 1.1 or newer. So from now on, we consider
262 260 matplotlib 1.1 to be the minimally supported version for IPython. Older
263 261 versions for the most part will work, but we make no guarantees about it.
264 262
265 263 * The :command:`pycolor` command has been removed. We recommend the much more capable
266 264 :command:`pygmentize` command from the `Pygments <http://pygments.org/>`_ project.
267 265 If you need to keep the exact output of :command:`pycolor`, you can still use
268 266 ``python -m IPython.utils.PyColorize foo.py``.
269 267
270 268 * :mod:`IPython.lib.irunner` and its command-line entry point have been removed.
271 269 It had fallen out of use long ago.
272 270
273 271 * The ``input_prefilter`` hook has been removed, as it was never
274 272 actually used by the code. The input transformer system offers much
275 273 more powerful APIs to work with input code. See
276 274 :doc:`/config/inputtransforms` for details.
277 275
278 276 * :class:`IPython.core.inputsplitter.IPythonInputSplitter` no longer has a method
279 277 ``source_raw_reset()``, but gains :meth:`~IPython.core.inputsplitter.IPythonInputSplitter.raw_reset`
280 278 instead. Use of ``source_raw_reset`` can be replaced with::
281 279
282 280 raw = isp.source_raw
283 281 transformed = isp.source_reset()
284 282
285 283 .. DO NOT EDIT THIS LINE BEFORE RELEASE. INCOMPAT INSERTION POINT.
General Comments 0
You need to be logged in to leave comments. Login now