Show More
@@ -24,7 +24,7 b' 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 | #----------------------------------------------------------------------------- |
@@ -271,6 +271,24 b' def display_javascript(*objs, **kwargs):' | |||
|
271 | 271 | """ |
|
272 | 272 | _display_mimetype('application/javascript', objs, **kwargs) |
|
273 | 273 | |
|
274 | ||
|
275 | def display_pdf(*objs, **kwargs): | |
|
276 | """Display the PDF representation of an object. | |
|
277 | ||
|
278 | Parameters | |
|
279 | ---------- | |
|
280 | objs : tuple of objects | |
|
281 | The Python objects to display, or if raw=True raw javascript data to | |
|
282 | display. | |
|
283 | raw : bool | |
|
284 | Are the data objects raw data or Python objects that need to be | |
|
285 | formatted before display? [default: False] | |
|
286 | metadata : dict (optional) | |
|
287 | Metadata to be associated with the specific mimetype output. | |
|
288 | """ | |
|
289 | _display_mimetype('application/pdf', objs, **kwargs) | |
|
290 | ||
|
291 | ||
|
274 | 292 | #----------------------------------------------------------------------------- |
|
275 | 293 | # Smart classes |
|
276 | 294 | #----------------------------------------------------------------------------- |
@@ -699,3 +717,56 b' def clear_output(wait=False):' | |||
|
699 | 717 | io.stdout.flush() |
|
700 | 718 | print('\033[2K\r', file=io.stderr, end='') |
|
701 | 719 | io.stderr.flush() |
|
720 | ||
|
721 | ||
|
722 | @skip_doctest | |
|
723 | def set_matplotlib_formats(*formats, **kwargs): | |
|
724 | """Select figure formats for the inline backend. Optionally pass quality for JPEG. | |
|
725 | ||
|
726 | For example, this enables PNG and JPEG output with a JPEG quality of 90%:: | |
|
727 | ||
|
728 | In [1]: set_matplotlib_formats('png', 'jpeg', quality=90) | |
|
729 | ||
|
730 | To set this in your config files use the following:: | |
|
731 | ||
|
732 | c.InlineBackend.figure_formats = {'pdf', 'png', 'svg'} | |
|
733 | c.InlineBackend.quality = 90 | |
|
734 | ||
|
735 | Parameters | |
|
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. | |
|
741 | """ | |
|
742 | from IPython.core.interactiveshell import InteractiveShell | |
|
743 | from IPython.core.pylabtools import select_figure_formats | |
|
744 | shell = InteractiveShell.instance() | |
|
745 | select_figure_formats(shell, formats, quality=90) | |
|
746 | ||
|
747 | @skip_doctest | |
|
748 | def set_matplotlib_close(close): | |
|
749 | """Set whether the inline backend closes all figures automatically or not. | |
|
750 | ||
|
751 | By default, the inline backend used in the IPython Notebook will close all | |
|
752 | matplotlib figures automatically after each cell is run. This means that | |
|
753 | plots in different cells won't interfere. Sometimes, you may want to make | |
|
754 | a plot in one cell and then refine it in later cells. This can be accomplished | |
|
755 | by:: | |
|
756 | ||
|
757 | In [1]: set_matplotlib_close(False) | |
|
758 | ||
|
759 | To set this in your config files use the following:: | |
|
760 | ||
|
761 | c.InlineBackend.close_figures = False | |
|
762 | ||
|
763 | Parameters | |
|
764 | ---------- | |
|
765 | close : bool | |
|
766 | Should all matplotlib figures be automatically closed after each cell is | |
|
767 | run? | |
|
768 | """ | |
|
769 | from IPython.kernel.zmq.pylab.backend_inline import InlineBackend | |
|
770 | ilbe = InlineBackend.instance() | |
|
771 | ilbe.close_figures = close | |
|
772 |
@@ -93,6 +93,7 b' class DisplayFormatter(Configurable):' | |||
|
93 | 93 | HTMLFormatter, |
|
94 | 94 | SVGFormatter, |
|
95 | 95 | PNGFormatter, |
|
96 | PDFFormatter, | |
|
96 | 97 | JPEGFormatter, |
|
97 | 98 | LatexFormatter, |
|
98 | 99 | JSONFormatter, |
@@ -116,6 +117,7 b' class DisplayFormatter(Configurable):' | |||
|
116 | 117 | * text/latex |
|
117 | 118 | * application/json |
|
118 | 119 | * application/javascript |
|
120 | * application/pdf | |
|
119 | 121 | * image/png |
|
120 | 122 | * image/jpeg |
|
121 | 123 | * image/svg+xml |
@@ -766,11 +768,29 b' class JavascriptFormatter(BaseFormatter):' | |||
|
766 | 768 | |
|
767 | 769 | print_method = ObjectName('_repr_javascript_') |
|
768 | 770 | |
|
771 | ||
|
772 | class PDFFormatter(BaseFormatter): | |
|
773 | """A PDF formatter. | |
|
774 | ||
|
775 | To defined the callables that compute to PDF representation of your | |
|
776 | objects, define a :meth:`_repr_pdf_` method or use the :meth:`for_type` | |
|
777 | or :meth:`for_type_by_name` methods to register functions that handle | |
|
778 | this. | |
|
779 | ||
|
780 | The return value of this formatter should be raw PDF data, *not* | |
|
781 | base64 encoded. | |
|
782 | """ | |
|
783 | format_type = Unicode('application/pdf') | |
|
784 | ||
|
785 | print_method = ObjectName('_repr_pdf_') | |
|
786 | ||
|
787 | ||
|
769 | 788 | FormatterABC.register(BaseFormatter) |
|
770 | 789 | FormatterABC.register(PlainTextFormatter) |
|
771 | 790 | FormatterABC.register(HTMLFormatter) |
|
772 | 791 | FormatterABC.register(SVGFormatter) |
|
773 | 792 | FormatterABC.register(PNGFormatter) |
|
793 | FormatterABC.register(PDFFormatter) | |
|
774 | 794 | FormatterABC.register(JPEGFormatter) |
|
775 | 795 | FormatterABC.register(LatexFormatter) |
|
776 | 796 | FormatterABC.register(JSONFormatter) |
@@ -789,6 +809,7 b' def format_display_data(obj, include=None, exclude=None):' | |||
|
789 | 809 | * text/latex |
|
790 | 810 | * application/json |
|
791 | 811 | * application/javascript |
|
812 | * application/pdf | |
|
792 | 813 | * image/png |
|
793 | 814 | * image/jpeg |
|
794 | 815 | * image/svg+xml |
@@ -47,28 +47,32 b' class PylabMagics(Magics):' | |||
|
47 | 47 | """Set up matplotlib to work interactively. |
|
48 | 48 | |
|
49 | 49 | This function lets you activate matplotlib interactive support |
|
50 | at any point during an IPython session. | |
|
51 |
|
|
|
50 | at any point during an IPython session. It does not import anything | |
|
51 | into the interactive namespace. | |
|
52 | 52 | |
|
53 |
If you are using the inline matplotlib backend |
|
|
54 | you can adjust its behavior via the %config magic:: | |
|
55 | ||
|
56 | # enable SVG figures, necessary for SVG+XHTML export in the qtconsole | |
|
57 | In [1]: %config InlineBackend.figure_format = 'svg' | |
|
53 | If you are using the inline matplotlib backend in the IPython Notebook | |
|
54 | you can set which figure formats are enabled using the following:: | |
|
55 | ||
|
56 | In [1]: from IPython.display import set_matplotlib_formats | |
|
57 | ||
|
58 | In [2]: set_matplotlib_formats('pdf', 'svg') | |
|
58 | 59 | |
|
59 | # change the behavior of closing all figures at the end of each | |
|
60 | # execution (cell), or allowing reuse of active figures across | |
|
61 | # cells: | |
|
62 | In [2]: %config InlineBackend.close_figures = False | |
|
60 | See the docstring of `IPython.display.set_matplotlib_formats` and | |
|
61 | `IPython.display.set_matplotlib_close` for more information on | |
|
62 | changing the behavior of the inline backend. | |
|
63 | 63 | |
|
64 | 64 | Examples |
|
65 | 65 | -------- |
|
66 | In this case, where the MPL default is TkAgg:: | |
|
66 | To enable the inline backend for usage with the IPython Notebook:: | |
|
67 | ||
|
68 | In [1]: %matplotlib inline | |
|
69 | ||
|
70 | In this case, where the matplotlib default is TkAgg:: | |
|
67 | 71 | |
|
68 | 72 | In [2]: %matplotlib |
|
69 | 73 | Using matplotlib backend: TkAgg |
|
70 | 74 | |
|
71 | But you can explicitly request a different backend:: | |
|
75 | But you can explicitly request a different GUI backend:: | |
|
72 | 76 | |
|
73 | 77 | In [3]: %matplotlib qt |
|
74 | 78 | """ |
@@ -25,6 +25,7 b' from io import BytesIO' | |||
|
25 | 25 | |
|
26 | 26 | from IPython.core.display import _pngxy |
|
27 | 27 | from IPython.utils.decorators import flag_calls |
|
28 | from IPython.utils import py3compat | |
|
28 | 29 | |
|
29 | 30 | # If user specifies a GUI, that dictates the backend, otherwise we read the |
|
30 | 31 | # user's mpl default from the mpl rc structure |
@@ -165,10 +166,17 b' def mpl_runner(safe_execfile):' | |||
|
165 | 166 | return mpl_execfile |
|
166 | 167 | |
|
167 | 168 | |
|
168 | def select_figure_format(shell, fmt, quality=90): | |
|
169 |
"""Select figure format for inline backend |
|
|
169 | def select_figure_formats(shell, formats, quality=90): | |
|
170 | """Select figure formats for the inline backend. | |
|
170 | 171 | |
|
171 | Using this method ensures only one figure format is active at a time. | |
|
172 | Parameters | |
|
173 | ========== | |
|
174 | shell : InteractiveShell | |
|
175 | The main IPython instance. | |
|
176 | formats : list | |
|
177 | 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. | |
|
172 | 180 | """ |
|
173 | 181 | from matplotlib.figure import Figure |
|
174 | 182 | from IPython.kernel.zmq.pylab import backend_inline |
@@ -176,22 +184,26 b' def select_figure_format(shell, fmt, quality=90):' | |||
|
176 | 184 | svg_formatter = shell.display_formatter.formatters['image/svg+xml'] |
|
177 | 185 | png_formatter = shell.display_formatter.formatters['image/png'] |
|
178 | 186 | jpg_formatter = shell.display_formatter.formatters['image/jpeg'] |
|
187 | pdf_formatter = shell.display_formatter.formatters['application/pdf'] | |
|
179 | 188 | |
|
180 | [ f.type_printers.pop(Figure, None) for f in {svg_formatter, png_formatter, jpg_formatter} ] | |
|
189 | if isinstance(formats, py3compat.string_types): | |
|
190 | formats = {formats} | |
|
181 | 191 | |
|
182 | if fmt == 'png': | |
|
183 | png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png')) | |
|
184 | elif fmt in ('png2x', 'retina'): | |
|
185 | png_formatter.for_type(Figure, retina_figure) | |
|
186 | elif fmt in ('jpg', 'jpeg'): | |
|
187 | jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', quality)) | |
|
188 | elif fmt == 'svg': | |
|
189 | svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg')) | |
|
190 | else: | |
|
191 | raise ValueError("supported formats are: 'png', 'retina', 'svg', 'jpg', not %r" % fmt) | |
|
192 | [ f.type_printers.pop(Figure, None) for f in {svg_formatter, png_formatter, jpg_formatter} ] | |
|
192 | 193 | |
|
193 | # set the format to be used in the backend() | |
|
194 | backend_inline._figure_format = fmt | |
|
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) | |
|
195 | 207 | |
|
196 | 208 | #----------------------------------------------------------------------------- |
|
197 | 209 | # Code for initializing matplotlib and importing pylab |
@@ -342,5 +354,5 b' def configure_inline_support(shell, backend):' | |||
|
342 | 354 | del shell._saved_rcParams |
|
343 | 355 | |
|
344 | 356 | # Setup the default figure format |
|
345 | select_figure_format(shell, cfg.figure_format, cfg.quality) | |
|
357 | select_figure_formats(shell, cfg.figure_formats, cfg.quality) | |
|
346 | 358 |
@@ -8,7 +8,9 b' except:' | |||
|
8 | 8 | numpy = None |
|
9 | 9 | import nose.tools as nt |
|
10 | 10 | |
|
11 | from IPython.core.formatters import PlainTextFormatter, HTMLFormatter, _mod_name_key | |
|
11 | from IPython.core.formatters import ( | |
|
12 | PlainTextFormatter, HTMLFormatter, PDFFormatter, _mod_name_key | |
|
13 | ) | |
|
12 | 14 | from IPython.utils.io import capture_output |
|
13 | 15 | |
|
14 | 16 | class A(object): |
@@ -279,4 +281,11 b' def test_warn_error_pretty_method():' | |||
|
279 | 281 | nt.assert_in("text/plain", captured.stderr) |
|
280 | 282 | nt.assert_in("argument", captured.stderr) |
|
281 | 283 | |
|
284 | class MakePDF(object): | |
|
285 | def _repr_pdf_(self): | |
|
286 | return 'PDF' | |
|
282 | 287 | |
|
288 | def test_pdf_formatter(): | |
|
289 | pdf = MakePDF() | |
|
290 | f = PDFFormatter() | |
|
291 | nt.assert_equal(f(pdf), 'PDF') |
@@ -252,6 +252,7 b' var IPython = (function (IPython) {' | |||
|
252 | 252 | 'image/svg+xml', |
|
253 | 253 | 'image/png', |
|
254 | 254 | 'image/jpeg', |
|
255 | 'application/pdf', | |
|
255 | 256 | 'text/plain' |
|
256 | 257 | ]; |
|
257 | 258 | |
@@ -620,6 +621,17 b' var IPython = (function (IPython) {' | |||
|
620 | 621 | }; |
|
621 | 622 | |
|
622 | 623 | |
|
624 | OutputArea.prototype.append_pdf = function (pdf, md, element) { | |
|
625 | var type = 'application/pdf'; | |
|
626 | var toinsert = this.create_output_subarea(md, "output_pdf", type); | |
|
627 | var a = $('<a/>').attr('href', 'data:application/pdf;base64,'+pdf); | |
|
628 | a.attr('target', '_blank'); | |
|
629 | a.text('View PDF') | |
|
630 | toinsert.append(a); | |
|
631 | element.append(toinsert); | |
|
632 | return toinsert; | |
|
633 | } | |
|
634 | ||
|
623 | 635 | OutputArea.prototype.append_latex = function (latex, md, element) { |
|
624 | 636 | // This method cannot do the typesetting because the latex first has to |
|
625 | 637 | // be on the page. |
@@ -807,6 +819,7 b' var IPython = (function (IPython) {' | |||
|
807 | 819 | "image/svg+xml" : "svg", |
|
808 | 820 | "image/png" : "png", |
|
809 | 821 | "image/jpeg" : "jpeg", |
|
822 | "application/pdf" : "pdf", | |
|
810 | 823 | "text/latex" : "latex", |
|
811 | 824 | "application/json" : "json", |
|
812 | 825 | "application/javascript" : "javascript", |
@@ -818,6 +831,7 b' var IPython = (function (IPython) {' | |||
|
818 | 831 | "svg" : "image/svg+xml", |
|
819 | 832 | "png" : "image/png", |
|
820 | 833 | "jpeg" : "image/jpeg", |
|
834 | "pdf" : "application/pdf", | |
|
821 | 835 | "latex" : "text/latex", |
|
822 | 836 | "json" : "application/json", |
|
823 | 837 | "javascript" : "application/javascript", |
@@ -830,6 +844,7 b' var IPython = (function (IPython) {' | |||
|
830 | 844 | 'image/svg+xml', |
|
831 | 845 | 'image/png', |
|
832 | 846 | 'image/jpeg', |
|
847 | 'application/pdf', | |
|
833 | 848 | 'text/plain' |
|
834 | 849 | ]; |
|
835 | 850 | |
@@ -842,6 +857,7 b' var IPython = (function (IPython) {' | |||
|
842 | 857 | "text/latex" : OutputArea.prototype.append_latex, |
|
843 | 858 | "application/json" : OutputArea.prototype.append_json, |
|
844 | 859 | "application/javascript" : OutputArea.prototype.append_javascript, |
|
860 | "application/pdf" : OutputArea.prototype.append_pdf | |
|
845 | 861 | }; |
|
846 | 862 | |
|
847 | 863 | IPython.OutputArea = OutputArea; |
@@ -14,7 +14,9 b' This module does not import anything from matplotlib.' | |||
|
14 | 14 | #----------------------------------------------------------------------------- |
|
15 | 15 | |
|
16 | 16 | from IPython.config.configurable import SingletonConfigurable |
|
17 | from IPython.utils.traitlets import Dict, Instance, CaselessStrEnum, Bool, Int, TraitError | |
|
17 | from IPython.utils.traitlets import ( | |
|
18 | Dict, Instance, CaselessStrEnum, Set, Bool, Int, TraitError, Unicode | |
|
19 | ) | |
|
18 | 20 | from IPython.utils.warn import warn |
|
19 | 21 | |
|
20 | 22 | #----------------------------------------------------------------------------- |
@@ -63,21 +65,26 b' class InlineBackend(InlineBackendConfig):' | |||
|
63 | 65 | inline backend.""" |
|
64 | 66 | ) |
|
65 | 67 | |
|
68 | figure_formats = Set({'png'}, config=True, | |
|
69 | help="""A set of figure formats to enable: 'png', | |
|
70 | 'retina', 'jpeg', 'svg', 'pdf'.""") | |
|
66 | 71 | |
|
67 | figure_format = CaselessStrEnum(['svg', 'png', 'retina', 'jpg'], | |
|
68 | default_value='png', config=True, | |
|
69 | help="""The image format for figures with the inline | |
|
70 | backend. JPEG requires the PIL/Pillow library.""") | |
|
71 | ||
|
72 | def _figure_format_changed(self, name, old, new): | |
|
73 | from IPython.core.pylabtools import select_figure_format | |
|
74 | if new in {"jpg", "jpeg"}: | |
|
72 | def _figure_formats_changed(self, name, old, new): | |
|
73 | from IPython.core.pylabtools import select_figure_formats | |
|
74 | if 'jpg' in new or 'jpeg' in new: | |
|
75 | 75 | if not pil_available(): |
|
76 | 76 | raise TraitError("Requires PIL/Pillow for JPG figures") |
|
77 | 77 | if self.shell is None: |
|
78 | 78 | return |
|
79 | 79 | else: |
|
80 | select_figure_format(self.shell, new) | |
|
80 | select_figure_formats(self.shell, new) | |
|
81 | ||
|
82 | figure_format = Unicode(config=True, help="""The figure format to enable (deprecated | |
|
83 | use `figure_formats` instead)""") | |
|
84 | ||
|
85 | def _figure_format_changed(self, name, old, new): | |
|
86 | if new: | |
|
87 | self.figure_formats = {new} | |
|
81 | 88 | |
|
82 | 89 | quality = Int(default_value=90, config=True, |
|
83 | 90 | help="Quality of compression [10-100], currently for lossy JPEG only.") |
@@ -119,6 +119,8 b" PNG64 = b'iVBORw0KG'" | |||
|
119 | 119 | JPEG = b'\xff\xd8' |
|
120 | 120 | # front of JPEG base64-encoded |
|
121 | 121 | JPEG64 = b'/9' |
|
122 | # front of PDF base64-encoded | |
|
123 | PDF64 = b'JVBER' | |
|
122 | 124 | |
|
123 | 125 | def encode_images(format_dict): |
|
124 | 126 | """b64-encodes images in a displaypub format dict |
@@ -136,7 +138,7 b' def encode_images(format_dict):' | |||
|
136 | 138 | |
|
137 | 139 | format_dict : dict |
|
138 | 140 | A copy of the same dictionary, |
|
139 |
but binary image data ('image/png' |
|
|
141 | but binary image data ('image/png', 'image/jpeg' or 'application/pdf') | |
|
140 | 142 | is base64-encoded. |
|
141 | 143 | |
|
142 | 144 | """ |
@@ -156,6 +158,13 b' def encode_images(format_dict):' | |||
|
156 | 158 | jpegdata = encodebytes(jpegdata) |
|
157 | 159 | encoded['image/jpeg'] = jpegdata.decode('ascii') |
|
158 | 160 | |
|
161 | pdfdata = format_dict.get('application/pdf') | |
|
162 | if isinstance(pdfdata, bytes): | |
|
163 | # make sure we don't double-encode | |
|
164 | if not pdfdata.startswith(PDF64): | |
|
165 | pdfdata = encodebytes(pdfdata) | |
|
166 | encoded['application/pdf'] = pdfdata.decode('ascii') | |
|
167 | ||
|
159 | 168 | return encoded |
|
160 | 169 | |
|
161 | 170 |
@@ -69,10 +69,12 b' def test_encode_images():' | |||
|
69 | 69 | # invalid data, but the header and footer are from real files |
|
70 | 70 | pngdata = b'\x89PNG\r\n\x1a\nblahblahnotactuallyvalidIEND\xaeB`\x82' |
|
71 | 71 | jpegdata = b'\xff\xd8\xff\xe0\x00\x10JFIFblahblahjpeg(\xa0\x0f\xff\xd9' |
|
72 | pdfdata = b'%PDF-1.\ntrailer<</Root<</Pages<</Kids[<</MediaBox[0 0 3 3]>>]>>>>>>' | |
|
72 | 73 | |
|
73 | 74 | fmt = { |
|
74 | 75 | 'image/png' : pngdata, |
|
75 | 76 | 'image/jpeg' : jpegdata, |
|
77 | 'application/pdf' : pdfdata | |
|
76 | 78 | } |
|
77 | 79 | encoded = encode_images(fmt) |
|
78 | 80 | for key, value in iteritems(fmt): |
General Comments 0
You need to be logged in to leave comments.
Login now