Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Matplotlib save only text without whitespace

So in python I have the following code, taken from this answer:

import matplotlib.pyplot as plt                                                 
import sympy                                                                    

x = sympy.symbols('x')                               
y = 1 + sympy.sin(sympy.sqrt(x**2 + 20))                                         
lat = sympy.latex(y)                                                            

#add text                                 
plt.text(0, 0.6, r"$%s$" % lat, fontsize = 50)                                  

#hide axes                                                                      
fig = plt.gca()                                                                 
fig.axes.get_xaxis().set_visible(False)                                         
fig.axes.get_yaxis().set_visible(False)                                         
plt.savefig('out.png', bbox_inches='tight', pad_inches=0)                                                        
plt.show()

This opens the text and exports it to a png file just fine:

Image Export 1

But this includes whitespace beyond the whitespace outside of the frame. How would you go about cropping the image to export only the text, like a bounding box, like so?

enter image description here

like image 522
satvikb Avatar asked Mar 24 '16 01:03

satvikb


People also ask

How do I save a Matplotlib plot without white space?

To removing white space around a saved image with Python matplotlib, we call plt. savefig with the bbox_inches argument set to 'tight' . to call savefig to save the flots to myfile. png.

How do I get rid of white space Matplotlib?

Hide the Whitespaces and Borders in Matplotlib Figure To get rid of whitespace around the border, we can set bbox_inches='tight' in the savefig() method. Similarly, to remove the white border around the image while we set pad_inches = 0 in the savefig() method.


1 Answers

The following is not a perfect solution, but it will hopefully give you some ideas on how to progress:

import matplotlib.pyplot as plt
import sympy

x = sympy.symbols('x')
y = 1 + sympy.sin(sympy.sqrt(x**2 + 2))
lat = sympy.latex(y)

fig = plt.figure()
renderer = fig.canvas.get_renderer()
t = plt.text(0.001, 0.001, f"${lat}$", fontsize=50)
wext = t.get_window_extent(renderer=renderer)

fig.set_size_inches(wext.width / 65, wext.height / 40, forward=True)
fig.patch.set_facecolor('white')
plt.axis('off')
plt.tight_layout()
plt.savefig('out.png', bbox_inches='tight', pad_inches=0)
plt.show()

The idea being that you can determine the size of your text by getting the window extent using the current renderer. It is then also possible to manually specify a figure size. I am though not sure on the correct approach to convert between the two. Note, I added a border to the image so you can see that amount of remaining padding:

matplotlib output


As a workaround to this problem, the following approach simply makes use of Python's PIL library to automatically crop the image before saving it:

import io
from PIL import Image, ImageOps
import matplotlib.pyplot as plt
import sympy

x = sympy.symbols('x')
y = 5 /sympy.sqrt(1 + sympy.sin(sympy.sqrt(x**2 + 2))) 
lat = sympy.latex(y)

fig = plt.figure()
t = plt.text(0.001, 0.001, f"${lat}$", fontsize=50)

fig.patch.set_facecolor('white')
plt.axis('off')
plt.tight_layout()

with io.BytesIO() as png_buf:
    plt.savefig(png_buf, bbox_inches='tight', pad_inches=0)
    png_buf.seek(0)
    image = Image.open(png_buf)
    image.load()
    inverted_image = ImageOps.invert(image.convert("RGB"))
    cropped = image.crop(inverted_image.getbbox())
    cropped.save('out.png')

The cropped version looks like:

cropped version

like image 199
Martin Evans Avatar answered Nov 06 '22 08:11

Martin Evans