Generating latex friendly plots

1,754 views
Skip to first unread message

Oliver Lylloff

unread,
May 12, 2014, 6:04:13 AM5/12/14
to julia...@googlegroups.com
Hello all, 

For several years (in the dark Matlab-ages before Julia), I used matlab2tikz to generate nice looking pdf figures for academic reports. It's a nice tool and I personally like the idea that my data is exported from matlab to a .tikz or .tex file that I can make changes to without having to open matlab and reexport my figures.

Julia already has some very nice plotting features in Winston, Gadfly and matplotlib (IJulia), am I forgetting someone? The exporting options are good and useful for many different purposes. However, for me, there's something extraordinary about the tikz/pgf plots that I haven't been able to reproduce with these packages. 

Therefore I've made a quick-and-dirty module https://github.com/1oly/PrintFig.jl that uses PyCall to call matplotlib2tikz, a close relative to matlab2tikz, that exports figure objects to a .tex file using the standalone latex documentclass. I like this approach and it creates the figures that I like for academic work. It's not the intention to add this to METADATA but merely to get a discussion going - if anyone is interested at all...

If anyone has comments, suggestions or want to discuss workflows for generating latex friendly plots, don't be shy :)

Cheers,
Oliver

Tomas Lycken

unread,
May 12, 2014, 6:20:19 AM5/12/14
to julia...@googlegroups.com
Hi,

This is really interesting to me as well. Being able to produce high-quality plots for academic publication more or less, imho, requires being able to typeset the textual content of the plot in LaTeX, to get fonts, font sizes etc to look nice with the rest of the document. There is this issue to add similar functionality to Gadfly.jl, but it doesn't seem like it's a priority.

// Tomas

Cristóvão Duarte Sousa

unread,
May 12, 2014, 8:38:54 AM5/12/14
to julia...@googlegroups.com
Hi,

Were you aware that matplotlib itself has a PGF/TikZ backend http://matplotlib.org/users/pgf.html ?

With it one does not need to use matplotlib2tikz, and one can save plots either as PFG files, prepared to
be included in some LaTeX document, or directly as PDF.

It took me long time to figure out how to properly tell matplotlib (from within Julia) to use that backend to
save PDF (I had to use PyCall in the end), but since then I've been successfully using this feature in Julia.

An example of how to save a figure in PGF source:

using PyPlot

##### plot appearance setup
linewidth = 0.4
plt.rc("axes", linewidth=linewidth)
plt.rc("font", family="")
plt.rc("axes", titlesize="small", labelsize="small")
plt.rc("xtick", labelsize="x-small")
plt.rc("xtick.major", width=linewidth/2)
plt.rc("ytick", labelsize="x-small")
plt.rc("ytick.major", width=linewidth/2)
plt.rc("legend", fontsize="small")

#### plot
x = linspace(0,2pi,100);
fig = plt.figure(figsize=(3,2));
plot(x,sin(x),color="red");
title(L"Test plot");
xlabel(L"$x$");
ylabel(L"$\sin(x)$");

#### save plot as PGF source (no setup needed)
plt.savefig("test.pgf")

If one wants to directly generate a PDF, then

### setup matplotlib to save PDF with the PGF backend (tricky in Julia)
using PyCall
backend_pgf
= pyimport("matplotlib.backends.backend_pgf")
backend_bases
= pyimport("matplotlib.backend_bases")
backend_bases
[:register_backend]("pdf", backend_pgf[:FigureCanvasPgf])

### setup PGF-PDF backend output appearance
plt
.rc("pgf", texsystem="pdflatex",
              preamble
=L"""\usepackage[utf8x]{inputenc}
                           \usepackage[T1]{fontenc}
                           \usepackage{lmodern}"""
)

#### save directly as PDF (there is NO need to save as PFG first)
plt
.savefig("test.pdf", transparent=true)

I think you can make your package to use this features.

Cheers,
Cristóvão

Steven G. Johnson

unread,
May 12, 2014, 8:57:01 AM5/12/14
to julia...@googlegroups.com


On Monday, May 12, 2014 8:38:54 AM UTC-4, Cristóvão Duarte Sousa wrote:
It took me long time to figure out how to properly tell matplotlib (from within Julia) to use that backend to
save PDF (I had to use PyCall in the end), but since then I've been successfully using this feature in Julia.

Is this due to the complexity of Matplotlib itself (i.e. is it about the same difficulty in Python?), or is there some specific difficulty with PyPlot/PyCall?

Cristóvão Duarte Sousa

unread,
May 12, 2014, 8:58:38 AM5/12/14
to julia...@googlegroups.com
Ah, attention that both "plt.rc(......" blocks in my examples are completely optional, I just use them to better match the default LaTeX visuals.

Miguel Bazdresch

unread,
May 12, 2014, 9:42:28 AM5/12/14
to julia...@googlegroups.com
Some time ago I wrote a script to use pgfplots from octave/Matlab:

https://bitbucket.org/mbaz/printpgf/src/28cead667bda6ec745a4418bc408f7f712cf8433/inst/printpgf.m

It's very easy to use and I've used it for several publications. I tried it to make it very easy to perfectly match fonts with the rest of your document, by including a document preamble that you specify.

I want to port this to Julia, but I haven't had the time. If somebody thinks this is a good idea, feel free to copy it.

-- mb

Cristóvão Duarte Sousa

unread,
May 12, 2014, 10:27:31 AM5/12/14
to julia...@googlegroups.com
Hi Steven,

