# Generating plots with pgfplots

Plotting results is often needed in Computer Science.
Say, you have a program that generates data which you want to plot.

A normal approach to this would be:

1. Write your results to a csv-file
2. Importing that file into a spreadsheet application like Excel
3. Clicking around to generate a plot
4. Saving the plot as an image
5. Putting the image into a LaTeX report

In case you change something in your program, this entire process would have to be repeated in order to get your fresh results plotted and into your report.

How cumbersome. This is a stupid problem we can solve with programming.
If our program already generates data and writes it to disk in text format, we can just add functions that write that data as LaTeX!

### Introducing PGFplots

PGFPlots is a nice package for LaTeX that does exactly what it says. It creates plots. There’s a gallery full of examples right here:
http://pgfplots.sourceforge.net/gallery.html
There are endless possibilities and this post will focus on generating plots from data generated by a program, not on the capabilities of pgfplots. Check out the main site for the package if you want to know how pgfplots works and what it can do.

http://pgfplots.sourceforge.net/

A pgfplot can look like this:

It is a made up example, plotting two data sets apples and oranges.

The code that generates this plot is:




### Writing a program to do the hard work

We can break the structure of this into its discrete parts, identify the static parts and the changing parts.

All plots start and end with these two lines:




We then have a “preamble” with 8 changing parts: the height and width of the plot, the four coordinates defining the values in the coordinate system and the labels of the x and y axis:

        \begin{axis}[ %Axis defines the metadata for our plot
height=9cm,%Height of the plot
width=9cm,%Width of the plot
grid=major,
xmin=0,%The starting x-coordinate
xmax=5,%The ending x-coordinate
ymin=0,%The starting y-coordinate
ymax=10,%The ending y-coordinate
xlabel=Time,%The label on the x-axis
ylabel=Number sold%The label on the y-axis
]
... % the actual plot goes here
\end{axis}


Last but not least we have the actual plot. For each thing we want to plot, we have a static part that always has to be there and a changing part, our data points and the label we want to go in the legend of the plot.

In my example, the labels are apples and oranges, each representing my made up data sets.

        \addplot coordinates { % The coordinates for apples
(0.0, 0.0)
(1.0, 2.0)
(2.0, 3.0)
(3.0, 5.0)
(4.0, 7.0)
(5.0, 3.0)
};


Breaking this down further, we have

	\addplot coordinates {
% Coordinates, i.e. data from our program, goes here
};


Writing functions that generates LaTeX for our plots is easy. We just need to inject our data into the static parts of a plot!

I will use F# for this but any language that can generate a string can be used.

First a long codedump that generates the example plot, then explanations of each part of the code:

let apples  = [(0.0, 0.0); (1.0,2.0); (2.0,3.0); (3.0,5.0); (4.0, 7.0); (5.0, 3.0)]
let oranges = [(0.0, 1.0); (1.0,3.0); (2.0,1.0); (3.0,5.0); (4.0, 4.0); (5.0, 8.0)]

/// All plots start and end with the same text.
/// This injects a string into that
let wrapInBeginAndEnd (s:string) =
let beginString = @""
sprintf "%s\n%s\n%s" beginString s endString

/// All plots define an "axis", metadata for our plot
/// This injects our parameters into that.
let generateAxis height width xmin xmax ymin ymax xlabel ylabel =
let beginAxis =        @"\begin{axis}["
let h         = sprintf "height=%dcm," height
let w         = sprintf "width=%dcm," width
let grid      =         "grid=major,"
let xMin      = sprintf "xmin=%d," xmin
let xMax      = sprintf "xmax=%d," xmax
let yMin      = sprintf "ymin=%d," ymin
let yMax      = sprintf "ymax=%d," ymax
let xlbl      = sprintf "xlabel=%s," xlabel
let ylbl      = sprintf "ylabel=%s," ylabel

sprintf "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n]\n" beginAxis h w grid xMin xMax yMin yMax xlbl ylbl

/// Generates the begin axis part, injecting the volatile parts height and width
let wrapInAxis height width xmin xmax ymin ymax  xlabel ylabel toWrap =
let openAxis  = generateAxis height width xmin xmax ymin ymax xlabel ylabel
let closeAxis = @"\end{axis}"
sprintf "%s%s\n%s\n" openAxis toWrap closeAxis

