6

I want to render equations to PNG files and embed them in the HTML documentation of my library. I am already using pylab (matplotlib) in other projects.

I have not found any clues in http://matplotlib.sourceforge.net/users/usetex.html and http://matplotlib.sourceforge.net/users/mathtext.html

When I do

plt.title(r'$\alpha > \beta$')
plt.show()

I get a titled empty figure with axes.

Update:

After doing some research I found, that the easiest way of rendering LaTeX to png is using mathext ( http://code.google.com/p/mathtex/ ).

Suprisingly, I had all requiered libraries to build it from source.

Anyway, thanks to everyone for replies.

Update 2:

I did some testing of mathtex and found it does not support matrices (\begin{pmatrix}) and some other things I need. So, I'm going to install LaTex (MikTeX).

Update 3:

I installed proTeXt. It's huge, but easy-to-use and fast. IMHO, for now it's the only way of rendering equations.

peterdemin
  • 516
  • 8
  • 26

4 Answers4

8

This worked for me:

# https://gist.github.com/tonyseek/95c90638cf43a87e723b

from cStringIO import StringIO

import matplotlib.pyplot as plt

def render_latex(formula, fontsize=12, dpi=300, format_='svg'):
    """Renders LaTeX formula into image.
    """
    fig = plt.figure(figsize=(0.01, 0.01))
    fig.text(0, 0, u'${}$'.format(formula), fontsize=fontsize)
    buffer_ = StringIO()
    fig.savefig(buffer_, dpi=dpi, transparent=True, format=format_, bbox_inches='tight', pad_inches=0.0)
    plt.close(fig)
    return buffer_.getvalue()

if __name__ == '__main__':
    image_bytes = render_latex(
        r'\theta=\theta+C(1+\theta-\beta)\sqrt{1-\theta}succ_mul',
        fontsize=10, dpi=200, format_='png')
    with open('formula.png', 'wb') as image_file:
        image_file.write(image_bytes)
warvariuc
  • 57,116
  • 41
  • 173
  • 227
  • This is the only good concrete answer I have seen so far. All the other recommend projects that now appear to be dead or point to questions that don't have a real answer. – Mad Physicist Mar 01 '16 at 17:47
  • 1
    In python 3 change the firts line to: `from io import BytesIO as StringIO` – HomoVafer Aug 24 '21 at 16:30
2
  • (source) If you are using IPython interpreter, it renders all single matplotlib step into a figure window by default.

    Thus, plt.title(r'$\alpha > \beta$') in IPython would immediately create a figure even before calling .show(). On the other hand, using terminal/cmd/IDLE won't.

  • plt.show() would create a figure window whether you're using IPython or not, you want to change that line to:

    plt.savefig('filename.png')
    

Edit: Okay, I misunderstood your question. As @Li-aung Yip said, you may want to use Sympy for pure equation image. We can still do some trick in matplotlib to achieve what you want though (you may need to readjust or resize accordingly):

import matplotlib.pyplot as plt

#add text
plt.text(0.01, 0.8, r'$\alpha > \beta$',fontsize=50)

#hide axes
fig = plt.gca()
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.draw() #or savefig

This is done by hiding axes ticks and adding text inside the plot figure.

But...this doesn't really "not drawing" a figure :\ Though you can post-process such as cropping the image with PIL.

EwyynTomato
  • 4,009
  • 1
  • 31
  • 39
  • plt.savefig('filename.png') creates that file with titled empty figure with axes – peterdemin Mar 22 '12 at 10:34
  • 2
    I get `/usr/local/lib/python2.7/dist-packages/matplotlib/backends/backend_gtk3.py:215: Warning: Source ID 7 was not found when attempting to remove it GLib.source_remove(self._idle_event_id)` when executing the last block of code. – Martin Thoma Feb 21 '15 at 09:44
2

It sounds like you want to render LaTeX equations to images. See linked question for a variety of ways of doing this with minimal dependencies. (Some even involve matplotlib, I believe.)

Alternately, if you can install LaTeX or rely on LaTeX being installed, you can just use LaTeX itself to render the equation to postscript and thence into an image format.

Community
  • 1
  • 1
Li-aung Yip
  • 12,320
  • 5
  • 34
  • 49
0

I fiddled with @warvariuc's answer for a long time in Python 3 and came up with the following solution. It is very similar but has a couple of key differences. First, StringIO and cStringIO are not modules in Py3. Secondly, the equivalent class io.StringIO does not work with at least some versions of MatPlotLib. See this thread: http://matplotlib.1069221.n5.nabble.com/savefig-and-StringIO-error-on-Python3-td44241.html. Basically, the image is binary, so you need to use io.BytesIO. The getvalue() method works just as with StringIO. I took the liberty of using savefig to do the file opening, since it can decide whether you passed in a file name or not for itself:

from io import BytesIO
import matplotlib.pyplot as plt

def renderLatex(formula, fontsize=12, dpi=300, format='svg', file=None):
    """Renders LaTeX formula into image or prints to file.
    """
    fig = plt.figure(figsize=(0.01, 0.01))
    fig.text(0, 0, u'${}$'.format(formula), fontsize=fontsize)

    output = BytesIO() if file is None else file
    with warnings.catch_warnings():
        warnings.filterwarnings('ignore', category=MathTextWarning)
        fig.savefig(output, dpi=dpi, transparent=True, format=format,
                    bbox_inches='tight', pad_inches=0.0, frameon=False)

    plt.close(fig)

    if file is None:
        output.seek(0)
        return output

The warning was something that I am pretty sure is related to the figure size. You can remove the enclosing with entirely if you would like. The reason for the seek is to make the "file" readable (best explained here: https://stackoverflow.com/a/8598881/2988730).

Community
  • 1
  • 1
Mad Physicist
  • 107,652
  • 25
  • 181
  • 264