##// END OF EJS Templates
enable retina display of Image objects...
MinRK -
Show More
@@ -1,635 +1,689 b''
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 import struct
23 24
24 25 from IPython.utils.py3compat import string_types
25 26
26 27 from .displaypub import publish_display_data
27 28
28 29 #-----------------------------------------------------------------------------
29 30 # utility functions
30 31 #-----------------------------------------------------------------------------
31 32
32 33 def _safe_exists(path):
33 34 """Check path, but don't let exceptions raise"""
34 35 try:
35 36 return os.path.exists(path)
36 37 except Exception:
37 38 return False
38 39
39 40 def _merge(d1, d2):
40 41 """Like update, but merges sub-dicts instead of clobbering at the top level.
41 42
42 43 Updates d1 in-place
43 44 """
44 45
45 46 if not isinstance(d2, dict) or not isinstance(d1, dict):
46 47 return d2
47 48 for key, value in d2.items():
48 49 d1[key] = _merge(d1.get(key), value)
49 50 return d1
50 51
51 52 def _display_mimetype(mimetype, objs, raw=False, metadata=None):
52 53 """internal implementation of all display_foo methods
53 54
54 55 Parameters
55 56 ----------
56 57 mimetype : str
57 58 The mimetype to be published (e.g. 'image/png')
58 59 objs : tuple of objects
59 60 The Python objects to display, or if raw=True raw text data to
60 61 display.
61 62 raw : bool
62 63 Are the data objects raw data or Python objects that need to be
63 64 formatted before display? [default: False]
64 65 metadata : dict (optional)
65 66 Metadata to be associated with the specific mimetype output.
66 67 """
67 68 if metadata:
68 69 metadata = {mimetype: metadata}
69 70 if raw:
70 71 # turn list of pngdata into list of { 'image/png': pngdata }
71 72 objs = [ {mimetype: obj} for obj in objs ]
72 73 display(*objs, raw=raw, metadata=metadata, include=[mimetype])
73 74
74 75 #-----------------------------------------------------------------------------
75 76 # Main functions
76 77 #-----------------------------------------------------------------------------
77 78
78 79 def display(*objs, **kwargs):
79 80 """Display a Python object in all frontends.
80 81
81 82 By default all representations will be computed and sent to the frontends.
82 83 Frontends can decide which representation is used and how.
83 84
84 85 Parameters
85 86 ----------
86 87 objs : tuple of objects
87 88 The Python objects to display.
88 89 raw : bool, optional
89 90 Are the objects to be displayed already mimetype-keyed dicts of raw display data,
90 91 or Python objects that need to be formatted before display? [default: False]
91 92 include : list or tuple, optional
92 93 A list of format type strings (MIME types) to include in the
93 94 format data dict. If this is set *only* the format types included
94 95 in this list will be computed.
95 96 exclude : list or tuple, optional
96 97 A list of format type strings (MIME types) to exclude in the format
97 98 data dict. If this is set all format types will be computed,
98 99 except for those included in this argument.
99 100 metadata : dict, optional
100 101 A dictionary of metadata to associate with the output.
101 102 mime-type keys in this dictionary will be associated with the individual
102 103 representation formats, if they exist.
103 104 """
104 105 raw = kwargs.get('raw', False)
105 106 include = kwargs.get('include')
106 107 exclude = kwargs.get('exclude')
107 108 metadata = kwargs.get('metadata')
108 109
109 110 from IPython.core.interactiveshell import InteractiveShell
110 111
111 112 if raw:
112 113 for obj in objs:
113 114 publish_display_data('display', obj, metadata)
114 115 else:
115 116 format = InteractiveShell.instance().display_formatter.format
116 117 for obj in objs:
117 118 format_dict, md_dict = format(obj, include=include, exclude=exclude)
118 119 if metadata:
119 120 # kwarg-specified metadata gets precedence
120 121 _merge(md_dict, metadata)
121 122 publish_display_data('display', format_dict, md_dict)
122 123
123 124
124 125 def display_pretty(*objs, **kwargs):
125 126 """Display the pretty (default) representation of an object.
126 127
127 128 Parameters
128 129 ----------
129 130 objs : tuple of objects
130 131 The Python objects to display, or if raw=True raw text data to
131 132 display.
132 133 raw : bool
133 134 Are the data objects raw data or Python objects that need to be
134 135 formatted before display? [default: False]
135 136 metadata : dict (optional)
136 137 Metadata to be associated with the specific mimetype output.
137 138 """
138 139 _display_mimetype('text/plain', objs, **kwargs)
139 140
140 141
141 142 def display_html(*objs, **kwargs):
142 143 """Display the HTML representation of an object.
143 144
144 145 Parameters
145 146 ----------
146 147 objs : tuple of objects
147 148 The Python objects to display, or if raw=True raw HTML data to
148 149 display.
149 150 raw : bool
150 151 Are the data objects raw data or Python objects that need to be
151 152 formatted before display? [default: False]
152 153 metadata : dict (optional)
153 154 Metadata to be associated with the specific mimetype output.
154 155 """
155 156 _display_mimetype('text/html', objs, **kwargs)
156 157
157 158
158 159 def display_svg(*objs, **kwargs):
159 160 """Display the SVG representation of an object.
160 161
161 162 Parameters
162 163 ----------
163 164 objs : tuple of objects
164 165 The Python objects to display, or if raw=True raw svg data to
165 166 display.
166 167 raw : bool
167 168 Are the data objects raw data or Python objects that need to be
168 169 formatted before display? [default: False]
169 170 metadata : dict (optional)
170 171 Metadata to be associated with the specific mimetype output.
171 172 """
172 173 _display_mimetype('image/svg+xml', objs, **kwargs)
173 174
174 175
175 176 def display_png(*objs, **kwargs):
176 177 """Display the PNG representation of an object.
177 178
178 179 Parameters
179 180 ----------
180 181 objs : tuple of objects
181 182 The Python objects to display, or if raw=True raw png data to
182 183 display.
183 184 raw : bool
184 185 Are the data objects raw data or Python objects that need to be
185 186 formatted before display? [default: False]
186 187 metadata : dict (optional)
187 188 Metadata to be associated with the specific mimetype output.
188 189 """
189 190 _display_mimetype('image/png', objs, **kwargs)
190 191
191 192
192 193 def display_jpeg(*objs, **kwargs):
193 194 """Display the JPEG representation of an object.
194 195
195 196 Parameters
196 197 ----------
197 198 objs : tuple of objects
198 199 The Python objects to display, or if raw=True raw JPEG data to
199 200 display.
200 201 raw : bool
201 202 Are the data objects raw data or Python objects that need to be
202 203 formatted before display? [default: False]
203 204 metadata : dict (optional)
204 205 Metadata to be associated with the specific mimetype output.
205 206 """
206 207 _display_mimetype('image/jpeg', objs, **kwargs)
207 208
208 209
209 210 def display_latex(*objs, **kwargs):
210 211 """Display the LaTeX representation of an object.
211 212
212 213 Parameters
213 214 ----------
214 215 objs : tuple of objects
215 216 The Python objects to display, or if raw=True raw latex data to
216 217 display.
217 218 raw : bool
218 219 Are the data objects raw data or Python objects that need to be
219 220 formatted before display? [default: False]
220 221 metadata : dict (optional)
221 222 Metadata to be associated with the specific mimetype output.
222 223 """
223 224 _display_mimetype('text/latex', objs, **kwargs)
224 225
225 226
226 227 def display_json(*objs, **kwargs):
227 228 """Display the JSON representation of an object.
228 229
229 230 Note that not many frontends support displaying JSON.
230 231
231 232 Parameters
232 233 ----------
233 234 objs : tuple of objects
234 235 The Python objects to display, or if raw=True raw json data to
235 236 display.
236 237 raw : bool
237 238 Are the data objects raw data or Python objects that need to be
238 239 formatted before display? [default: False]
239 240 metadata : dict (optional)
240 241 Metadata to be associated with the specific mimetype output.
241 242 """
242 243 _display_mimetype('application/json', objs, **kwargs)
243 244
244 245
245 246 def display_javascript(*objs, **kwargs):
246 247 """Display the Javascript representation of an object.
247 248
248 249 Parameters
249 250 ----------
250 251 objs : tuple of objects
251 252 The Python objects to display, or if raw=True raw javascript data to
252 253 display.
253 254 raw : bool
254 255 Are the data objects raw data or Python objects that need to be
255 256 formatted before display? [default: False]
256 257 metadata : dict (optional)
257 258 Metadata to be associated with the specific mimetype output.
258 259 """
259 260 _display_mimetype('application/javascript', objs, **kwargs)
260 261
261 262 #-----------------------------------------------------------------------------
262 263 # Smart classes
263 264 #-----------------------------------------------------------------------------
264 265
265 266
266 267 class DisplayObject(object):
267 268 """An object that wraps data to be displayed."""
268 269
269 270 _read_flags = 'r'
270 271
271 272 def __init__(self, data=None, url=None, filename=None):
272 273 """Create a display object given raw data.
273 274
274 275 When this object is returned by an expression or passed to the
275 276 display function, it will result in the data being displayed
276 277 in the frontend. The MIME type of the data should match the
277 278 subclasses used, so the Png subclass should be used for 'image/png'
278 279 data. If the data is a URL, the data will first be downloaded
279 280 and then displayed. If
280 281
281 282 Parameters
282 283 ----------
283 284 data : unicode, str or bytes
284 285 The raw data or a URL or file to load the data from
285 286 url : unicode
286 287 A URL to download the data from.
287 288 filename : unicode
288 289 Path to a local file to load the data from.
289 290 """
290 291 if data is not None and isinstance(data, string_types):
291 292 if data.startswith('http') and url is None:
292 293 url = data
293 294 filename = None
294 295 data = None
295 296 elif _safe_exists(data) and filename is None:
296 297 url = None
297 298 filename = data
298 299 data = None
299 300
300 301 self.data = data
301 302 self.url = url
302 303 self.filename = None if filename is None else unicode(filename)
303 304
304 305 self.reload()
305 306
306 307 def reload(self):
307 308 """Reload the raw data from file or URL."""
308 309 if self.filename is not None:
309 310 with open(self.filename, self._read_flags) as f:
310 311 self.data = f.read()
311 312 elif self.url is not None:
312 313 try:
313 314 import urllib2
314 315 response = urllib2.urlopen(self.url)
315 316 self.data = response.read()
316 317 # extract encoding from header, if there is one:
317 318 encoding = None
318 319 for sub in response.headers['content-type'].split(';'):
319 320 sub = sub.strip()
320 321 if sub.startswith('charset'):
321 322 encoding = sub.split('=')[-1].strip()
322 323 break
323 324 # decode data, if an encoding was specified
324 325 if encoding:
325 326 self.data = self.data.decode(encoding, 'replace')
326 327 except:
327 328 self.data = None
328 329
329 330 class Pretty(DisplayObject):
330 331
331 332 def _repr_pretty_(self):
332 333 return self.data
333 334
334 335
335 336 class HTML(DisplayObject):
336 337
337 338 def _repr_html_(self):
338 339 return self.data
339 340
340 341 def __html__(self):
341 342 """
342 343 This method exists to inform other HTML-using modules (e.g. Markupsafe,
343 344 htmltag, etc) that this object is HTML and does not need things like
344 345 special characters (<>&) escaped.
345 346 """
346 347 return self._repr_html_()
347 348
348 349
349 350 class Math(DisplayObject):
350 351
351 352 def _repr_latex_(self):
352 353 s = self.data.strip('$')
353 354 return "$$%s$$" % s
354 355
355 356
356 357 class Latex(DisplayObject):
357 358
358 359 def _repr_latex_(self):
359 360 return self.data
360 361
361 362
362 363 class SVG(DisplayObject):
363 364
364 365 # wrap data in a property, which extracts the <svg> tag, discarding
365 366 # document headers
366 367 _data = None
367 368
368 369 @property
369 370 def data(self):
370 371 return self._data
371 372
372 373 @data.setter
373 374 def data(self, svg):
374 375 if svg is None:
375 376 self._data = None
376 377 return
377 378 # parse into dom object
378 379 from xml.dom import minidom
379 380 x = minidom.parseString(svg)
380 381 # get svg tag (should be 1)
381 382 found_svg = x.getElementsByTagName('svg')
382 383 if found_svg:
383 384 svg = found_svg[0].toxml()
384 385 else:
385 386 # fallback on the input, trust the user
386 387 # but this is probably an error.
387 388 pass
388 389 self._data = svg
389 390
390 391 def _repr_svg_(self):
391 392 return self.data
392 393
393 394
394 395 class JSON(DisplayObject):
395 396
396 397 def _repr_json_(self):
397 398 return self.data
398 399
399 400 css_t = """$("head").append($("<link/>").attr({
400 401 rel: "stylesheet",
401 402 type: "text/css",
402 403 href: "%s"
403 404 }));
404 405 """
405 406
406 407 lib_t1 = """$.getScript("%s", function () {
407 408 """
408 409 lib_t2 = """});
409 410 """
410 411
411 412 class Javascript(DisplayObject):
412 413
413 414 def __init__(self, data=None, url=None, filename=None, lib=None, css=None):
414 415 """Create a Javascript display object given raw data.
415 416
416 417 When this object is returned by an expression or passed to the
417 418 display function, it will result in the data being displayed
418 419 in the frontend. If the data is a URL, the data will first be
419 420 downloaded and then displayed.
420 421
421 422 In the Notebook, the containing element will be available as `element`,
422 423 and jQuery will be available. The output area starts hidden, so if
423 424 the js appends content to `element` that should be visible, then
424 425 it must call `container.show()` to unhide the area.
425 426
426 427 Parameters
427 428 ----------
428 429 data : unicode, str or bytes
429 430 The Javascript source code or a URL to download it from.
430 431 url : unicode
431 432 A URL to download the data from.
432 433 filename : unicode
433 434 Path to a local file to load the data from.
434 435 lib : list or str
435 436 A sequence of Javascript library URLs to load asynchronously before
436 437 running the source code. The full URLs of the libraries should
437 438 be given. A single Javascript library URL can also be given as a
438 439 string.
439 440 css: : list or str
440 441 A sequence of css files to load before running the source code.
441 442 The full URLs of the css files should be given. A single css URL
442 443 can also be given as a string.
443 444 """
444 445 if isinstance(lib, basestring):
445 446 lib = [lib]
446 447 elif lib is None:
447 448 lib = []
448 449 if isinstance(css, basestring):
449 450 css = [css]
450 451 elif css is None:
451 452 css = []
452 453 if not isinstance(lib, (list,tuple)):
453 454 raise TypeError('expected sequence, got: %r' % lib)
454 455 if not isinstance(css, (list,tuple)):
455 456 raise TypeError('expected sequence, got: %r' % css)
456 457 self.lib = lib
457 458 self.css = css
458 459 super(Javascript, self).__init__(data=data, url=url, filename=filename)
459 460
460 461 def _repr_javascript_(self):
461 462 r = ''
462 463 for c in self.css:
463 464 r += css_t % c
464 465 for l in self.lib:
465 466 r += lib_t1 % l
466 467 r += self.data
467 468 r += lib_t2*len(self.lib)
468 469 return r
469 470
470 471 # constants for identifying png/jpeg data
471 472 _PNG = b'\x89PNG\r\n\x1a\n'
472 473 _JPEG = b'\xff\xd8'
473 474
475 def _pngxy(data):
476 """read the (width, height) from a PNG header"""
477 ihdr = data.index(b'IHDR')
478 # next 8 bytes are width/height
479 w4h4 = data[ihdr+4:ihdr+12]
480 return struct.unpack('>ii', w4h4)
481
482 def _jpegxy(data):
483 """read the (width, height) from a JPEG header"""
484 # adapted from http://www.64lines.com/jpeg-width-height
485
486 idx = 4
487 while True:
488 block_size = struct.unpack('>H', data[idx:idx+2])[0]
489 idx = idx + block_size
490 if data[idx:idx+2] == b'\xFF\xC0':
491 # found Start of Frame
492 iSOF = idx
493 break
494 else:
495 # read another block
496 idx += 2
497
498 h, w = struct.unpack('>HH', data[iSOF+5:iSOF+9])
499 return w, h
500
474 501 class Image(DisplayObject):
475 502
476 503 _read_flags = 'rb'
477 504 _FMT_JPEG = u'jpeg'
478 505 _FMT_PNG = u'png'
479 506 _ACCEPTABLE_EMBEDDINGS = [_FMT_JPEG, _FMT_PNG]
480 507
481 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None):
508 def __init__(self, data=None, url=None, filename=None, format=u'png', embed=None, width=None, height=None, retina=False):
482 509 """Create a display an PNG/JPEG image given raw data.
483 510
484 511 When this object is returned by an expression or passed to the
485 512 display function, it will result in the image being displayed
486 513 in the frontend.
487 514
488 515 Parameters
489 516 ----------
490 517 data : unicode, str or bytes
491 518 The raw image data or a URL or filename to load the data from.
492 519 This always results in embedded image data.
493 520 url : unicode
494 521 A URL to download the data from. If you specify `url=`,
495 522 the image data will not be embedded unless you also specify `embed=True`.
496 523 filename : unicode
497 524 Path to a local file to load the data from.
498 525 Images from a file are always embedded.
499 526 format : unicode
500 527 The format of the image data (png/jpeg/jpg). If a filename or URL is given
501 528 for format will be inferred from the filename extension.
502 529 embed : bool
503 530 Should the image data be embedded using a data URI (True) or be
504 531 loaded using an <img> tag. Set this to True if you want the image
505 532 to be viewable later with no internet connection in the notebook.
506 533
507 534 Default is `True`, unless the keyword argument `url` is set, then
508 535 default value is `False`.
509 536
510 537 Note that QtConsole is not able to display images if `embed` is set to `False`
511 538 width : int
512 539 Width to which to constrain the image in html
513 540 height : int
514 541 Height to which to constrain the image in html
542 retina : bool
543 Automatically set the width and height to half of the measured
544 width and height.
545 This only works for embedded images because it reads the width/height
546 from image data.
547 For non-embedded images, you can just set the desired display width
548 and height directly.
515 549
516 550 Examples
517 551 --------
518 552 # embedded image data, works in qtconsole and notebook
519 553 # when passed positionally, the first arg can be any of raw image data,
520 554 # a URL, or a filename from which to load image data.
521 555 # The result is always embedding image data for inline images.
522 556 Image('http://www.google.fr/images/srpr/logo3w.png')
523 557 Image('/path/to/image.jpg')
524 558 Image(b'RAW_PNG_DATA...')
525 559
526 560 # Specifying Image(url=...) does not embed the image data,
527 561 # it only generates `<img>` tag with a link to the source.
528 562 # This will not work in the qtconsole or offline.
529 563 Image(url='http://www.google.fr/images/srpr/logo3w.png')
530 564
531 565 """
532 566 if filename is not None:
533 567 ext = self._find_ext(filename)
534 568 elif url is not None:
535 569 ext = self._find_ext(url)
536 570 elif data is None:
537 571 raise ValueError("No image data found. Expecting filename, url, or data.")
538 572 elif isinstance(data, string_types) and (
539 573 data.startswith('http') or _safe_exists(data)
540 574 ):
541 575 ext = self._find_ext(data)
542 576 else:
543 577 ext = None
544 578
545 579 if ext is not None:
546 580 format = ext.lower()
547 581 if ext == u'jpg' or ext == u'jpeg':
548 582 format = self._FMT_JPEG
549 583 if ext == u'png':
550 584 format = self._FMT_PNG
551 585 elif isinstance(data, bytes) and format == 'png':
552 586 # infer image type from image data header,
553 587 # only if format might not have been specified.
554 588 if data[:2] == _JPEG:
555 589 format = 'jpeg'
556 590
557 591 self.format = unicode(format).lower()
558 592 self.embed = embed if embed is not None else (url is None)
559 593
560 594 if self.embed and self.format not in self._ACCEPTABLE_EMBEDDINGS:
561 595 raise ValueError("Cannot embed the '%s' image format" % (self.format))
562 596 self.width = width
563 597 self.height = height
598 self.retina = retina
564 599 super(Image, self).__init__(data=data, url=url, filename=filename)
600
601 if retina:
602 self._retina_shape()
603
604 def _retina_shape(self):
605 """load pixel-doubled width and height from image data"""
606 if not self.embed:
607 return
608 if self.format == 'png':
609 w, h = _pngxy(self.data)
610 elif self.format == 'jpeg':
611 w, h = _jpegxy(self.data)
612 else:
613 # retina only supports png
614 return
615 self.width = w // 2
616 self.height = h // 2
565 617
566 618 def reload(self):
567 619 """Reload the raw data from file or URL."""
568 620 if self.embed:
569 621 super(Image,self).reload()
622 if self.retina:
623 self._retina_shape()
570 624
571 625 def _repr_html_(self):
572 626 if not self.embed:
573 627 width = height = ''
574 628 if self.width:
575 629 width = ' width="%d"' % self.width
576 630 if self.height:
577 631 height = ' height="%d"' % self.height
578 632 return u'<img src="%s"%s%s/>' % (self.url, width, height)
579 633
580 634 def _data_and_metadata(self):
581 635 """shortcut for returning metadata with shape information, if defined"""
582 636 md = {}
583 637 if self.width:
584 638 md['width'] = self.width
585 639 if self.height:
586 640 md['height'] = self.height
587 641 if md:
588 642 return self.data, md
589 643 else:
590 644 return self.data
591 645
592 646 def _repr_png_(self):
593 647 if self.embed and self.format == u'png':
594 648 return self._data_and_metadata()
595 649
596 650 def _repr_jpeg_(self):
597 651 if self.embed and (self.format == u'jpeg' or self.format == u'jpg'):
598 652 return self._data_and_metadata()
599 653
600 654 def _find_ext(self, s):
601 655 return unicode(s.split('.')[-1].lower())
602 656
603 657
604 658 def clear_output(stdout=True, stderr=True, other=True):
605 659 """Clear the output of the current cell receiving output.
606 660
607 661 Optionally, each of stdout/stderr or other non-stream data (e.g. anything
608 662 produced by display()) can be excluded from the clear event.
609 663
610 664 By default, everything is cleared.
611 665
612 666 Parameters
613 667 ----------
614 668 stdout : bool [default: True]
615 669 Whether to clear stdout.
616 670 stderr : bool [default: True]
617 671 Whether to clear stderr.
618 672 other : bool [default: True]
619 673 Whether to clear everything else that is not stdout/stderr
620 674 (e.g. figures,images,HTML, any result of display()).
621 675 """
622 676 from IPython.core.interactiveshell import InteractiveShell
623 677 if InteractiveShell.initialized():
624 678 InteractiveShell.instance().display_pub.clear_output(
625 679 stdout=stdout, stderr=stderr, other=other,
626 680 )
627 681 else:
628 682 from IPython.utils import io
629 683 if stdout:
630 684 print('\033[2K\r', file=io.stdout, end='')
631 685 io.stdout.flush()
632 686 if stderr:
633 687 print('\033[2K\r', file=io.stderr, end='')
634 688 io.stderr.flush()
635 689
@@ -1,391 +1,385 b''
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
11 11 #-----------------------------------------------------------------------------
12 # Copyright (C) 2009-2011 The IPython Development Team
12 # Copyright (C) 2009 The IPython Development Team
13 13 #
14 14 # Distributed under the terms of the BSD License. The full license is in
15 15 # the file COPYING, distributed as part of this software.
16 16 #-----------------------------------------------------------------------------
17 17
18 18 #-----------------------------------------------------------------------------
19 19 # Imports
20 20 #-----------------------------------------------------------------------------
21 21
22 import struct
23 22 import sys
24 23 from io import BytesIO
25 24
25 from IPython.core.display import _pngxy
26 26 from IPython.utils.decorators import flag_calls
27 27
28 28 # If user specifies a GUI, that dictates the backend, otherwise we read the
29 29 # user's mpl default from the mpl rc structure
30 30 backends = {'tk': 'TkAgg',
31 31 'gtk': 'GTKAgg',
32 32 'wx': 'WXAgg',
33 33 'qt': 'Qt4Agg', # qt3 not supported
34 34 'qt4': 'Qt4Agg',
35 35 'osx': 'MacOSX',
36 36 'inline' : 'module://IPython.kernel.zmq.pylab.backend_inline'}
37 37
38 38 # We also need a reverse backends2guis mapping that will properly choose which
39 39 # GUI support to activate based on the desired matplotlib backend. For the
40 40 # most part it's just a reverse of the above dict, but we also need to add a
41 41 # few others that map to the same GUI manually:
42 42 backend2gui = dict(zip(backends.values(), backends.keys()))
43 43 # In the reverse mapping, there are a few extra valid matplotlib backends that
44 44 # map to the same GUI support
45 45 backend2gui['GTK'] = backend2gui['GTKCairo'] = 'gtk'
46 46 backend2gui['WX'] = 'wx'
47 47 backend2gui['CocoaAgg'] = 'osx'
48 48
49 49 #-----------------------------------------------------------------------------
50 50 # Matplotlib utilities
51 51 #-----------------------------------------------------------------------------
52 52
53 53
54 54 def getfigs(*fig_nums):
55 55 """Get a list of matplotlib figures by figure numbers.
56 56
57 57 If no arguments are given, all available figures are returned. If the
58 58 argument list contains references to invalid figures, a warning is printed
59 59 but the function continues pasting further figures.
60 60
61 61 Parameters
62 62 ----------
63 63 figs : tuple
64 64 A tuple of ints giving the figure numbers of the figures to return.
65 65 """
66 66 from matplotlib._pylab_helpers import Gcf
67 67 if not fig_nums:
68 68 fig_managers = Gcf.get_all_fig_managers()
69 69 return [fm.canvas.figure for fm in fig_managers]
70 70 else:
71 71 figs = []
72 72 for num in fig_nums:
73 73 f = Gcf.figs.get(num)
74 74 if f is None:
75 75 print('Warning: figure %s not available.' % num)
76 76 else:
77 77 figs.append(f.canvas.figure)
78 78 return figs
79 79
80 80
81 81 def figsize(sizex, sizey):
82 82 """Set the default figure size to be [sizex, sizey].
83 83
84 84 This is just an easy to remember, convenience wrapper that sets::
85 85
86 86 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
87 87 """
88 88 import matplotlib
89 89 matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
90 90
91 91
92 92 def print_figure(fig, fmt='png'):
93 93 """Convert a figure to svg or png for inline display."""
94 94 from matplotlib import rcParams
95 95 # When there's an empty figure, we shouldn't return anything, otherwise we
96 96 # get big blank areas in the qt console.
97 97 if not fig.axes and not fig.lines:
98 98 return
99 99
100 100 fc = fig.get_facecolor()
101 101 ec = fig.get_edgecolor()
102 102 bytes_io = BytesIO()
103 103 dpi = rcParams['savefig.dpi']
104 104 if fmt == 'retina':
105 105 dpi = dpi * 2
106 fmt = 'png'
106 107 fig.canvas.print_figure(bytes_io, format=fmt, bbox_inches='tight',
107 108 facecolor=fc, edgecolor=ec, dpi=dpi)
108 109 data = bytes_io.getvalue()
109 110 return data
110 111
111 def pngxy(data):
112 """read the width/height from a PNG header"""
113 ihdr = data.index(b'IHDR')
114 # next 8 bytes are width/height
115 w4h4 = data[ihdr+4:ihdr+12]
116 return struct.unpack('>ii', w4h4)
117
118 112 def retina_figure(fig):
119 113 """format a figure as a pixel-doubled (retina) PNG"""
120 114 pngdata = print_figure(fig, fmt='retina')
121 w, h = pngxy(pngdata)
115 w, h = _pngxy(pngdata)
122 116 metadata = dict(width=w//2, height=h//2)
123 117 return pngdata, metadata
124 118
125 119 # We need a little factory function here to create the closure where
126 120 # safe_execfile can live.
127 121 def mpl_runner(safe_execfile):
128 122 """Factory to return a matplotlib-enabled runner for %run.
129 123
130 124 Parameters
131 125 ----------
132 126 safe_execfile : function
133 127 This must be a function with the same interface as the
134 128 :meth:`safe_execfile` method of IPython.
135 129
136 130 Returns
137 131 -------
138 132 A function suitable for use as the ``runner`` argument of the %run magic
139 133 function.
140 134 """
141 135
142 136 def mpl_execfile(fname,*where,**kw):
143 137 """matplotlib-aware wrapper around safe_execfile.
144 138
145 139 Its interface is identical to that of the :func:`execfile` builtin.
146 140
147 141 This is ultimately a call to execfile(), but wrapped in safeties to
148 142 properly handle interactive rendering."""
149 143
150 144 import matplotlib
151 145 import matplotlib.pylab as pylab
152 146
153 147 #print '*** Matplotlib runner ***' # dbg
154 148 # turn off rendering until end of script
155 149 is_interactive = matplotlib.rcParams['interactive']
156 150 matplotlib.interactive(False)
157 151 safe_execfile(fname,*where,**kw)
158 152 matplotlib.interactive(is_interactive)
159 153 # make rendering call now, if the user tried to do it
160 154 if pylab.draw_if_interactive.called:
161 155 pylab.draw()
162 156 pylab.draw_if_interactive.called = False
163 157
164 158 return mpl_execfile
165 159
166 160
167 161 def select_figure_format(shell, fmt):
168 162 """Select figure format for inline backend, can be 'png', 'retina', or 'svg'.
169 163
170 164 Using this method ensures only one figure format is active at a time.
171 165 """
172 166 from matplotlib.figure import Figure
173 167 from IPython.kernel.zmq.pylab import backend_inline
174 168
175 169 svg_formatter = shell.display_formatter.formatters['image/svg+xml']
176 170 png_formatter = shell.display_formatter.formatters['image/png']
177 171
178 172 if fmt == 'png':
179 173 svg_formatter.type_printers.pop(Figure, None)
180 174 png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png'))
181 175 elif fmt in ('png2x', 'retina'):
182 176 svg_formatter.type_printers.pop(Figure, None)
183 177 png_formatter.for_type(Figure, retina_figure)
184 178 elif fmt == 'svg':
185 179 png_formatter.type_printers.pop(Figure, None)
186 180 svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg'))
187 181 else:
188 182 raise ValueError("supported formats are: 'png', 'retina', 'svg', not %r" % fmt)
189 183
190 184 # set the format to be used in the backend()
191 185 backend_inline._figure_format = fmt
192 186
193 187 #-----------------------------------------------------------------------------
194 188 # Code for initializing matplotlib and importing pylab
195 189 #-----------------------------------------------------------------------------
196 190
197 191
198 192 def find_gui_and_backend(gui=None, gui_select=None):
199 193 """Given a gui string return the gui and mpl backend.
200 194
201 195 Parameters
202 196 ----------
203 197 gui : str
204 198 Can be one of ('tk','gtk','wx','qt','qt4','inline').
205 199 gui_select : str
206 200 Can be one of ('tk','gtk','wx','qt','qt4','inline').
207 201 This is any gui already selected by the shell.
208 202
209 203 Returns
210 204 -------
211 205 A tuple of (gui, backend) where backend is one of ('TkAgg','GTKAgg',
212 206 'WXAgg','Qt4Agg','module://IPython.kernel.zmq.pylab.backend_inline').
213 207 """
214 208
215 209 import matplotlib
216 210
217 211 if gui and gui != 'auto':
218 212 # select backend based on requested gui
219 213 backend = backends[gui]
220 214 else:
221 215 backend = matplotlib.rcParams['backend']
222 216 # In this case, we need to find what the appropriate gui selection call
223 217 # should be for IPython, so we can activate inputhook accordingly
224 218 gui = backend2gui.get(backend, None)
225 219
226 220 # If we have already had a gui active, we need it and inline are the
227 221 # ones allowed.
228 222 if gui_select and gui != gui_select:
229 223 gui = gui_select
230 224 backend = backends[gui]
231 225
232 226 return gui, backend
233 227
234 228
235 229 def activate_matplotlib(backend):
236 230 """Activate the given backend and set interactive to True."""
237 231
238 232 import matplotlib
239 233 matplotlib.interactive(True)
240 234
241 235 # Matplotlib had a bug where even switch_backend could not force
242 236 # the rcParam to update. This needs to be set *before* the module
243 237 # magic of switch_backend().
244 238 matplotlib.rcParams['backend'] = backend
245 239
246 240 import matplotlib.pyplot
247 241 matplotlib.pyplot.switch_backend(backend)
248 242
249 243 # This must be imported last in the matplotlib series, after
250 244 # backend/interactivity choices have been made
251 245 import matplotlib.pylab as pylab
252 246
253 247 pylab.show._needmain = False
254 248 # We need to detect at runtime whether show() is called by the user.
255 249 # For this, we wrap it into a decorator which adds a 'called' flag.
256 250 pylab.draw_if_interactive = flag_calls(pylab.draw_if_interactive)
257 251
258 252
259 253 def import_pylab(user_ns, import_all=True):
260 254 """Import the standard pylab symbols into user_ns."""
261 255
262 256 # Import numpy as np/pyplot as plt are conventions we're trying to
263 257 # somewhat standardize on. Making them available to users by default
264 258 # will greatly help this.
265 259 s = ("import numpy\n"
266 260 "import matplotlib\n"
267 261 "from matplotlib import pylab, mlab, pyplot\n"
268 262 "np = numpy\n"
269 263 "plt = pyplot\n"
270 264 )
271 265 exec s in user_ns
272 266
273 267 if import_all:
274 268 s = ("from matplotlib.pylab import *\n"
275 269 "from numpy import *\n")
276 270 exec s in user_ns
277 271
278 272
279 273 def configure_inline_support(shell, backend, user_ns=None):
280 274 """Configure an IPython shell object for matplotlib use.
281 275
282 276 Parameters
283 277 ----------
284 278 shell : InteractiveShell instance
285 279
286 280 backend : matplotlib backend
287 281
288 282 user_ns : dict
289 283 A namespace where all configured variables will be placed. If not given,
290 284 the `user_ns` attribute of the shell object is used.
291 285 """
292 286 # If using our svg payload backend, register the post-execution
293 287 # function that will pick up the results for display. This can only be
294 288 # done with access to the real shell object.
295 289
296 290 # Note: if we can't load the inline backend, then there's no point
297 291 # continuing (such as in terminal-only shells in environments without
298 292 # zeromq available).
299 293 try:
300 294 from IPython.kernel.zmq.pylab.backend_inline import InlineBackend
301 295 except ImportError:
302 296 return
303 297 from matplotlib import pyplot
304 298
305 299 user_ns = shell.user_ns if user_ns is None else user_ns
306 300
307 301 cfg = InlineBackend.instance(config=shell.config)
308 302 cfg.shell = shell
309 303 if cfg not in shell.configurables:
310 304 shell.configurables.append(cfg)
311 305
312 306 if backend == backends['inline']:
313 307 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
314 308 shell.register_post_execute(flush_figures)
315 309
316 310 # Save rcParams that will be overwrittern
317 311 shell._saved_rcParams = dict()
318 312 for k in cfg.rc:
319 313 shell._saved_rcParams[k] = pyplot.rcParams[k]
320 314 # load inline_rc
321 315 pyplot.rcParams.update(cfg.rc)
322 316 # Add 'figsize' to pyplot and to the user's namespace
323 317 user_ns['figsize'] = pyplot.figsize = figsize
324 318 else:
325 319 from IPython.kernel.zmq.pylab.backend_inline import flush_figures
326 320 if flush_figures in shell._post_execute:
327 321 shell._post_execute.pop(flush_figures)
328 322 if hasattr(shell, '_saved_rcParams'):
329 323 pyplot.rcParams.update(shell._saved_rcParams)
330 324 del shell._saved_rcParams
331 325
332 326 # Setup the default figure format
333 327 fmt = cfg.figure_format
334 328 select_figure_format(shell, fmt)
335 329
336 330 # The old pastefig function has been replaced by display
337 331 from IPython.core.display import display
338 332 # Add display and getfigs to the user's namespace
339 333 user_ns['display'] = display
340 334 user_ns['getfigs'] = getfigs
341 335
342 336
343 337 def pylab_activate(user_ns, gui=None, import_all=True, shell=None, welcome_message=False):
344 338 """Activate pylab mode in the user's namespace.
345 339
346 340 Loads and initializes numpy, matplotlib and friends for interactive use.
347 341
348 342 Parameters
349 343 ----------
350 344 user_ns : dict
351 345 Namespace where the imports will occur.
352 346
353 347 gui : optional, string
354 348 A valid gui name following the conventions of the %gui magic.
355 349
356 350 import_all : optional, boolean
357 351 If true, an 'import *' is done from numpy and pylab.
358 352
359 353 welcome_message : optional, boolean
360 354 If true, print a welcome message about pylab, which includes the backend
361 355 being used.
362 356
363 357 Returns
364 358 -------
365 359 The actual gui used (if not given as input, it was obtained from matplotlib
366 360 itself, and will be needed next to configure IPython's gui integration.
367 361 """
368 362 pylab_gui_select = shell.pylab_gui_select if shell is not None else None
369 363 # Try to find the appropriate gui and backend for the settings
370 364 gui, backend = find_gui_and_backend(gui, pylab_gui_select)
371 365 if shell is not None and gui != 'inline':
372 366 # If we have our first gui selection, store it
373 367 if pylab_gui_select is None:
374 368 shell.pylab_gui_select = gui
375 369 # Otherwise if they are different
376 370 elif gui != pylab_gui_select:
377 371 print ('Warning: Cannot change to a different GUI toolkit: %s.'
378 372 ' Using %s instead.' % (gui, pylab_gui_select))
379 373 gui, backend = find_gui_and_backend(pylab_gui_select)
380 374 activate_matplotlib(backend)
381 375 import_pylab(user_ns, import_all)
382 376 if shell is not None:
383 377 configure_inline_support(shell, backend, user_ns)
384 378 if welcome_message:
385 379 print """
386 380 Welcome to pylab, a matplotlib-based Python environment [backend: %s].
387 381 For more information, type 'help(pylab)'.""" % backend
388 382 # flush stdout, just to be safe
389 383 sys.stdout.flush()
390 384
391 385 return gui
General Comments 0
You need to be logged in to leave comments. Login now