/// Converts our list of data to newline-separated tikz-data
let floatTupleListToTikzTuples (data: (float*float) list)  =
let convFun acc x = sprintf "%s%A\n" acc x
List.fold convFun "" data

let wrapCoords coordsAsString legendName =
let legend  = sprintf @"\addlegendentry{%s}" legendName

// Convert data to tikz data
let applesCoords = floatTupleListToTikzTuples apples
let orangesCoords = floatTupleListToTikzTuples oranges
// Wrap data in \addplot{...} including legend entry name
let wrappedApplesCoords = wrapCoords applesCoords "apples"
let wrappedOrangesCoords = wrapCoords orangesCoords "oranges"
// Joins the two generated plots
let allCoordsAsTikz =  sprintf "%s\n%s\n" wrappedApplesCoords wrappedOrangesCoords
// Wraps it all in \begin{axis}...\end{axis}
let withAxis = wrapInAxis 9 9 0 5 0 10 "Time" "Number sold" allCoordsAsTikz
// wraps it all in
let finalLatex = wrapInBeginAndEnd withAxis

printfn "%s" finalLatex


Not too bad. Now for the explanations.

We start by converting our data to something Tikz can understand. (Tikz is what pgfplots uses to draw the plots).

let floatTupleListToTikzTuples (data: (float*float) list)  =
let convFun acc x = sprintf "%s%A\n" acc x
List.fold convFun "" data


We have our data as tuples of floats. F# lets us convert the tuple into a string, using the format string %A. We want to separate the elements by newline. We accomplish this with a fold over our list of data, generating the desired string for each element of our data.

We now want to wrap the plot coordinates in the
in the

let wrapCoords coordsAsString legendName =
let legend = sprintf @"\addlegendentry{%s}" legendName


Next we want to wrap that inside the
\begin{axis}…\end{axis} part. We need to generate the axis preamble before we can do that!

let generateAxis height width xmin xmax ymin ymax xlabel ylabel =
let beginAxis =        @"\begin{axis}["
let h         = sprintf "height=%dcm," height
let w         = sprintf "width=%dcm," width
let grid      =         "grid=major,"
let xMin      = sprintf "xmin=%d," xmin
let xMax      = sprintf "xmax=%d," xmax
let yMin      = sprintf "ymin=%d," ymin
let yMax      = sprintf "ymax=%d," ymax
let xlbl      = sprintf "xlabel=%s," xlabel
let ylbl      = sprintf "ylabel=%s," ylabel

sprintf "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n]\n" beginAxis h w grid xMin xMax yMin yMax xlbl ylbl


This function seems a bit messy but actually there is not much going on, just a lot of format strings.

The function takes these parameters as input:

• height : int
• width : int
• xmin : int
• xmax : int
• ymin : int
• ymax : int
• xlabel : string
• ylabel : string

Now that we can generate our axis preamble, we want to inject our plots in between
\begin{axis}[…] … \end{axis}.

let wrapInAxis height width xmin xmax ymin ymax  xlabel ylabel toWrap =
let openAxis  = generateAxis height width xmin xmax ymin ymax xlabel ylabel
let closeAxis = @"\end{axis}"
sprintf "%s%s\n%s\n" openAxis toWrap closeAxis


We are almost done! We just need to wrap our generated string in between

.

The following piece of code does exactly that.

let wrapInBeginAndEnd (s:string) =
let beginString = @""
sprintf "%s\n%s\n%s" beginString s endString


Putting it all together, we end up with the many lines of code I showed earlier.
The generated LaTeX-string can be saved to disk and used in any LaTeX report.

### Getting the plot into a LaTeX report

LaTeX has a command for including LaTeX files. This is useful if you are writing e.g. a book and want to split your chapters into separate files.
It is also useful to us, as we can save the generated plot as a .tex file and just include that.
If we have a LaTeX file called report.tex and in the same directory have a file called ourGeneratedPlot.tex, we can include the plot in our report in the following way:

\documentclass[12pt, a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage [T1]{fontenc}
\usepackage{pgfplots} % We of course need to include the package pgfplots to use it
\pgfplotsset{compat=1.13}
\title{Plotting with PGFPlots}