# Diagram Generator Lua Filter

## Introduction
This Lua filter is used to create images with or without captions from code
blocks. Currently PlantUML, Graphviz, Ti*k*Z and Python can be processed.
This document also serves as a test document, which is why the subsequent
test diagrams are integrated in every supported language.

## Prerequisites
To be able to use this Lua filter, the respective external tools must be
installed. However, it is sufficient if the tools to be used are installed.
If you only want to use PlantUML, you don't need LaTeX or Python, etc.

### PlantUML
To use PlantUML, you must install PlantUML itself. See the
[PlantUML website](http://plantuml.com/) for more details. It should be
noted that PlantUML is a Java program and therefore Java must also
be installed.

By default, this filter expects the plantuml.jar file to be in the
working directory. Alternatively, the environment variable
`PLANTUML` can be set with a path. If, for example, a specific
PlantUML version is to be used per pandoc document, the
`plantumlPath` meta variable can be set.

Furthermore, this filter assumes that Java is located in the
system or user path. This means that from any place of the system
the `java` command is understood. Alternatively, the `JAVA_HOME`
environment variable gets used. To use a specific Java version per
pandoc document, use the `javaPath` meta variable. Please notice
that `JAVA_HOME` must be set to the java's home directory e.g.
`c:\Program Files\Java\jre1.8.0_201\` whereas `javaPath` must be
set to the absolute path of `java.exe` e.g.
`c:\Program Files\Java\jre1.8.0_201\bin\java.exe`.

Example usage:

~~~~~~~~~~~~~~~~
```{.plantuml caption="This is an image, created by **PlantUML**."}
@startuml
Alice -> Bob: Authentication Request Bob --> Alice: Authentication Response
Alice -> Bob: Another authentication Request Alice <-- Bob: another Response
@enduml
```
~~~~~~~~~~~~~~~~

### Graphviz
To use Graphviz you only need to install Graphviz, as you can read
on its [website](http://www.graphviz.org/). There are no other
dependencies.

This filter assumes that the `dot` command is located in the path
and therefore can be used from any location. Alternatively, you can
set the environment variable `DOT` or use the pandoc's meta variable
`dotPath`.

Example usage from [the Graphviz
gallery](https://graphviz.gitlab.io/_pages/Gallery/directed/fsm.html):

~~~~~~~~~~~~~~~~
```{.graphviz caption="This is an image, created by **Graphviz**'s dot."}
digraph finite_state_machine {
	rankdir=LR;
	size="8,5"
	node [shape = doublecircle]; LR_0 LR_3 LR_4 LR_8;
	node [shape = circle];
	LR_0 -> LR_2 [ label = "SS(B)" ];
	LR_0 -> LR_1 [ label = "SS(S)" ];
	LR_1 -> LR_3 [ label = "S($end)" ];
	LR_2 -> LR_6 [ label = "SS(b)" ];
	LR_2 -> LR_5 [ label = "SS(a)" ];
	LR_2 -> LR_4 [ label = "S(A)" ];
	LR_5 -> LR_7 [ label = "S(b)" ];
	LR_5 -> LR_5 [ label = "S(a)" ];
	LR_6 -> LR_6 [ label = "S(b)" ];
	LR_6 -> LR_5 [ label = "S(a)" ];
	LR_7 -> LR_8 [ label = "S(b)" ];
	LR_7 -> LR_5 [ label = "S(a)" ];
	LR_8 -> LR_6 [ label = "S(b)" ];
	LR_8 -> LR_5 [ label = "S(a)" ];
}
```
~~~~~~~~~~~~~~~~

### Ti*k*Z
Ti*k*Z (cf. [Wikipedia](https://en.wikipedia.org/wiki/PGF/TikZ)) is a
description language for graphics of any kind that can be used within
LaTeX (cf. [Wikipedia](https://en.wikipedia.org/wiki/LaTeX)).

Therefore a LaTeX system must be installed on the system. The Ti*k*Z code is
embedded into a dynamic LaTeX document. This temporary document gets
translated into a PDF document using LaTeX (`pdflatex`). Finally,
Inkscape is used to convert the PDF file to the desired format.

Note: We are using Inkscape here to use a stable solution for the
convertion. Formerly ImageMagick was used instead. ImageMagick is
not able to convert PDF files. Hence, it uses Ghostscript to do
so, cf. [1](https://stackoverflow.com/a/6599718/2258393).
Unfortunately, Ghostscript behaves unpredictable during Windows and
Linux tests cases, cf. [2](https://stackoverflow.com/questions/21774561/some-pdfs-are-converted-improperly-using-imagemagick),
[3](https://stackoverflow.com/questions/9064706/imagemagic-convert-command-pdf-convertion-with-bad-size-orientation), [4](https://stackoverflow.com/questions/18837093/imagemagic-renders-image-with-black-background),
[5](https://stackoverflow.com/questions/37392798/pdf-to-svg-is-not-perfect),
[6](https://stackoverflow.com/q/10288065/2258393), etc. By using Inkscape,
we need one dependency less and get rid of unexpected Ghostscript issues.

Due to this more complicated process, the use of Ti*k*Z is also more
complicated overall. The process is error-prone: An insufficiently
configured LaTeX installation or an insufficiently configured
Inkscape installation can lead to errors. Overall, this results in
the following dependencies:

- Any LaTeX installation. This should be configured so that
missing packages are installed automatically. This filter uses the
`pdflatex` command which is available by the system's path. Alternatively,
you can set the `PDFLATEX` environment variable. In case you have to use
a specific LaTeX version on a pandoc document basis, you might set the
`pdflatexPath` meta variable.

- An installation of [Inkscape](https://inkscape.org/).
It is assumed that the `inkscape` command is in the path and can be
executed from any location. Alternatively, the environment
variable `INKSCAPE` can be set with a path. If a specific
version per pandoc document is to be used, the `inkscapePath`
meta-variable can be set.

In order to use additional LaTeX packages, use the optional
`additionalPackages` attribute in your document, as in the
example below.

Example usage from [TikZ
examples](http://www.texample.net/tikz/examples/parallelepiped/) by
[Kjell Magne Fauske](http://www.texample.net/tikz/examples/nav1d/):

~~~~~~~~~~~~~~~~
```{.tikz caption="This is an image, created by **TikZ i.e. LaTeX**."
     additionalPackages="\usepackage{adjustbox}"}
\usetikzlibrary{arrows}
\tikzstyle{int}=[draw, fill=blue!20, minimum size=2em]
\tikzstyle{init} = [pin edge={to-,thin,black}]

\resizebox{16cm}{!}{%
  \trimbox{3.5cm 0cm 0cm 0cm}{
    \begin{tikzpicture}[node distance=2.5cm,auto,>=latex']
      \node [int, pin={[init]above:$v_0$}] (a) {$\frac{1}{s}$};
      \node (b) [left of=a,node distance=2cm, coordinate] {a};
      \node [int, pin={[init]above:$p_0$}] at (0,0) (c)
        [right of=a] {$\frac{1}{s}$};
      \node [coordinate] (end) [right of=c, node distance=2cm]{};
      \path[->] (b) edge node {$a$} (a);
      \path[->] (a) edge node {$v$} (c);
      \draw[->] (c) edge node {$p$} (end) ;
    \end{tikzpicture}
  }
}
```
~~~~~~~~~~~~~~~~

### Python
In order to use Python to generate a diagram, your Python code must store the
final image data in a temporary file with the correct format. In case you use
matplotlib for a diagram, add the following line to do so:

```python
plt.savefig("$DESTINATION$", dpi=300, fomat="$FORMAT$")
```

The placeholder `$FORMAT$` gets replace by the necessary format. Most of the
time, this will be `png` or `svg`. The second placeholder, `$DESTINATION$`
gets replaced by the path and file name of the destination. Both placeholders
can be used as many times as you want. Example usage from the [Matplotlib 
examples](https://matplotlib.org/gallery/lines_bars_and_markers/cohere.html#sphx-glr-gallery-lines-bars-and-markers-cohere-py):

~~~~~~~~~~~~~~~~
```{.py2image caption="This is an image, created by **Python**."}
import matplotlib
matplotlib.use('Agg')

import sys
import numpy as np
import matplotlib.pyplot as plt

# Fixing random state for reproducibility
np.random.seed(19680801)

dt = 0.01
t = np.arange(0, 30, dt)
nse1 = np.random.randn(len(t))                 # white noise 1
nse2 = np.random.randn(len(t))                 # white noise 2

# Two signals with a coherent part at 10Hz and a random part
s1 = np.sin(2 * np.pi * 10 * t) + nse1
s2 = np.sin(2 * np.pi * 10 * t) + nse2

fig, axs = plt.subplots(2, 1)
axs[0].plot(t, s1, t, s2)
axs[0].set_xlim(0, 2)
axs[0].set_xlabel('time')
axs[0].set_ylabel('s1 and s2')
axs[0].grid(True)

cxy, f = axs[1].cohere(s1, s2, 256, 1. / dt)
axs[1].set_ylabel('coherence')

fig.tight_layout()
plt.savefig("$DESTINATION$", dpi=300, fomat="$FORMAT$")
```
~~~~~~~~~~~~~~~~

Precondition to use Python is a Python environment which contains all
necessary libraries you want to use. To use, for example, the standard
[Anaconda Python](https://www.anaconda.com/distribution/) environment
on a Microsoft Windows system ...

- set the environment variable `PYTHON` or the meta key `pythonPath`
to `c:\ProgramData\Anaconda3\python.exe`

- set the environment variable `PYTHON_ACTIVATE` or the meta
key `activatePythonPath` to `c:\ProgramData\Anaconda3\Scripts\activate.bat`.

Pandoc will activate this Python environment and starts Python with your code.

## How to run pandoc
This section will show, how to call Pandoc in order to use this filter with
meta keys. The following command assume, that the filters are stored in the
subdirectory `filters`. Further, this is a example for a Microsoft Windows
system.

Command to use PlantUML (a single line):

```
pandoc.exe README.md -f markdown -t docx --self-contained --standalone --lua-filter=filters\diagram-generator.lua --metadata=plantumlPath:"c:\ProgramData\chocolatey\lib\plantuml\tools\plantuml.jar" --metadata=javaPath:"c:\Program Files\Java\jre1.8.0_201\bin\java.exe" -o README.docx
```

All available environment variables:

- `PLANTUML` e.g. `c:\ProgramData\chocolatey\lib\plantuml\tools\plantuml.jar`; Default: `plantuml.jar`
- `INKSCAPE` e.g. `c:\Program Files\Inkscape\inkscape.exe`; Default: `inkscape`
- `PYTHON` e.g. `c:\ProgramData\Anaconda3\python.exe`; Default: n/a
- `PYTHON_ACTIVATE` e.g. `c:\ProgramData\Anaconda3\Scripts\activate.bat`; Default: n/a
- `JAVA_HOME` e.g. `c:\Program Files\Java\jre1.8.0_201`; Default: n/a
- `DOT` e.g. `c:\ProgramData\chocolatey\bin\dot.exe`; Default: `dot`
- `PDFLATEX` e.g. `c:\Program Files\MiKTeX 2.9\miktex\bin\x64\pdflatex.exe`; Default: `pdflatex`

All available meta keys:

- `plantumlPath`
- `inkscapePath`
- `pythonPath`
- `activatePythonPath`
- `javaPath`
- `dotPath`
- `pdflatexPath`
