Latex generator using Jinja

Wed 11 November 2020
Kawasukune-jinja (Photo creadit: Wikipedia)

The goal is to generate a PDF file using python. I decided to generate \(\LaTeX\).

Pipeline

I decided to use jinja as its documentation mention it.

\begin{equation*} \boxed{\text{Jinja template}} \xrightarrow[\text{python}]{} \boxed{\LaTeX} \xrightarrow[\text{pdflatex}]{} \boxed{\text{PDF}} \end{equation*}

The hard part is the \(\LaTeX\) generation using python. This require few modification in jinja templates.

Jinja modification

Jinja is made to generate html files. Directives (such as statements and expressions) use delimiters that are not entirely compatible with \(\LaTeX\) file.

There is a widely used way <http://eosrei.net/articles/2015/11/latex-templates-python-and-jinja2-generate-pdfs>_ to overcome this problem written by Brad Erikson.

A basic minimal working example is the following:

  • The \(LaTeX\) template:

templates/document.tex:

\documentclass{article}

\BLOCK{ for pkg in packages }
\usepackage{\VAR{pkg}}
\BLOCK{ endfor }

\begin{document}

\BLOCK{ block content } \BLOCK{ endblock }

\end{document}
  • The code to use it
import os.path

import jinja2

latex_jinja_env = jinja2.Environment(
    block_start_string="\BLOCK{",
    block_end_string="}",
    variable_start_string="\VAR{",
    variable_end_string="}",
    comment_start_string="\#{",
    comment_end_string="}",
    line_statement_prefix="%%",
    line_comment_prefix="%#",
    trim_blocks=True,
    autoescape=False,
    loader=jinja2.FileSystemLoader(os.path.abspath("templates")),
)

doc = latex_jinja_env.get_template("document.tex")
simpledoc = doc.render(packages=["amsmath", "makeidx"])

with open("/tmp/doc.tex", "w") as fd:
    fd.write(simpledoc)
  • The produced file
\documentclass{article}

\usepackage{amsmath}
\usepackage{makeidx}

\begin{document}


\end{document}

Yes, I know, there is no content, but is uses several jinja mechanisms:

  • a for loop to specify packages used
  • jinja block
  • jinja variable

I don't understand the difference between block and statement. In both cases it consists of executable code lines.

Template specificity

Inheritance

Let's now play with the inheritance feature of jinja templates.

We have to:

  • extend the document
  • modify the packages variable to ensure one specific package in used
  • fill the content block

I decided to implement a template to write a table taking as argument a list of dict (API comparable to the csv.DictWriter)

The directives to extend the first template and to include a package (let's say the array package) are the following

%% extends "document.tex"
%% set packages = packages + ["array"] if packages else ["array",]

Then, we have to retrieve the table headers and the number of columns

%% if not headers
%% set headers = table[0].keys()
%% set ncol = headers|length
%% endif

I decided to use keys from the first line if no headers were provided.

Finally, we have to draw the table

\BLOCK{ block content }
\begin{tabular}{ l|*{\VAR{ ncol }}{l}|}
\cline{2-\VAR{ ncol + 1 }}
\BLOCK{ for h in headers }& \VAR{ h } \BLOCK{ endfor }\\
\cline{2-\VAR{ ncol + 1 }}

\end{tabular}
\BLOCK{ endblock }

I decided to offset the columns because I first wanted to begin each line by its number but then I dropped this idea.

dict keys

One difficulty is to access dict element by keys when keys are themselves variables. I didn't find any documentation although this step is not that difficult:

Given the dict row and the keys in the iteratble headers:

\BLOCK{ for col in headers }& \VAR{ row[col] } \BLOCK{ endfor }

The table template

Putting all together, the template is the following one:

templates/dict_writer.tex

%% extends "document.tex"
%% set packages = packages + ["array"] if packages else ["array",]

%% if not headers
%% set headers = table[0].keys()
%% set ncol = headers|length
%% endif

\BLOCK{ block content }
\begin{tabular}{ l|*{\VAR{ ncol }}{l}|}
\cline{2-\VAR{ ncol + 1 }}
\BLOCK{ for h in headers }& \VAR{ h } \BLOCK{ endfor }\\
\cline{2-\VAR{ ncol + 1 }}
%% for row in table
\BLOCK{ for col in headers }& \VAR{ row[col] } \BLOCK{ endfor }\\
%% endfor
\cline{2-\VAR{ ncol + 1 }}
\end{tabular}
\BLOCK{ endblock }

Alternatives

This method works but I think other alternatives are to be considered, especially if they avoid using too many languages:

  • generate an html
\begin{equation*} \boxed{\text{Jinja template}} \xrightarrow[\text{python}]{} \boxed{html} \xrightarrow[\text{wkhtmltopdf}]{} \boxed{\text{PDF}} \end{equation*}

There are several way to transfrom an html to a pdf, wkhtml2pdf is only one of them.

This method takes advantage of all the power of jinja to generate html.

  • python library generating latex

The pandas library can export a DataFrame to latex, other libraries exist to generate latex but I didn't test them (yet)

  • directly generate the latex in python

Category: LaTeX Tagged: python LaTeX Jinja


LaTeX makefile updated

Fri 29 March 2019

My default LaTeX makefile evolved. Here is an update:

The makefile looks like:

LATEX=pdflatex
BIBTEX=bibtex
BIB=
RERUN='(There is undefined reference|Rerun to get (cross-references|the bars) right)'

%.pdf:%.tex
    ${LATEX} $<
    @if [ -e $*.bbl ]; then ${BIBTEX} $* && ${LATEX} $< && ${LATEX} $< ; fi
    @if egrep -q $(RERUN) $*.log ; then ${LATEX} $< ; fi

%.aux …

Category: tools Tagged: GNU LaTeX Makefile Writing how to tools

Read More

Functional Block diagram

Thu 28 March 2019

How to make a block diagram with \(\text{\LaTeX}\)?

This article is mainly inspired by tex example.

Here is an example with tikz resulting in the following figure:

The code:

\documentclass{article}
\usepackage[landscape,margin=1cm]{geometry}

\usepackage{tikz}
\usetikzlibrary{shapes,arrows}
\begin{document}


\tikzstyle{block}=[draw,fill=red …

Category: LaTeX Tagged: LaTeX how to

Read More

Conference posters

Fri 11 December 2015
English: This mindmap (Mind map) consists of r...

mindmap needing clarification (Photo credit: Wikipedia)

Few weeks ago, I wrote about mindmap in LaTeX . Now I want to precise few ideas and to have all key ideas visible in one sight. I think the best layout is similar to a conference poster:

  • key ideas are easily seen few meters away …

Category: LaTeX Tagged: LaTeX Poster how to tools

Read More

LaTeX paragraph trick

Wed 05 August 2015
[caption id="" align="alignright" width="150" class="zemanta-img"]Lorem ipsum flush left aligned parnoindent (Photo credit: Wikipedia)[/caption]
It may be hard to use \par\noindent to begin a paragraph without indentation just after a \section or \paragraph command. One can think of letting a blank line, but this may not work. A trick is …

Category: LaTeX Tagged: LaTeX Typesetting

Read More

LaTeX mindmap

Tue 09 June 2015

The canonical way to draw a mindmap in LaTeX seems to be using the ad-hoc tikz module.

Quick beginner guide

  1. use the tikz package adding in the preamble usepackage{tikz}
  2. load the mindmap module using usetikzlibrary{mindmap}
  3. begin your tikz picture with begin{tikzpicture}[mindmap] (you may add others options) and …

Category: LaTeX Tagged: LaTeX Mindmap how to tools

Read More
Page 1 of 2

Next »