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.).