##// END OF EJS Templates
Embed LaTeX output from pyout into equation* environment
jakobgager -
Show More
@@ -1,198 +1,198 b''
1 from converters.base import Converter
1 from converters.base import Converter
2 from converters.utils import markdown2latex, remove_ansi
2 from converters.utils import markdown2latex, remove_ansi
3 import os
3 import os
4 import subprocess
4 import subprocess
5 import sys
5 import sys
6
6
7 inkscape = 'inkscape'
7 inkscape = 'inkscape'
8 if sys.platform == 'darwin':
8 if sys.platform == 'darwin':
9 inkscape = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
9 inkscape = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
10 if not os.path.exists(inkscape):
10 if not os.path.exists(inkscape):
11 inkscape = None
11 inkscape = None
12
12
13
13
14 class ConverterLaTeX(Converter):
14 class ConverterLaTeX(Converter):
15 """Converts a notebook to a .tex file suitable for pdflatex.
15 """Converts a notebook to a .tex file suitable for pdflatex.
16
16
17 Note: this converter *needs*:
17 Note: this converter *needs*:
18
18
19 - `pandoc`: for all conversion of markdown cells. If your notebook only
19 - `pandoc`: for all conversion of markdown cells. If your notebook only
20 has Raw cells, pandoc will not be needed.
20 has Raw cells, pandoc will not be needed.
21
21
22 - `inkscape`: if your notebook has SVG figures. These need to be
22 - `inkscape`: if your notebook has SVG figures. These need to be
23 converted to PDF before inclusion in the TeX file, as LaTeX doesn't
23 converted to PDF before inclusion in the TeX file, as LaTeX doesn't
24 understand SVG natively.
24 understand SVG natively.
25
25
26 You will in general obtain much better final PDF results if you configure
26 You will in general obtain much better final PDF results if you configure
27 the matplotlib backend to create SVG output with
27 the matplotlib backend to create SVG output with
28
28
29 %config InlineBackend.figure_format = 'svg'
29 %config InlineBackend.figure_format = 'svg'
30
30
31 (or set the equivalent flag at startup or in your configuration profile).
31 (or set the equivalent flag at startup or in your configuration profile).
32 """
32 """
33 inkscape = inkscape
33 inkscape = inkscape
34 extension = 'tex'
34 extension = 'tex'
35 documentclass = 'article'
35 documentclass = 'article'
36 documentclass_options = '11pt,english'
36 documentclass_options = '11pt,english'
37 heading_map = {1: r'\section',
37 heading_map = {1: r'\section',
38 2: r'\subsection',
38 2: r'\subsection',
39 3: r'\subsubsection',
39 3: r'\subsubsection',
40 4: r'\paragraph',
40 4: r'\paragraph',
41 5: r'\subparagraph',
41 5: r'\subparagraph',
42 6: r'\subparagraph'}
42 6: r'\subparagraph'}
43 user_preamble = None
43 user_preamble = None
44 exclude_cells = []
44 exclude_cells = []
45
45
46 def in_env(self, environment, lines):
46 def in_env(self, environment, lines):
47 """Return list of environment lines for input lines
47 """Return list of environment lines for input lines
48
48
49 Parameters
49 Parameters
50 ----------
50 ----------
51 env : string
51 env : string
52 Name of the environment to bracket with begin/end.
52 Name of the environment to bracket with begin/end.
53
53
54 lines: """
54 lines: """
55 out = [ur'\begin{%s}' % environment]
55 out = [ur'\begin{%s}' % environment]
56 if isinstance(lines, basestring):
56 if isinstance(lines, basestring):
57 out.append(lines)
57 out.append(lines)
58 else: # list
58 else: # list
59 out.extend(lines)
59 out.extend(lines)
60 out.append(ur'\end{%s}' % environment)
60 out.append(ur'\end{%s}' % environment)
61 return out
61 return out
62
62
63 def convert(self, *args, **kwargs):
63 def convert(self, *args, **kwargs):
64 # The main body is done by the logic in the parent class, and that's
64 # The main body is done by the logic in the parent class, and that's
65 # all we need if preamble support has been turned off.
65 # all we need if preamble support has been turned off.
66 body = super(ConverterLaTeX, self).convert(*args, **kwargs)
66 body = super(ConverterLaTeX, self).convert(*args, **kwargs)
67 if not self.with_preamble:
67 if not self.with_preamble:
68 return body
68 return body
69 # But if preamble is on, then we need to construct a proper, standalone
69 # But if preamble is on, then we need to construct a proper, standalone
70 # tex file.
70 # tex file.
71
71
72 # Tag the document at the top and set latex class
72 # Tag the document at the top and set latex class
73 final = [r'%% This file was auto-generated by IPython, do NOT edit',
73 final = [r'%% This file was auto-generated by IPython, do NOT edit',
74 r'%% Conversion from the original notebook file:',
74 r'%% Conversion from the original notebook file:',
75 r'%% {0}'.format(self.infile),
75 r'%% {0}'.format(self.infile),
76 r'%%',
76 r'%%',
77 r'\documentclass[%s]{%s}' % (self.documentclass_options,
77 r'\documentclass[%s]{%s}' % (self.documentclass_options,
78 self.documentclass),
78 self.documentclass),
79 '',
79 '',
80 ]
80 ]
81 # Load our own preamble, which is stored next to the main file. We
81 # Load our own preamble, which is stored next to the main file. We
82 # need to be careful in case the script entry point is a symlink
82 # need to be careful in case the script entry point is a symlink
83 myfile = os.path.realpath(__file__)
83 myfile = os.path.realpath(__file__)
84 preamble = '../preamble.tex'
84 preamble = '../preamble.tex'
85 with open(os.path.join(os.path.dirname(myfile), preamble)) as f:
85 with open(os.path.join(os.path.dirname(myfile), preamble)) as f:
86 final.append(f.read())
86 final.append(f.read())
87
87
88 # Load any additional user-supplied preamble
88 # Load any additional user-supplied preamble
89 if self.user_preamble:
89 if self.user_preamble:
90 final.extend(['', '%% Adding user preamble from file:',
90 final.extend(['', '%% Adding user preamble from file:',
91 '%% {0}'.format(self.user_preamble), ''])
91 '%% {0}'.format(self.user_preamble), ''])
92 with open(self.user_preamble) as f:
92 with open(self.user_preamble) as f:
93 final.append(f.read())
93 final.append(f.read())
94
94
95 # Include document body
95 # Include document body
96 final.extend([r'\begin{document}', '',
96 final.extend([r'\begin{document}', '',
97 body,
97 body,
98 r'\end{document}', ''])
98 r'\end{document}', ''])
99 # Retun value must be a string
99 # Retun value must be a string
100 return '\n'.join(final)
100 return '\n'.join(final)
101
101
102 def render_heading(self, cell):
102 def render_heading(self, cell):
103 marker = self.heading_map[cell.level]
103 marker = self.heading_map[cell.level]
104 return ['%s{%s}' % (marker, cell.source)]
104 return ['%s{%s}' % (marker, cell.source)]
105
105
106 def render_code(self, cell):
106 def render_code(self, cell):
107 if not cell.input:
107 if not cell.input:
108 return []
108 return []
109
109
110 # Cell codes first carry input code, we use lstlisting for that
110 # Cell codes first carry input code, we use lstlisting for that
111 lines = [ur'\begin{codecell}']
111 lines = [ur'\begin{codecell}']
112
112
113 if 'source' not in self.exclude_cells:
113 if 'source' not in self.exclude_cells:
114 lines.extend(self.in_env('codeinput',
114 lines.extend(self.in_env('codeinput',
115 self.in_env('lstlisting', cell.input)))
115 self.in_env('lstlisting', cell.input)))
116 else:
116 else:
117 # Empty output is still needed for LaTeX formatting
117 # Empty output is still needed for LaTeX formatting
118 lines.extend(self.in_env('codeinput', ''))
118 lines.extend(self.in_env('codeinput', ''))
119
119
120 outlines = []
120 outlines = []
121 if 'output' not in self.exclude_cells:
121 if 'output' not in self.exclude_cells:
122 for output in cell.outputs:
122 for output in cell.outputs:
123 conv_fn = self.dispatch(output.output_type)
123 conv_fn = self.dispatch(output.output_type)
124 outlines.extend(conv_fn(output))
124 outlines.extend(conv_fn(output))
125
125
126 # And then output of many possible types; use a frame for all of it.
126 # And then output of many possible types; use a frame for all of it.
127 if outlines:
127 if outlines:
128 lines.extend(self.in_env('codeoutput', outlines))
128 lines.extend(self.in_env('codeoutput', outlines))
129
129
130 lines.append(ur'\end{codecell}')
130 lines.append(ur'\end{codecell}')
131
131
132 return lines
132 return lines
133
133
134 def _img_lines(self, img_file):
134 def _img_lines(self, img_file):
135 return self.in_env('center',
135 return self.in_env('center',
136 [r'\includegraphics[width=6in]{%s}' % img_file, r'\par'])
136 [r'\includegraphics[width=6in]{%s}' % img_file, r'\par'])
137
137
138 def _svg_lines(self, img_file):
138 def _svg_lines(self, img_file):
139 base_file = os.path.splitext(img_file)[0]
139 base_file = os.path.splitext(img_file)[0]
140 pdf_file = base_file + '.pdf'
140 pdf_file = base_file + '.pdf'
141 subprocess.check_call([self.inkscape, '--export-pdf=%s' % pdf_file,
141 subprocess.check_call([self.inkscape, '--export-pdf=%s' % pdf_file,
142 img_file])
142 img_file])
143 return self._img_lines(pdf_file)
143 return self._img_lines(pdf_file)
144
144
145 def render_markdown(self, cell):
145 def render_markdown(self, cell):
146 return [markdown2latex(cell.source)]
146 return [markdown2latex(cell.source)]
147
147
148 def render_pyout(self, output):
148 def render_pyout(self, output):
149 lines = []
149 lines = []
150
150
151 # output is a dictionary like object with type as a key
151 # output is a dictionary like object with type as a key
152 if 'latex' in output:
152 if 'latex' in output:
153 lines.extend(output.latex)
153 lines.extend(self.in_env('equation*', output.latex.lstrip('$$').rstrip('$$')))
154
154
155 if 'text' in output:
155 if 'text' in output:
156 lines.extend(self.in_env('verbatim', output.text))
156 lines.extend(self.in_env('verbatim', output.text))
157
157
158 return lines
158 return lines
159
159
160 def render_pyerr(self, output):
160 def render_pyerr(self, output):
161 # Note: a traceback is a *list* of frames.
161 # Note: a traceback is a *list* of frames.
162 return self.in_env('traceback',
162 return self.in_env('traceback',
163 self.in_env('verbatim',
163 self.in_env('verbatim',
164 remove_ansi('\n'.join(output.traceback))))
164 remove_ansi('\n'.join(output.traceback))))
165
165
166 def render_raw(self, cell):
166 def render_raw(self, cell):
167 if self.raw_as_verbatim:
167 if self.raw_as_verbatim:
168 return self.in_env('verbatim', cell.source)
168 return self.in_env('verbatim', cell.source)
169 else:
169 else:
170 return [cell.source]
170 return [cell.source]
171
171
172 def _unknown_lines(self, data):
172 def _unknown_lines(self, data):
173 return [r'{\vspace{5mm}\bf WARNING:: unknown cell:}'] + \
173 return [r'{\vspace{5mm}\bf WARNING:: unknown cell:}'] + \
174 self.in_env('verbatim', data)
174 self.in_env('verbatim', data)
175
175
176 def render_display_format_text(self, output):
176 def render_display_format_text(self, output):
177 lines = []
177 lines = []
178
178
179 if 'text' in output:
179 if 'text' in output:
180 lines.extend(self.in_env('verbatim', output.text.strip()))
180 lines.extend(self.in_env('verbatim', output.text.strip()))
181
181
182 return lines
182 return lines
183
183
184 def render_display_format_html(self, output):
184 def render_display_format_html(self, output):
185 return []
185 return []
186
186
187 def render_display_format_latex(self, output):
187 def render_display_format_latex(self, output):
188 if type(output.latex) == type([]):
188 if type(output.latex) == type([]):
189 return output.latex
189 return output.latex
190 return [output.latex]
190 return [output.latex]
191
191
192 def render_display_format_json(self, output):
192 def render_display_format_json(self, output):
193 # latex ignores json
193 # latex ignores json
194 return []
194 return []
195
195
196 def render_display_format_javascript(self, output):
196 def render_display_format_javascript(self, output):
197 # latex ignores javascript
197 # latex ignores javascript
198 return []
198 return []
General Comments 0
You need to be logged in to leave comments. Login now