scipy: savefig without frames, axes, only content
PythonImageNumpyMatplotlibScipyPython Problem Overview
In numpy/scipy I have an image stored in an array. I can display it, I want to save it using savefig
without any borders, axes, labels, titles,... Just pure image, nothing else.
I want to avoid packages like PyPNG
or scipy.misc.imsave
, they are sometimes problematic (they do not always install well, only basic savefig()
for me
Python Solutions
Solution 1 - Python
EDIT
Changed aspect='normal
to aspect='auto'
since that changed in more recent versions of matplotlib (thanks to @Luke19).
Assuming :
import matplotlib.pyplot as plt
To make a figure without the frame :
fig = plt.figure(frameon=False)
fig.set_size_inches(w,h)
To make the content fill the whole figure
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
Then draw your image on it :
ax.imshow(your_image, aspect='auto')
fig.savefig(fname, dpi)
The aspect
parameter changes the pixel size to make sure they fill the figure size specified in fig.set_size_inches(…)
. To get a feel of how to play with this sort of things, read through matplotlib's documentation, particularly on the subject of Axes, Axis and Artist.
Solution 2 - Python
An easier solution seems to be:
fig.savefig('out.png', bbox_inches='tight', pad_inches=0)
Solution 3 - Python
You can find the bbox of the image inside the axis (using get_window_extent
), and use the bbox_inches
parameter to save only that portion of the image:
import numpy as np
import matplotlib.pyplot as plt
data=np.arange(9).reshape((3,3))
fig=plt.figure()
ax=fig.add_subplot(1,1,1)
plt.axis('off')
plt.imshow(data)
extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig('/tmp/test.png', bbox_inches=extent)
I learned this trick from Joe Kington here.
Solution 4 - Python
I've tried several options in my case, and the best solution was this:
fig.subplots_adjust(bottom = 0)
fig.subplots_adjust(top = 1)
fig.subplots_adjust(right = 1)
fig.subplots_adjust(left = 0)
then save your figure with savefig
Solution 5 - Python
I will suggest heron13 answer with a slight addition borrowed from here to remove the padding left after setting the bbox to tight mode, therefore:
axes = fig.axes()
axes.get_xaxis().set_visible(False)
axes.get_yaxis().set_visible(False)
fig.savefig('out.png', bbox_inches='tight', pad_inches=0)
Solution 6 - Python
This one work for me
plt.savefig('filename',bbox_inches='tight',transparent=True, pad_inches=0)
Solution 7 - Python
For anybody trying to do this in Jupyter
plt.axis('off')
spec = plt.imshow
plt.savefig('spec',bbox_inches='tight',transparent=True, pad_inches=0)
Solution 8 - Python
Actually I have tried this recently and instead of all these lines, you can use
plt.imsave(image_path, image)
Works like a charm. just one line and problem solved.
imsave()
Documentation ( https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.imsave.html )
Solution 9 - Python
For me, this code made similar the input image size without frame and axes. I combined snippets from matehat, unutbu, and WHZW:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
plt.axis('off')
viridis = cm.get_cmap('gist_gray', 256)
plt.imshow(data, aspect='auto', cmap=viridis)
plt.tight_layout()
plt.savefig(out_file, bbox_inches='tight', transparent=True, pad_inches=0)
Runtime environment:
Python: 3.6.10
Matplotlib: 3.2.1
OS: Windows 10
Solution 10 - Python
I had the same problem while doing some visualization using librosa where I wanted to extract content of the plot without any other information. So this my approach. unutbu answer also helps me to make to work.
figure = plt.figure(figsize=(500, 600), dpi=1)
axis = plt.subplot(1, 1, 1)
plt.axis('off')
plt.tick_params(axis='both', left='off', top='off', right='off', bottom='off', labelleft='off', labeltop='off',
labelright='off', labelbottom='off')
# your code goes here. e.g: I used librosa function to draw a image
result = np.array(clip.feature_list['fft'].get_logamplitude()[0:2])
librosa.display.specshow(result, sr=api.Clip.RATE, x_axis='time', y_axis='mel', cmap='RdBu_r')
extent = axis.get_window_extent().transformed(figure.dpi_scale_trans.inverted())
plt.savefig((clip.filename + str("_.jpg")), format='jpg', bbox_inches=extent, pad_inches=0)
plt.close()
Solution 11 - Python
While the above answers address removing margins and padding, they did not work for me in removing labels. Here's what worked, for anyone who stumbles upon this question later:
Assuming you want a 2x2 grid of subplots from four images stored in images
:
matplotlib.pyplot.figure(figsize = (16,12)) # or whatever image size you require
for i in range(4):
ax = matplotlib.pyplot.subplot(2,2,i+1)
ax.axis('off')
imshow(images[i])
matplotlib.pyplot.savefig(path, bbox_inches='tight')
Solution 12 - Python
I tried to get rid of the border too, using tips here but nothing really worked. Some fiddling about and I found that changing the faceolor gave me no border in jupyter labs (Any color resulted in getting rid of the white border). Hope this helps.
def show_num(data):
data = np.rot90(data.reshape((16,16)), k=3)
data = np.fliplr(data)
fig = plt.figure(frameon=False, facecolor='white')
ax = plt.Axes(fig, [0., 0., 1., 1.])
ax.set_axis_off()
fig.add_axes(ax)
ax.imshow(data)
plt.show()