According to http://matplotlib.org/users/pgf.html one has to do
matplotlib.use('pgf')
or
from matplotlib.backends.backend_pgf import FigureCanvasPgf
matplotlib
.backend_bases.register_backend('pdf', FigureCanvasPgf)


Both work as expected in Python. In Julia the first one done as
matplotlib[:use]("pgf")

issues this warning (in REPL only, not in IJulia):
UserWarning:  This call to matplotlib.use() has no effect
because the backend has already been chosen
;
matplotlib
.use() must be called *before* pylab, matplotlib.pyplot,
or matplotlib.backends is imported for the first time.

That is something not easy to do before the "using PyPlot" :)


So I try the second way, but it was not possible to access the needed Python modules/objects
from PyPlot.matplotlib alone, and that's why I had to rely on PyCall. Maybe I'd missed something.

That took me sometime, but now I remember that what took me long time was to realize that

println(PyPlot.matplotlib[:rcParams]["axes.linewidth"])
PyPlot.matplotlib[:rcParams]["axes.linewidth"] = 2         # this does not work
println
(PyPlot.matplotlib[:rcParams]["axes.linewidth"])
plt
.rc("axes", linewidth=2)                                # but this works
println
(PyPlot.matplotlib[:rcParams]["axes.linewidth"])
1.0
1.0
2.0

Sure, I should had report these issues in the first place but I got a little lazy :p

Steven G. Johnson

unread,
May 12, 2014, 12:16:09 PM5/12/14
to julia...@googlegroups.com


On Monday, May 12, 2014 10:27:31 AM UTC-4, Cristóvão Duarte Sousa wrote:
Hi Steven,

According to http://matplotlib.org/users/pgf.html one has to do
matplotlib.use('pgf')

Yes, there is currently no easy way to load PyPlot with a different backend like this.  I could add such a feature pretty easily, but the alternate command that allows you to continue using Matplotlib interactively is probably nicer anyway.
 
from matplotlib.backends.backend_pgf import FigureCanvasPgf
matplotlib
.backend_bases.register_backend('pdf', FigureCanvasPgf)

For this command, you certainly need to do "using PyCall" in order to access pyimport, but otherwise it looks like you are using exactly the same commands as in Python (albeit translated to Julia/PyCall syntax).   Glad to hear that this works!

Oliver Lylloff

unread,
May 13, 2014, 6:03:03 AM5/13/14
to julia...@googlegroups.com
Hi,

Were you aware that matplotlib itself has a PGF/TikZ backend http://matplotlib.org/users/pgf.html ?

No but this is really cool I think! 
 
An example of how to save a figure in PGF source:

using PyPlot

##### plot appearance setup
linewidth = 0.4
plt.rc("axes", linewidth=linewidth)
plt.rc("font", family="")
plt.rc("axes", titlesize="small", labelsize="small")
plt.rc("xtick", labelsize="x-small")
plt.rc("xtick.major", width=linewidth/2)
plt.rc("ytick", labelsize="x-small")
plt.rc("ytick.major", width=linewidth/2)
plt.rc("legend", fontsize="small")

#### plot
x = linspace(0,2pi,100);
fig = plt.figure(figsize=(3,2));
plot(x,sin(x),color="red");
title(L"Test plot");
xlabel(L"$x$");
ylabel(L"$\sin(x)$");

#### save plot as PGF source (no setup needed)
plt.savefig("test.pgf")


On my setup (both in IJulia and REPL) I still need to do the pyimport of the pgf backend to save as a "test.pgf". Is that just me?

 
If one wants to directly generate a PDF, then

### setup matplotlib to save PDF with the PGF backend (tricky in Julia)
using PyCall
backend_pgf
= pyimport("matplotlib.backends.backend_pgf")
backend_bases
= pyimport("matplotlib.backend_bases")
backend_bases
[:register_backend]("pdf", backend_pgf[:FigureCanvasPgf])

### setup PGF-PDF backend output appearance
plt
.rc("pgf", texsystem="pdflatex",
              preamble
=L"""\usepackage[utf8x]{inputenc}
                           \usepackage[T1]{fontenc}
                           \usepackage{lmodern}"""
)

#### save directly as PDF (there is NO need to save as PFG first)
plt
.savefig("test.pdf", transparent=true)

I think you can make your package to use this features.

This would certainly be easy to implement. One small thing, a matter of taste I would say, is that since I like to have figures saved both as .pgf/.tikz/.tex and pdf, the pgf files are quite difficult to read (for me at least) and therefore also more difficult to make corrections to. In the .pgf case I would probably just run my plot script one more time with my changes. 

Do you have all your settings (the plt.rc parameters) ready each time you savefig or do you copy-paste or have a module?

Cheers,
Oliver

Oliver Lylloff

unread,
May 13, 2014, 6:04:30 AM5/13/14
to julia...@googlegroups.com
This would certainly serve as a good template for a julia version. Thanks!

Cristóvão Duarte Sousa

unread,
May 13, 2014, 12:46:49 PM5/13/14
to julia...@googlegroups.com
I can generate the .pgf without having to setup the backend which I think is the expected behavior. According to the docs: 
"Figures can also be directly compiled and saved to PDF with plt.savefig('figure.pdf') by either switching to the backend..."
So it seems its only needed to save the PDFs... You may try directly in Python to see what hapens.

About the settings, I do copy-paste and change them as I need for each plot. 
Reply all
Reply to author
Forward
0 new messages