Skip to content
Geoffrey Poore edited this page Jul 14, 2014 · 9 revisions

This page describes ways to make PythonTeX work with matplotlib more conveniently.

Saving figures and including them in your document

Suppose you have the following code in your document:

x = linspace(0, pi)
plt.plot(x, sin(x), label='sin(x)')
plt.plot(x, cos(x), label='cos(x)')

If you want to quickly view these plots in your document, you could call plt.legend() and plt.savefig('foo.pdf') and then write the LaTeX code to include a figure. To simplify this process the following helper functions may be useful. (Modify them to suit your needs!)

# Set the prefix used for figure labels
fig_label_prefix = 'fig'
# Track figure numbers to create unique auto-generated names
fig_count = 0

def savefig(name='', legend=False, fig=None, ext='.pdf'):
    '''
    Save the current figure (or `fig`) to file using `plt.savefig()`.
    If called with no arguments, automatically generate a unique filename.
    Return the filename.
    '''
    # Get name (without extension) and extension
    if not name:
        global fig_count
        # `pytex.id` is a unique identifier for the session;
        # it's `<family>_<session>_<restart>`
        name = 'auto_fig_{}-{}'.format(pytex.id, fig_count)
        fig_count += 1
    else:
        if len(name) > 4 and name[:-4] in ['.pdf', '.svg', '.png', '.jpg']:
            name, ext = name.rsplit('.', 1)

    # Get current figure if figure isn't specified
    if not fig:
        fig = gcf()

    # Put a nice legend on top of the figure (you may need to adjust this!)
    # Only create legend if axis has labels
    if legend and len(fig.gca().get_legend_handles_labels()[0]) != 0: 
        for ax in fig.axes:
            if ax.is_first_row():
                box = ax.get_position()
                ax.set_position([box.x0, box.y0, box.width, box.height*0.9])
        leg = ax.legend(loc="upper center", bbox_to_anchor=(0.5, 1.04), ncol=3, bbox_transform=fig.transFigure, frameon=False)
    fig.savefig(name + ext)
    fig.clf()
    return name

def latex_environment(name, content='', option=''):
    '''
    Simple helper function to write the `\begin...\end` LaTeX block.
    '''
    return '\\\\begin{%s}%s\n%s\n\\\\end{%s}' % (name, option, content, name)

def latex_figure(name=None, caption='', label='', width=0.8):
    ''''
    Auto wrap `name` in a LaTeX figure environment.
    Width is a fraction of `\textwidth`.
    '''
    if not name:
        name = savefig()
    content = '\\\\centering\n'
    content += '\\\\includegraphics[width=%f\\\\textwidth]{%s}\n' % (width, name)
    if not label:
        label = name
    if caption and not caption.rstrip().endswith('.'):
        caption += '.'
    # `\label` needs to be in `\caption` to avoid issues in some cases
    content += "\\\\caption{%s\\\\label{%s:%s}}\n" % (caption, fig_label_prefix, label)
    return latex_environment('figure', content, '[htp]')

The above code block can be included in your document's preamble via

\begin{pythontexcustomcode}[begin]
...
\end{pythontexcustomcode}

Or you may store it in a file and import it in the usual way. Say you have a src directory alongside your document and the above code is in a file python_preamble.py:

\begin{pythontexcustomcode}[begin]{pylab}
# Might want sys.path.insert(1, '../src/') in some cases
# But then it would probably be better to use virtualenv
sys.path.append('../src/')
from python_preamble import *
\end{pythontexcustomcode}

The figure for the example considered at the beginning may now be created very simply:

\begin{pylabcode}
x = linspace(0, pi)
plt.plot(x, sin(x), label='sin(x)')
plt.plot(x, cos(x), label='cos(x)')
name = savefig()
fig = latex_figure(name)
\end{pylabcode}
\pylab{fig}

Of course, we could also just print the figure, using print(latex_figure()) at the end of the pylabcode environment or using \pylab{latex_figure()} after the end of the environment.

PGF backend

Matplotlib 1.2 has a new pgf backend. This may be useful when you want to create graphics that are compiled at the same time as the document (for better font integration, etc.).

Clone this wiki locally