Pregunta

Using the python library matplotlib, I've found what suggests to be a solution to this question:
Displaying (nicely) an algebraic expression in PyQt by utilising matplotlibs TeX markup.

What I'd like to do is take TeX code from my python program which represents a mathematical expression, and save it to an image that can be displayed in my PyQt GUI, rather than displaying the equation in ugly plain text.

Something like this essentially...

import matplotlib.pyplot as plt
formula = '$x=3^2$'

fig = plt.figure()
fig.text(0,0,formula)
fig.savefig('formula.png')

However, the pyplot module is primarily for displaying graphs and plots, not the samples of text like I need. The result of that code is usually a tiny bit of text in the bottom left corner of a huge, white, blank image.
If my formula involves fractions, and thus requires downward space, it is truncated, like in the image below.

Note that this appears a blank image; look to the left side of the display
Fraction at coordinate (0,0) truncated and surrounded by whitespace

I believe I could create a very large (space wise) figure, write the formula in the middle of the blank plot, save it, and use pixel analysis to trim it to as small an image as possible, but this seems rather crude.

Are plots the only intended output of matplotlib?
Is there nothing devoted to just outputting equations, that won't require me to worry about all the extra space or position of the text?

Thanks!

¿Fue útil?

Solución

The trick is to render the text, then get its bounding box, and finally adjust the figure size and the vertical positioning of text in the new figure. This saves the figure twice, but as is common in any text engine, the correct bounding box and other parameters can only be correctly obtained after the text has been rendered.

import pylab

formula = r'$x=3^2, y = \frac{1}{\frac{2}{3}}, %s$' % ('test' * 20)

fig = pylab.figure()
text = fig.text(0, 0, formula)

# Saving the figure will render the text.
dpi = 300
fig.savefig('formula.png', dpi=dpi)

# Now we can work with text's bounding box.
bbox = text.get_window_extent()
width, height = bbox.size / float(dpi) + 0.005
# Adjust the figure size so it can hold the entire text.
fig.set_size_inches((width, height))

# Adjust text's vertical position.
dy = (bbox.ymin/float(dpi))/height
text.set_position((0, -dy))

# Save the adjusted text.
fig.savefig('formula.png', dpi=dpi)

The 0.005 constant was added to width and height because, apparently, for certain texts Matplotlib is returning a slightly underestimated bounding box, i.e., smaller than required.

Otros consejos

The text in the figure can be placed correctly using figure.suptitle and specifying sensible alignments, such that the text sits in the top left corner and runs down and to the right (relative to the x and y coordinates specified).

fig = plt.Figure()
fig.suptitle('TeX', 
             horizontalalignment = 'left',
             verticalalignment='top', 
             x=0.01, y = 0.99)

It can be wrapped in a Qt Widget, FigureCanvasQTAgg to be displayed in the program.

canvas = FigureCanvasQTAgg(fig) #Treated as QWidget
canvas.draw()

However, the canvas and figure remain no knowledge of the size of the text and so can still be too large and cause white-space, or be too small and cause truncation. This is fine for the purposes of my program, but doesn't satisfy the Question as mmgp's does.

what about

import matplotlib.pyplot as plt

params = {
      'figure.figsize': [2,2],
     }
plt.rcParams.update(params)

formula = r'$x=\frac{3}{100}$'

fig = plt.figure()
fig.text(0.5,0.5,formula)

plt.savefig('formula.png')

The first two arguments of the matplotlib text() function set the position of the text (between 0 & 1, so 0.5 for both gets your text in the middle.)

You can change all kinds of things like the font and text size by setting the rc parameters. See http://matplotlib.org/users/customizing.html. I've editted the rc params for figure size, but you can change the defaults so you don't have to do this every time.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top