Last active
January 1, 2016 17:29
-
-
Save danielrichman/8177307 to your computer and use it in GitHub Desktop.
IPYNB -> Latex nbconvert template for CATAM
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/local/bin/python3.3 | |
# -*- coding: utf8 -*- | |
{% for worksheet in nb.worksheets -%} | |
{%- for cell in worksheet.cells -%} | |
{%- if cell.cell_type in ['code'] and cell.metadata.listing is defined -%} | |
### {{ cell.metadata.listing.title }} ### | |
{{ cell.input }} | |
{% endif -%} | |
{%- endfor -%} | |
{%- endfor -%} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/make | |
# -*- makefile -*- | |
figures = $(wildcard figure_*.pdf) | |
report.ipynb.tex : report.ipynb ../nbconvert.tplx | |
ipython3 nbconvert \ | |
--to latex \ | |
--template nbconvert \ | |
--ExtractOutputTransformer.enabled=False \ | |
--output=$< $< | |
report.ipynb.py : report.ipynb ../code_submission.tpl | |
ipython3 nbconvert \ | |
--to python \ | |
--template code_submission \ | |
--output=$< $< | |
report.ipynb.pdf : report.ipynb.tex $(figures) | |
pdflatex -halt-on-error $< | |
all : report.ipynb.pdf report.ipynb.py | |
.PHONY : all | |
.DEFAULT_GOAL := all |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
((*- extends 'latex_basic.tplx' -*)) | |
((*- block headingcell *)) | |
\ | |
((*- if cell.level == 1 -*)) | |
((* block h1 -*))catamtitle{((( cell.metadata.project_number )))}((* endblock h1 -*)) | |
((*- elif cell.level == 2 -*)) | |
((* block h2 -*))section*((* endblock h2 -*)) | |
((*- elif cell.level == 3 -*)) | |
((* block h3 -*))subsection*((* endblock h3 -*)) | |
((*- elif cell.level == 4 -*)) | |
((* block h4 -*))subsubsection*((* endblock h4 -*)) | |
((*- elif cell.level == 5 -*)) | |
((* block h5 -*))textbf((* endblock h5 -*)) | |
((*- elif cell.level == 6 -*)) | |
((* block h6 -*))textit((* endblock h6 -*)) | |
((*- endif -*)) | |
{((( cell.source | replace('\n', ' ') | markdown2latex )))} | |
((* endblock headingcell -*)) | |
((*- block header *)) | |
\documentclass{article} | |
\usepackage[a4paper,left=2cm,top=2cm]{geometry} | |
\usepackage[utf8x]{inputenc} | |
\usepackage[T1]{fontenc} | |
\usepackage{parskip} | |
\usepackage{graphicx} | |
\usepackage{amsmath} | |
\usepackage{amssymb} | |
\usepackage[justification=centering]{caption} | |
\usepackage{subcaption} | |
\usepackage{fancyvrb} | |
\usepackage{color} | |
\usepackage{placeins} | |
\usepackage{fancyhdr} | |
\usepackage{lastpage} | |
((* for worksheet in nb.worksheets -*)) | |
((*- for cell in worksheet.cells -*)) | |
((*- if cell.metadata.usepackages is defined -*)) | |
((*- for package in cell.metadata.usepackages *)) | |
\usepackage{((( package )))} | |
((* endfor -*)) | |
((*- endif -*)) | |
((*- endfor -*)) | |
((*- endfor *)) | |
\newcommand{\catamtitle}[2]{ | |
\begin{titlepage} | |
\vspace*{-1.5cm} | |
\hspace{-1.5cm} | |
\huge{#1} | |
\centering | |
\vspace*{5cm} % 2cm margin + 5cm > 5cm space for label | |
\huge{#2} | |
\vspace{10cm} | |
\large{\today} | |
\end{titlepage} | |
} | |
\pagestyle{fancy} | |
\renewcommand{\headrulewidth}{0pt} | |
\cfoot{\thepage\ of \pageref{LastPage} } | |
((( resources.sphinx.pygment_definitions ))) | |
\newcommand{\mathstop}{\text{\quad.}} | |
\newcommand{\mathcomma}{\text{\quad,}} | |
\newcommand{\mathcolon}{\text{\quad:}} | |
\newcommand{\mathand}{\text{\quad and}} | |
((* endblock header -*)) | |
((*- block body -*)) | |
\begin{document} | |
((= pass one: non-code cells and programmatically generated latex -=)) | |
((*- for worksheet in nb.worksheets -*)) | |
((*- for cell in worksheet.cells -*)) | |
((*- if cell.cell_type in ['code'] -*)) | |
((*- for output in cell.outputs -*)) | |
((*- for type in output | filter_data_type -*)) | |
((*- if type in ['latex'] *)) | |
((( output.latex ))) | |
((* endif -*)) | |
((*- endfor -*)) | |
((*- endfor -*)) | |
((*- else -*)) | |
((*- block any_cell scoped -*)) | |
(((- super() -))) | |
((*- endblock any_cell -*)) | |
((*- endif -*)) | |
((*- endfor -*)) | |
((*- endfor -*)) | |
((=- pass two: code listings =)) | |
\clearpage | |
\section*{Code listings} | |
((*- for worksheet in nb.worksheets -*)) | |
((*- for cell in worksheet.cells -*)) | |
((*- if cell.cell_type in ['code'] and cell.metadata.listing is defined *)) | |
\filbreak | |
\subsection*{((( cell.metadata.listing.title )))} | |
\label{code:((( cell.metadata.listing.id )))} | |
((( cell.input | highlight2latex ))) | |
((* endif -*)) | |
((*- endfor -*)) | |
((*- endfor *)) | |
\end{document} | |
((*- endblock body -*)) | |
((* block rawcell scoped *)) | |
((( cell.source ))) | |
((* endblock rawcell *)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import markupsafe | |
from IPython.display import DisplayObject | |
class Table(DisplayObject): | |
VDOTS = object() | |
def __init__(self, data, headings=None, formats=None, | |
caption=None, label=None, position='h', subtables=1): | |
""" | |
A HTML/LaTeX IPython DisplayObject Table | |
`data` should be a 2 dimensional array, indexed by row then column, | |
with an optional extra row `headings`. | |
A 'row' (i.e., an element of `data`) may also be | |
:py:const:`Table.VDOTS`, which produces vertical dots in all columns. | |
`formats` may be a string, whose format method will be used for every | |
cell; a function, called for every cell; or a mixed array of strings | |
and functions which is zipped with each row. | |
Headings are not formatted. | |
`caption` and `label` add the relevant LaTeX markup, and will go in | |
the first row of the HTML copy. `label` will have ``tab:`` prepended | |
to it. | |
If `subtables` is greater than 1, the table will be split into | |
`subtables` parts of approximately equal length, and laid out side | |
by side. | |
""" | |
if len(data) == 0: | |
raise ValueError("data is empty") | |
if label is None != caption is None: | |
raise ValueError("specify neither or both of label & caption") | |
self.columns = len(data[0]) | |
if self.columns == 0: | |
raise ValueError("no columns") | |
if headings and len(headings) != self.columns: | |
raise ValueError("bad headings length") | |
if isinstance(formats, str): | |
formats = [formats.format] * self.columns | |
elif callable(formats): | |
formats = [formats] * self.columns | |
elif formats: | |
if len(formats) != self.columns: | |
raise ValueError("bad formats length") | |
def maybe_string_format(f): | |
if isinstance(f, str): | |
return f.format | |
else: | |
assert callable(f) | |
return f | |
formats = list(map(maybe_string_format, formats)) | |
else: | |
formats = [self._default_format] * self.columns | |
for i, row in enumerate(data): | |
if row is not self.VDOTS and len(row) != self.columns: | |
raise ValueError("bad row length", i) | |
self.headings = headings | |
self.data = data | |
self.formats = formats | |
self.caption = caption | |
self.label = label | |
self.position = position | |
self.subtables = subtables | |
@staticmethod | |
def _default_format(what): | |
if isinstance(what, float): | |
return "{0:.5f}".format(what) | |
else: | |
return str(what) | |
def _format_rows(self): | |
for row in self.data: | |
if row is self.VDOTS: | |
yield self.VDOTS | |
else: | |
yield (f(x) for f, x in zip(self.formats, row)) | |
def _subtables_split(self): | |
assert self.subtables > 1 | |
rows = list(self._format_rows()) | |
nominal_height = len(rows) // self.subtables | |
remainder = len(rows) % self.subtables | |
heights = [nominal_height] * self.subtables | |
for i in range(remainder): | |
heights[i] += 1 | |
slices = [] | |
acc = 0 | |
for l in heights: | |
slices.append((acc, acc + l)) | |
acc += l | |
assert slices[-1][1] == len(rows) | |
subtables = [rows[a:b] for a, b in slices] | |
return subtables | |
def _repr_latex_(self): | |
strings = [] | |
strings.append(r""" | |
\begin{table}[""" + self.position + r"""] | |
\centering | |
""") | |
if self.label: | |
strings.append(r"\caption{" + self.caption + "}") | |
strings.append(r"\label{tab:" + self.label + "}") | |
if self.subtables > 1: | |
subtables = self._subtables_split() | |
width = "{:.3f}\linewidth".format(0.95 / self.subtables) | |
for i, rows in enumerate(subtables): | |
strings.append(r"\begin{{subtable}}[t]{{{0}}}%".format(width)) | |
strings.append(r""" | |
\centering | |
\vspace{0pt} | |
""") | |
self._latex_tabular(strings, rows) | |
strings.append(r"\end{subtable}%") | |
if i != len(subtables) - 1: | |
strings.append("\hfill%") | |
else: | |
rows = self._format_rows() | |
self._latex_tabular(strings, rows) | |
strings.append(r""" | |
\end{table} | |
""") | |
return "\n".join(strings) | |
def _latex_tabular(self, strings, rows): | |
x = "|".join(["c"] * self.columns) | |
strings.append(r"\begin{tabular}{|" + x + "|}") | |
strings.append(r"\hline") | |
if self.headings: | |
latex = " & ".join(str(x) for x in self.headings) | |
strings.append(latex + r" \\") | |
strings.append(r"\hline") | |
for row in rows: | |
if row is self.VDOTS: | |
row = [r"\vdots"] * self.columns | |
latex = " & ".join(row) | |
strings.append(latex + r" \\") | |
strings.append(r""" | |
\hline | |
\end{tabular}%""") | |
def _repr_html_(self): | |
strings = [] | |
strings.append(""" | |
<style type="text/css"> | |
.util_Table td { text-align: center; } | |
.util_Table tbody tr, .util_Table tbody td { | |
border-bottom: 0; | |
border-top: 0; | |
} | |
.util_Table_subtable { | |
float: left; | |
} | |
</style> | |
""") | |
if self.label: | |
c = markupsafe.escape(self.caption) | |
l = "<code>[{}]</code>".format(markupsafe.escape(self.label)) | |
strings.append(""" | |
<h3>{1} {2}</h3> | |
""".format(self.columns, c, l)) | |
if self.subtables > 1: | |
subtables = self._subtables_split() | |
width = 0.95 / self.subtables | |
strings.append("<div class='clearfix'>") | |
for rows in subtables: | |
strings.append("<div class='util_Table_subtable'>") | |
self._html_table(strings, rows) | |
strings.append("</div>") | |
strings.append("</div>") | |
else: | |
rows = self._format_rows() | |
self._html_table(strings, rows) | |
return "\n".join(strings) | |
def _html_table(self, strings, rows): | |
strings.append("<table class='util_Table'>") | |
if self.headings: | |
strings.append("<thead>") | |
strings.append("<tr>") | |
headings = map(markupsafe.escape, self.headings) | |
headings = map("<th>{0}</th>".format, headings) | |
strings.append("\n".join(headings)) | |
strings.append("</tr>") | |
strings.append("</thead>") | |
strings.append("<tbody>") | |
for row in rows: | |
if row is self.VDOTS: | |
row = ["\u22ee"] * self.columns | |
strings.append("<tr>") | |
row = map(markupsafe.escape, row) | |
row = map("<td>{0}</td>".format, row) | |
strings.append("\n".join(row)) | |
strings.append("</tr>") | |
strings.append("</tbody>") | |
strings.append("</table>") | |
def __repr__(self): | |
if self.headings: | |
widths = [len(x) for x in self.headings] | |
data = [self.headings] | |
else: | |
widths = None | |
data = [] | |
# don't forget - self._format_rows() is a generator that yields generators | |
for row in self._format_rows(): | |
if row is self.VDOTS: | |
continue | |
r = list(row) | |
w = [len(x) for x in r] | |
if widths is None: | |
widths = w | |
else: | |
widths = [max(a, b) for a, b in zip(widths, w)] | |
data.append(list(r)) | |
strings = [] | |
if self.label: | |
c = self.caption.replace("\n", " ") | |
strings.append('Table: {0} ({1})'.format(self.label, c)) | |
for row in data: | |
if row is self.VDOTS: | |
strings.append('...') | |
else: | |
r = [x.ljust(b + 4) for x, b in zip(row, widths)] | |
strings.append(''.join(r)) | |
return '\n'.join(strings) | |
def __html__(self): | |
return self._repr_html_() | |
class LatexFigure(object): | |
def __init__(self, label, caption, fig=None, position="h"): | |
""" | |
A LaTeX IPython DisplayObject Figure | |
`label` is mandatory, since it also sets the filename. It will | |
have ``fig:`` preprended to it. | |
`fig` is optional - the current figure (via ``gcf``) will be used | |
if it is not set. | |
`position` is either the float placement specifier or the subfigure | |
vertical position. | |
If `subfigure` is set to true, a subfigure with width `width` will | |
be created. | |
The figure is saved (via ``savefig``) as a PDF file in the current | |
directory. | |
Displaying the object produces LaTeX (only) to embed the figure. | |
A little hacky, but since this is meant for use in the notebook | |
it is assumed that the figure is going to be displayed automatically | |
in HTML independently. | |
""" | |
if fig is None: | |
from matplotlib.pyplot import gcf | |
fig = gcf() | |
self.label = label | |
self.caption = caption | |
self.fig = fig | |
self.position = position | |
self.filename = "figure_" + label + ".pdf" | |
self.fig.savefig(self.filename) | |
def _repr_html_(self): | |
# Bit crude. Hide ourselves to the notebook viewer, since we'll | |
# have been shown already anyway. | |
# Nicer solutions are afaict infeasible. | |
return "" | |
def _repr_latex_(self, subfigure=None): | |
if subfigure: | |
environment = "subfigure" | |
args = "[{position}]{{{width}}}".format(**subfigure) | |
else: | |
environment = "figure" | |
args = "[{0}]".format(self.position) | |
return r""" | |
\begin{""" + environment + "}" + args + r""" | |
\centering | |
\includegraphics{""" + self.filename + r"""} | |
\caption{""" + self.caption + r"""} | |
\label{fig:""" + self.label + r"""} | |
\end{""" + environment + r"""} | |
""" | |
def __repr__(self): | |
c = self.caption.replace("\n", " ") | |
return "Figure: {0} ({1})".format(self.label, c) | |
def __html__(self): | |
return "" | |
class LatexSubfigures(object): | |
def __init__(self, label, caption, figures, position='h', | |
subfigure_position='b'): | |
""" | |
Displays several :cls:`LatexFigures` as sub-figures, two per row. | |
`figures` should be an array of :cls:`LatexFigure` objects, not | |
:cls:`matplotlib.Figure` objects. | |
""" | |
self.label = label | |
self.caption = caption | |
self.figures = figures | |
self.position = position | |
self.subfigure_position = subfigure_position | |
def _repr_html_(self): | |
# Bit crude. Hide ourselves to the notebook viewer, since we'll | |
# have been shown already anyway. | |
# Nicer solutions are afaict infeasible. | |
return "" | |
def _repr_latex_(self): | |
strings = [] | |
strings.append(r""" | |
\begin{figure}[""" + self.position + r"""] | |
\centering | |
""") | |
left = True | |
first = True | |
opts = {"position": self.subfigure_position, "width": ".5\linewidth"} | |
for f in self.figures: | |
if left and not first: | |
strings.append(r"\vspace{1em}") | |
# have to be quite careful about whitespace | |
latex = f._repr_latex_(subfigure=opts).strip() | |
if left: | |
latex += '%' | |
else: | |
latex += r'\newline' | |
first = False | |
left = not left | |
strings.append(latex) | |
strings.append(r""" | |
\caption{""" + self.caption + r"""} | |
\label{fig:""" + self.label + r"""} | |
\end{figure} | |
""") | |
return "\n".join(strings) | |
def __repr__(self): | |
c = self.caption.replace("\n", " ") | |
strings = ["Figure group: {0} ({1})".format(self.label, c)] | |
strings += [repr(x) for x in self.figures] | |
return "\n".join(strings) | |
def __html__(self): | |
return "" | |
class LatexNumberFormatter(object): | |
""" | |
Format floats in exponent notation using latex markup for the exponent | |
e.g., ``$-4.234 \\times 10^{-5}$`` | |
Usage: | |
>>> fmtr = LatexNumberFormatter(sf=4) | |
>>> fmtr(-4.234e-5) | |
"$-4.234 \\\\times 10^{-5}$" | |
""" | |
def __init__(self, sf=10): | |
"""Create a callable object that formats numbers""" | |
self.sf = sf | |
self.s_fmt = "{{:.{0}e}}".format(self.sf) | |
def __call__(self, n): | |
"""Format `n`""" | |
n = self.s_fmt.format(n) | |
n, e, exp = n.partition("e") | |
if e == "e": | |
exp = int(exp) | |
if not n.startswith("-"): | |
n = r"\phantom{-}" + n | |
return r"${} \times 10^{{{}}}$".format(n, exp) | |
else: | |
return "${}$".format(n) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment