##// END OF EJS Templates
Split transformer code
Split transformer code

File last commit:

r10386:6416b524
r10437:8f13741f
Show More
latex.py
231 lines | 8.2 KiB | text/x-python | PythonLexer
David Warde-Farley
Introduce standard structure from coding guidelines in converters/.
r8789 """Notebook export to LaTeX.
This file implements a converter class for rendering IPython notebooks as
LaTeX, suitable for rendering by pdflatex.
"""
#-----------------------------------------------------------------------------
# Copyright (c) 2012, the IPython Development Team.
#
# Distributed under the terms of the Modified BSD License.
#
# The full license is in the file COPYING.txt, distributed with this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
# Stdlib imports
David Warde-Farley
PEP8-ify rest of the repository.
r8749 import os
Matthias BUSSONNIER
latex working
r8618 import subprocess
David Warde-Farley
PEP8-ify rest of the repository.
r8749 import sys
Matthias BUSSONNIER
latex working
r8618
David Warde-Farley
Introduce standard structure from coding guidelines in converters/.
r8789 # Our own imports
Anthony Scopatz
convters sub-package use relative imports
r8933 from .base import Converter
from .utils import markdown2latex, remove_ansi
David Warde-Farley
Introduce standard structure from coding guidelines in converters/.
r8789
#-----------------------------------------------------------------------------
# Globals and constants
#-----------------------------------------------------------------------------
# XXX: This is a hack that needs to be addressed in a more principled fashion.
Matthias BUSSONNIER
latex working
r8618 inkscape = 'inkscape'
if sys.platform == 'darwin':
inkscape = '/Applications/Inkscape.app/Contents/Resources/bin/inkscape'
if not os.path.exists(inkscape):
inkscape = None
David Warde-Farley
PEP8-ify rest of the repository.
r8749
David Warde-Farley
Introduce standard structure from coding guidelines in converters/.
r8789 #-----------------------------------------------------------------------------
David Warde-Farley
More descriptive comment headers.
r8808 # Class declarations
David Warde-Farley
Introduce standard structure from coding guidelines in converters/.
r8789 #-----------------------------------------------------------------------------
Matthias BUSSONNIER
latex working
r8618 class ConverterLaTeX(Converter):
"""Converts a notebook to a .tex file suitable for pdflatex.
Note: this converter *needs*:
- `pandoc`: for all conversion of markdown cells. If your notebook only
has Raw cells, pandoc will not be needed.
David Warde-Farley
PEP8-ify rest of the repository.
r8749
Matthias BUSSONNIER
latex working
r8618 - `inkscape`: if your notebook has SVG figures. These need to be
converted to PDF before inclusion in the TeX file, as LaTeX doesn't
understand SVG natively.
David Warde-Farley
PEP8-ify rest of the repository.
r8749
Matthias BUSSONNIER
latex working
r8618 You will in general obtain much better final PDF results if you configure
David Warde-Farley
PEP8-ify rest of the repository.
r8749 the matplotlib backend to create SVG output with
Matthias BUSSONNIER
latex working
r8618
%config InlineBackend.figure_format = 'svg'
(or set the equivalent flag at startup or in your configuration profile).
"""
David Warde-Farley
More documentation.
r8811 #-------------------------------------------------------------------------
# Class-level attributes determining the behaviour of the class but
# probably not varying from instance to instance.
#-------------------------------------------------------------------------
Matthias BUSSONNIER
latex working
r8618 extension = 'tex'
David Warde-Farley
More documentation.
r8811 # LaTeX specific class configuration.
inkscape = inkscape
Matthias BUSSONNIER
latex working
r8618 documentclass = 'article'
documentclass_options = '11pt,english'
jakobgager
Use equation_env variable, PEP8 adaptation
r8806 equation_env = 'equation*'
Matthias BUSSONNIER
latex working
r8618 heading_map = {1: r'\section',
2: r'\subsection',
3: r'\subsubsection',
4: r'\paragraph',
5: r'\subparagraph',
6: r'\subparagraph'}
Rick Lupton
LaTeX converter: command line args for preamble filename and to exclude certain cell types
r8750 user_preamble = None
jakobgager
Improve conversion to latex of output cells...
r8804 display_data_priority = ['latex', 'pdf', 'svg', 'png', 'jpg', 'text']
Matthias BUSSONNIER
latex working
r8618
def in_env(self, environment, lines):
"""Return list of environment lines for input lines
Parameters
----------
env : string
Name of the environment to bracket with begin/end.
lines: """
out = [ur'\begin{%s}' % environment]
if isinstance(lines, basestring):
out.append(lines)
else: # list
out.extend(lines)
out.append(ur'\end{%s}' % environment)
return out
David Warde-Farley
PEP8-ify rest of the repository.
r8749 def convert(self, *args, **kwargs):
Matthias BUSSONNIER
latex working
r8618 # The main body is done by the logic in the parent class, and that's
# all we need if preamble support has been turned off.
David Warde-Farley
PEP8-ify rest of the repository.
r8749 body = super(ConverterLaTeX, self).convert(*args, **kwargs)
Matthias BUSSONNIER
latex working
r8618 if not self.with_preamble:
return body
# But if preamble is on, then we need to construct a proper, standalone
# tex file.
David Warde-Farley
PEP8-ify rest of the repository.
r8749
Matthias BUSSONNIER
latex working
r8618 # Tag the document at the top and set latex class
jakobgager
Use equation_env variable, PEP8 adaptation
r8806 final = [r'%% This file was auto-generated by IPython.',
David Warde-Farley
PEP8-ify rest of the repository.
r8749 r'%% Conversion from the original notebook file:',
r'%% {0}'.format(self.infile),
r'%%',
r'\documentclass[%s]{%s}' % (self.documentclass_options,
self.documentclass),
'',
Matthias BUSSONNIER
latex working
r8618 ]
# Load our own preamble, which is stored next to the main file. We
# need to be careful in case the script entry point is a symlink
myfile = os.path.realpath(__file__)
David Warde-Farley
PEP8-ify rest of the repository.
r8749 preamble = '../preamble.tex'
with open(os.path.join(os.path.dirname(myfile), preamble)) as f:
Matthias BUSSONNIER
latex working
r8618 final.append(f.read())
David Warde-Farley
PEP8-ify rest of the repository.
r8749
Matthias BUSSONNIER
latex working
r8618 # Load any additional user-supplied preamble
if self.user_preamble:
final.extend(['', '%% Adding user preamble from file:',
'%% {0}'.format(self.user_preamble), ''])
with open(self.user_preamble) as f:
final.append(f.read())
David Warde-Farley
PEP8-ify rest of the repository.
r8749
Matthias BUSSONNIER
latex working
r8618 # Include document body
David Warde-Farley
PEP8-ify rest of the repository.
r8749 final.extend([r'\begin{document}', '',
body,
r'\end{document}', ''])
jakobgager
Improve conversion to latex of output cells...
r8804 # Return value must be a string
Matthias BUSSONNIER
latex working
r8618 return '\n'.join(final)
David Warde-Farley
PEP8-ify rest of the repository.
r8749
Matthias BUSSONNIER
latex working
r8618 def render_heading(self, cell):
marker = self.heading_map[cell.level]
David Warde-Farley
PEP8-ify rest of the repository.
r8749 return ['%s{%s}' % (marker, cell.source)]
Matthias BUSSONNIER
latex working
r8618
def render_code(self, cell):
if not cell.input:
return []
# Cell codes first carry input code, we use lstlisting for that
lines = [ur'\begin{codecell}']
Rick Lupton
Options to exclude certain sections (source code or cell output) from exported result
r8753
if 'source' not in self.exclude_cells:
lines.extend(self.in_env('codeinput',
self.in_env('lstlisting', cell.input)))
else:
# Empty output is still needed for LaTeX formatting
lines.extend(self.in_env('codeinput', ''))
Matthias BUSSONNIER
latex working
r8618
outlines = []
Rick Lupton
Options to exclude certain sections (source code or cell output) from exported result
r8753 if 'output' not in self.exclude_cells:
for output in cell.outputs:
conv_fn = self.dispatch(output.output_type)
outlines.extend(conv_fn(output))
Matthias BUSSONNIER
latex working
r8618
# And then output of many possible types; use a frame for all of it.
if outlines:
lines.extend(self.in_env('codeoutput', outlines))
lines.append(ur'\end{codecell}')
return lines
def _img_lines(self, img_file):
jakobgager
Use equation_env variable, PEP8 adaptation
r8806 rel_img_position = os.path.relpath(img_file, self.infile_dir)
return self.in_env('center',
[r'\includegraphics[width=0.7\textwidth]{%s}' % rel_img_position,
r'\par'])
Matthias BUSSONNIER
latex working
r8618
def _svg_lines(self, img_file):
base_file = os.path.splitext(img_file)[0]
pdf_file = base_file + '.pdf'
David Warde-Farley
PEP8-ify rest of the repository.
r8749 subprocess.check_call([self.inkscape, '--export-pdf=%s' % pdf_file,
Matthias BUSSONNIER
latex working
r8618 img_file])
return self._img_lines(pdf_file)
def render_markdown(self, cell):
return [markdown2latex(cell.source)]
David Warde-Farley
PEP8-ify rest of the repository.
r8749
Matthias BUSSONNIER
latex working
r8618 def render_pyout(self, output):
lines = []
# output is a dictionary like object with type as a key
if 'latex' in output:
jakobgager
Use equation_env variable, PEP8 adaptation
r8806 lines.extend(self.in_env(self.equation_env,
output.latex.lstrip('$$').rstrip('$$')))
jakobgager
Improve conversion to latex of output cells...
r8804 #use text only if no latex representation is available
elif 'text' in output:
Matthias BUSSONNIER
latex working
r8618 lines.extend(self.in_env('verbatim', output.text))
return lines
def render_pyerr(self, output):
# Note: a traceback is a *list* of frames.
return self.in_env('traceback',
David Warde-Farley
PEP8-ify rest of the repository.
r8749 self.in_env('verbatim',
Matthias BUSSONNIER
latex working
r8618 remove_ansi('\n'.join(output.traceback))))
def render_raw(self, cell):
if self.raw_as_verbatim:
return self.in_env('verbatim', cell.source)
else:
return [cell.source]
def _unknown_lines(self, data):
return [r'{\vspace{5mm}\bf WARNING:: unknown cell:}'] + \
self.in_env('verbatim', data)
def render_display_format_text(self, output):
jakobgager
Improve conversion to latex of output cells...
r8804 return self.in_env('verbatim', output.text.strip())
Matthias BUSSONNIER
latex working
r8618
def render_display_format_html(self, output):
return []
def render_display_format_latex(self, output):
jakobgager
Use equation_env variable, PEP8 adaptation
r8806 return self.in_env(self.equation_env,
output.latex.lstrip('$$').rstrip('$$'))
Matthias BUSSONNIER
latex working
r8618
def render_display_format_json(self, output):
# latex ignores json
return []
def render_display_format_javascript(self, output):
# latex ignores javascript
return []