Save only line without axes, labels and padding in matplotlib - python

I would like to save matplotlib line chart to transparent png image with aspect ratio 3:1 and without axes or labels. I need the line of the graph to start and end directly at the edge of the image (without any padding).
I found several similar topics, e. g. tight savefig without axes in matplotlib or Removing white space around a saved image in matplotlib, however neither advice helped.
Here is my code:
import matplotlib.pyplot as plt
x = np.arange(1, 10)
y = np.arange(51, 60)
plt.gca().set_axis_off()
plt.subplots_adjust(top=1, bottom=0, right=1, left=0, hspace=0, wspace=0)
plt.margins(0, 0)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
fig = plt.figure(figsize=(9,3))
ax = fig.add_axes([0, 0, 1, 1], frameon=False)
ax.set_axis_off()
ax.plot(x, y)
# plt.savefig("result.png", format="png", transparent=True, `bbox_inches="tight", pad_inches=0) # Result image is empty.
plt.savefig("result.png", format="png", transparent=True)
plt.show()
Still, there is some padding in result image (there is white background to show padding, but in fact image is transparent):
Is there any way to achieve chart with no padding?

Here is a solution based on one of the question you added:
import matplotlib.pyplot as plt
import numpy as np
import os
x = np.arange(1, 10)
y = np.arange(51, 60)
plt.figure(figsize=(9,3))
plt.plot(x,y)
plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0,
hspace = 0, wspace = 0)
plt.margins(0,0)
plt.savefig("myfig.png")
#os.system('convert myfig.png -trim myfig.png') #<- a quick workaround if you are on mac or Linux.
plt.show()
Output:

Related

Constrain axis dimensions to those of another axis

I've got code that produces a square image with smaller plots to the left and below the main image plot by using GridSpec with width_ratios and height_ratios:
import matplotlib.pyplot as plt
import numpy as np
# Some fake data.
imdata = np.random.random((100, 100))
extradata1 = np.max(imdata, axis=1)
extradata2 = np.max(imdata, axis=0)
fig = plt.figure(constrained_layout=True)
spec = fig.add_gridspec(ncols=2, nrows=2, width_ratios=(1, 8), height_ratios=(8, 1))
# Main image plot.
ax1 = fig.add_subplot(spec[:-1, 1:], aspect='equal')
ax1.imshow(imdata, cmap='viridis')
# Vertical (left) plot.
ax2 = fig.add_subplot(spec[:-1, 0], sharey=ax1)
ax2.plot(extradata1, range(imdata.shape[0]))
# Horizontal (bottom) plot.
ax3 = fig.add_subplot(spec[-1, 1:], sharex=ax1)
ax3.plot(range(imdata.shape[1]), extradata2)
plt.show()
I'd like the height of the left plot and the width of the bottom plot to be equal to the height and width of the main image, respectively. Currently as you can see the horizontal plot is wider than the image's horizontal size, and they also scale differently as the figure is scaled. Is it possible to constrain axis dimensions to those of other axes?
Calling imshow() with aspect='auto' should fix your problem:
ax1.imshow(imdata, cmap='viridis',aspect='auto')
For some more explanation on this, please look here:
Imshow: extent and aspect
import matplotlib.pyplot as plt
import numpy as np
# Some fake data.
imdata = np.random.random((100, 100))
extradata1 = np.max(imdata, axis=1)
extradata2 = np.max(imdata, axis=0)
fig = plt.figure(constrained_layout=True)
spec = fig.add_gridspec(ncols=2, nrows=2, width_ratios=(1, 8), height_ratios=(8, 1))
# Main image plot.
ax1 = fig.add_subplot(spec[:-1, 1:])
ax1.imshow(imdata, cmap='viridis',aspect='auto')
# Vertical (left) plot.
ax2 = fig.add_subplot(spec[:-1, 0], sharey=ax1)
ax2.plot(extradata1, range(imdata.shape[0]))
# Horizontal (bottom) plot.
ax3 = fig.add_subplot(spec[-1, 1:], sharex=ax1)
ax3.plot(range(imdata.shape[1]), extradata2)
Result:
Fourier's answer worked nicely, but I also found that I could get the desired behaviour by changing constrained_layout=True to constrained_layout=False in the plt.figure call.
Using aspect aspect="auto" works, it has the disadvantage of giving you non-square pixels.
For this kind of tasks, I found that the axes_grid toolkit is pretty useful
from mpl_toolkits.axes_grid1 import make_axes_locatable
# Some fake data.
imdata = np.random.random((100, 100))
extradata1 = np.max(imdata, axis=1)
extradata2 = np.max(imdata, axis=0)
fig, main_ax = plt.subplots()
divider = make_axes_locatable(main_ax)
bottom_ax = divider.append_axes("bottom", 1.2, pad=0.1, sharex=main_ax)
left_ax = divider.append_axes("left", 1.2, pad=0.1, sharey=main_ax)
bottom_ax.xaxis.set_tick_params(labelbottom=False)
left_ax.yaxis.set_tick_params(labelleft=False)
main_ax.imshow(imdata, cmap='viridis')
left_ax.plot(extradata1, range(imdata.shape[0]))
bottom_ax.plot(range(imdata.shape[1]), extradata2)
plt.show()

matplotlib ax to figure extent - remove whitespace, borders, everything for plot of geopandas map

I am looking for a solution to have a seamless map image plot with matplotlib. The current code works good and stable, however, it leaves a whitespace to the left and bottom. I would like to remove this whitespace and don't know how.
My sample code for this:
import geopandas
from seaborn import despine
from pandas import read_csv
import matplotlib.pyplot as plt
# read data and shapefile
geo_path = 'shapefiles/ne_10m_admin_0_countries.shp'
df = read_csv('UNpopEstimates2100.csv')
world = geopandas.read_file(geo_path)
# specifiy what is to be plotted
cm = 'Greys'
world['2015'] = df['2015']
# set plot environment
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')
plt.subplots_adjust(left=0, right=1, bottom=0, top=1)
world.plot(ax=ax, column='2015', cmap=cm, scheme='quantiles')
plt.savefig('sample.png', bbox_inches='tight', tight_layout=True, pad_inches=0, frameon=None)
sample.png
smaple.png with marked whitespace I would like to remove
I followed the Tutorial at Matplotlib's Tight Layout guide, machinelearningplus.com, Removing white padding from figure on Reddit as well as several other stackoverflow posts, namely
Matplotlib scatter plot - Remove white padding,
Matplotlib: Getting subplots to fill figure,
Matplotlib plots: removing axis, legends and white spaces,
Removing white space around a saved image in matplotlib
and
matplotlib plot to fill figure only with data points, no borders, labels, axes,
What am I missing?
edit
- to provide a reproducable version with non-real-life data, but question stays the same - how do I get rid of the whitespace around my plot?
I am new to Geopandas, so I am not sure how to recreate a geodataframe, however, there is built in datasets with it.
world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))
world['2015'] = np.random.uniform(low=1., high=100., size=(177,))
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')
plt.subplots_adjust(left=0, right=1, bottom=0, top=1)
world.plot(ax=ax, column='2015', scheme='quantiles')
plt.savefig('sample.png')
First there is a difference when using different geopandas versions. One should probably make sure to use geopandas 0.4 at least to have the map in the correct aspect ratio.
Next one needs to remove the padding inside the axes. This can be done using the ax.margins(0) command.
Now this would lead to some whitespace in one direction (top and bottom in this case). One option is to shrink the figure to the extent of the axes.
import numpy as np
import matplotlib; print(matplotlib.__version__)
import matplotlib.pyplot as plt
import geopandas; print(geopandas.__version__)
world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))
world['2015'] = np.random.uniform(low=1., high=100., size=(177,))
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')
world.plot(ax=ax, column='2015', scheme='quantiles')
ax.margins(0)
ax.apply_aspect()
bbox = ax.get_window_extent().inverse_transformed(fig.transFigure)
w,h = fig.get_size_inches()
fig.set_size_inches(w*bbox.width, h*bbox.height)
plt.savefig('sample.png')
plt.show()
The advantage of this is that the physical size of the figure really fits the axes; so the result is the same whether shown on screen or saved as image.
If instead the aim is to just save the figure without whitespace you can use the bbox_inches argument to savefig and supply the actual extent of the axes in inches.
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')
world.plot(ax=ax, column='2015', scheme='quantiles')
ax.margins(0)
ax.apply_aspect()
bbox = ax.get_window_extent().inverse_transformed(fig.dpi_scale_trans)
plt.savefig('sample.png', bbox_inches=bbox)
Finally, the above can be automated, using bbox_inches='tight'. However, for the 'tight' option to work correctly, one will need to make sure there are no ticks and labels around the axes, which would otherwise increase the spacing.
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ax.axis('off')
world.plot(ax=ax, column='2015', scheme='quantiles')
ax.margins(0)
ax.tick_params(left=False, labelleft=False, bottom=False, labelbottom=False)
plt.savefig('sample.png', bbox_inches="tight", pad_inches=0)
In all three cases above, the resulting figure would be

Generate spectrograms with equal height in pixels and their aspect ratio kept intact with matplotlib? [duplicate]

I need to take an image and save it after some process. The figure looks fine when I display it, but after saving the figure, I got some white space around the saved image. I have tried the 'tight' option for savefig method, did not work either. The code:
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
fig = plt.figure(1)
img = mpimg.imread("image.jpg")
plt.imshow(img)
ax = fig.add_subplot(1, 1, 1)
extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig('1.png', bbox_inches=extent)
plt.axis('off')
plt.show()
I am trying to draw a basic graph by using NetworkX on a figure and save it. I realized that without a graph it works, but when added a graph I get white space around the saved image;
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import networkx as nx
G = nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_edge(1, 3)
G.add_edge(1, 2)
pos = {1:[100, 120], 2:[200, 300], 3:[50, 75]}
fig = plt.figure(1)
img = mpimg.imread("image.jpg")
plt.imshow(img)
ax = fig.add_subplot(1, 1, 1)
nx.draw(G, pos=pos)
extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig('1.png', bbox_inches=extent)
plt.axis('off')
plt.show()
You can remove the white space padding by setting bbox_inches="tight" in savefig:
plt.savefig("test.png",bbox_inches='tight')
You'll have to put the argument to bbox_inches as a string, perhaps this is why it didn't work earlier for you.
Possible duplicates:
Matplotlib plots: removing axis, legends and white spaces
How to set the margins for a matplotlib figure?
Reduce left and right margins in matplotlib plot
I cannot claim I know exactly why or how my “solution” works, but this is what I had to do when I wanted to plot the outline of a couple of aerofoil sections — without white margins — to a PDF file.
(Note that I used matplotlib inside an IPython notebook, with the -pylab flag.)
plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0,
hspace = 0, wspace = 0)
plt.margins(0,0)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.savefig("filename.pdf", bbox_inches = 'tight',
pad_inches = 0)
I have tried to deactivate different parts of this, but this always lead to a white margin somewhere. You may even have modify this to keep fat lines near the limits of the figure from being shaved by the lack of margins.
After trying the above answers with no success (and a slew of other stack posts) what finally worked for me was just
plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0,
hspace = 0, wspace = 0)
plt.margins(0,0)
plt.savefig("myfig.pdf")
Importantly this does not include the bbox or padding arguments.
I found something from Arvind Pereira (http://robotics.usc.edu/~ampereir/wordpress/?p=626) and seemed to work for me:
plt.savefig(filename, transparent = True, bbox_inches = 'tight', pad_inches = 0)
The following function incorporates johannes-s answer above. I have tested it with plt.figure and plt.subplots() with multiple axes, and it works nicely.
def save(filepath, fig=None):
'''Save the current image with no whitespace
Example filepath: "myfig.png" or r"C:\myfig.pdf"
'''
import matplotlib.pyplot as plt
if not fig:
fig = plt.gcf()
plt.subplots_adjust(0,0,1,1,0,0)
for ax in fig.axes:
ax.axis('off')
ax.margins(0,0)
ax.xaxis.set_major_locator(plt.NullLocator())
ax.yaxis.set_major_locator(plt.NullLocator())
fig.savefig(filepath, pad_inches = 0, bbox_inches='tight')
The most straightforward method is to use plt.tight_layout transformation which is actually more preferable as it doesn't do unnecessary cropping when using plt.savefig
import matplotlib as plt
plt.plot([1,2,3], [1,2,3])
plt.tight_layout(pad=0)
plt.savefig('plot.png')
However, this may not be preferable for complex plots that modifies the figure. Refer to Johannes S's answer that uses plt.subplots_adjust if that's the case.
I found the following codes work perfectly for the job.
fig = plt.figure(figsize=[6,6])
ax = fig.add_subplot(111)
ax.imshow(data)
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
ax.set_frame_on(False)
plt.savefig('data.png', dpi=400, bbox_inches='tight',pad_inches=0)
This worked for me
plt.savefig(save_path,bbox_inches='tight', pad_inches=0, transparent=True)
i followed this sequence and it worked like a charm.
plt.axis("off")
fig=plt.imshow(image array,interpolation='nearest')
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.savefig('destination_path.pdf',
bbox_inches='tight', pad_inches=0, format='pdf', dpi=1200)
A much simpler approach I found is to use plt.imsave :
import matplotlib.pyplot as plt
arr = plt.imread(path)
plt.imsave('test.png', arr)
For anyone who wants to work in pixels rather than inches this will work.
Plus the usual you will also need
from matplotlib.transforms import Bbox
Then you can use the following:
my_dpi = 100 # Good default - doesn't really matter
# Size of output in pixels
h = 224
w = 224
fig, ax = plt.subplots(1, figsize=(w/my_dpi, h/my_dpi), dpi=my_dpi)
ax.set_position([0, 0, 1, 1]) # Critical!
# Do some stuff
ax.imshow(img)
ax.imshow(heatmap) # 4-channel RGBA
ax.plot([50, 100, 150], [50, 100, 150], color="red")
ax.axis("off")
fig.savefig("saved_img.png",
bbox_inches=Bbox([[0, 0], [w/my_dpi, h/my_dpi]]),
dpi=my_dpi)
So the solution depend on whether you adjust the subplot. If you specify plt.subplots_adjust (top, bottom, right, left), you don't want to use the kwargs of bbox_inches='tight' with plt.savefig, as it paradoxically creates whitespace padding. It also allows you to save the image as the same dims as the input image (600x600 input image saves as 600x600 pixel output image).
If you don't care about the output image size consistency, you can omit the plt.subplots_adjust attributes and just use the bbox_inches='tight' and pad_inches=0 kwargs with plt.savefig.
This solution works for matplotlib versions 3.0.1, 3.0.3 and 3.2.1. It also works when you have more than 1 subplot (eg. plt.subplots(2,2,...).
def save_inp_as_output(_img, c_name, dpi=100):
h, w, _ = _img.shape
fig, axes = plt.subplots(figsize=(h/dpi, w/dpi))
fig.subplots_adjust(top=1.0, bottom=0, right=1.0, left=0, hspace=0, wspace=0)
axes.imshow(_img)
axes.axis('off')
plt.savefig(c_name, dpi=dpi, format='jpeg')
You may try this. It solved my issue.
import matplotlib.image as mpimg
img = mpimg.imread("src.png")
mpimg.imsave("out.png", img, cmap=cmap)
In a Jupyter notebook, one can add this line:
%config InlineBackend.print_figure_kwargs = {'pad_inches':0}
Here is a minimal example
import matplotlib.pyplot as plt
import numpy as np
%config InlineBackend.print_figure_kwargs = {'pad_inches':0}
fig, ax = plt.subplots()
ax.axis("off")
ax.imshow(np.fromfunction(lambda i, j: np.sin(j), (15, 15)), cmap="YlGnBu")
This works for me saving a numpy array plotted with imshow to file
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10,10))
plt.imshow(img) # your image here
plt.axis("off")
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0,
hspace = 0, wspace = 0)
plt.savefig("example2.png", box_inches='tight', dpi=100)
plt.show()

Plotting a cropped background image on a matplotlib graph

I'm trying to plot a simple line plot and insert a background image to a plot.
An example pic (with cat.jpg and dog.jpd):
At the moment I have a code that plots the line (from a pandas dataframe) and places the images into figure. However the images and the line plot do not 'interact' at all.
fig, ax = plt.subplots(figsize=(15,10))
cat = np.array(Image.open('cat.jpg'))
dog = np.array(Image.open('dog.jpg'))
ax.imshow(cat, extent=[0, 10, 0, 18], aspect='auto', cmap='gray',alpha=0.75)
ax.imshow(dog, extent=[10, 20, 0, 18], aspect='auto', cmap='gray',alpha=0.75)
ax.plot(df['Series'],color='#3cb8fb',alpha=0.95,linewidth=3.0)
plt.show()
You can use plt.fill_between to create a polygon that covers the area between the origin and the line, then use the .set_clip_path method of each image object to display only the part of the image that falls within the polygon.
For example:
from matplotlib import pyplot as plt
from scipy.misc import lena
fig, ax = plt.subplots(1, 1)
x = np.linspace(0, 1, 10)
y = np.random.rand(10)
image = ax.imshow(lena(), cmap=plt.cm.gray, extent=[0, 1, 0, 1])
line = ax.plot(x, y, '-r', lw=2)
# invisible clipping polygon
poly = ax.fill_between(x, 0, y, visible=False)
clip = poly.get_paths()[0]
# you will need to do this separately for each of the images in your plot
image.set_clip_path(clip, transform=ax.transData)
plt.show()

Removing white space around a saved image

I need to take an image and save it after some process. The figure looks fine when I display it, but after saving the figure, I got some white space around the saved image. I have tried the 'tight' option for savefig method, did not work either. The code:
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
fig = plt.figure(1)
img = mpimg.imread("image.jpg")
plt.imshow(img)
ax = fig.add_subplot(1, 1, 1)
extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig('1.png', bbox_inches=extent)
plt.axis('off')
plt.show()
I am trying to draw a basic graph by using NetworkX on a figure and save it. I realized that without a graph it works, but when added a graph I get white space around the saved image;
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import networkx as nx
G = nx.Graph()
G.add_node(1)
G.add_node(2)
G.add_node(3)
G.add_edge(1, 3)
G.add_edge(1, 2)
pos = {1:[100, 120], 2:[200, 300], 3:[50, 75]}
fig = plt.figure(1)
img = mpimg.imread("image.jpg")
plt.imshow(img)
ax = fig.add_subplot(1, 1, 1)
nx.draw(G, pos=pos)
extent = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted())
plt.savefig('1.png', bbox_inches=extent)
plt.axis('off')
plt.show()
You can remove the white space padding by setting bbox_inches="tight" in savefig:
plt.savefig("test.png",bbox_inches='tight')
You'll have to put the argument to bbox_inches as a string, perhaps this is why it didn't work earlier for you.
Possible duplicates:
Matplotlib plots: removing axis, legends and white spaces
How to set the margins for a matplotlib figure?
Reduce left and right margins in matplotlib plot
I cannot claim I know exactly why or how my “solution” works, but this is what I had to do when I wanted to plot the outline of a couple of aerofoil sections — without white margins — to a PDF file.
(Note that I used matplotlib inside an IPython notebook, with the -pylab flag.)
plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0,
hspace = 0, wspace = 0)
plt.margins(0,0)
plt.gca().xaxis.set_major_locator(plt.NullLocator())
plt.gca().yaxis.set_major_locator(plt.NullLocator())
plt.savefig("filename.pdf", bbox_inches = 'tight',
pad_inches = 0)
I have tried to deactivate different parts of this, but this always lead to a white margin somewhere. You may even have modify this to keep fat lines near the limits of the figure from being shaved by the lack of margins.
After trying the above answers with no success (and a slew of other stack posts) what finally worked for me was just
plt.gca().set_axis_off()
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0,
hspace = 0, wspace = 0)
plt.margins(0,0)
plt.savefig("myfig.pdf")
Importantly this does not include the bbox or padding arguments.
I found something from Arvind Pereira (http://robotics.usc.edu/~ampereir/wordpress/?p=626) and seemed to work for me:
plt.savefig(filename, transparent = True, bbox_inches = 'tight', pad_inches = 0)
The following function incorporates johannes-s answer above. I have tested it with plt.figure and plt.subplots() with multiple axes, and it works nicely.
def save(filepath, fig=None):
'''Save the current image with no whitespace
Example filepath: "myfig.png" or r"C:\myfig.pdf"
'''
import matplotlib.pyplot as plt
if not fig:
fig = plt.gcf()
plt.subplots_adjust(0,0,1,1,0,0)
for ax in fig.axes:
ax.axis('off')
ax.margins(0,0)
ax.xaxis.set_major_locator(plt.NullLocator())
ax.yaxis.set_major_locator(plt.NullLocator())
fig.savefig(filepath, pad_inches = 0, bbox_inches='tight')
The most straightforward method is to use plt.tight_layout transformation which is actually more preferable as it doesn't do unnecessary cropping when using plt.savefig
import matplotlib as plt
plt.plot([1,2,3], [1,2,3])
plt.tight_layout(pad=0)
plt.savefig('plot.png')
However, this may not be preferable for complex plots that modifies the figure. Refer to Johannes S's answer that uses plt.subplots_adjust if that's the case.
I found the following codes work perfectly for the job.
fig = plt.figure(figsize=[6,6])
ax = fig.add_subplot(111)
ax.imshow(data)
ax.axes.get_xaxis().set_visible(False)
ax.axes.get_yaxis().set_visible(False)
ax.set_frame_on(False)
plt.savefig('data.png', dpi=400, bbox_inches='tight',pad_inches=0)
This worked for me
plt.savefig(save_path,bbox_inches='tight', pad_inches=0, transparent=True)
i followed this sequence and it worked like a charm.
plt.axis("off")
fig=plt.imshow(image array,interpolation='nearest')
fig.axes.get_xaxis().set_visible(False)
fig.axes.get_yaxis().set_visible(False)
plt.savefig('destination_path.pdf',
bbox_inches='tight', pad_inches=0, format='pdf', dpi=1200)
A much simpler approach I found is to use plt.imsave :
import matplotlib.pyplot as plt
arr = plt.imread(path)
plt.imsave('test.png', arr)
For anyone who wants to work in pixels rather than inches this will work.
Plus the usual you will also need
from matplotlib.transforms import Bbox
Then you can use the following:
my_dpi = 100 # Good default - doesn't really matter
# Size of output in pixels
h = 224
w = 224
fig, ax = plt.subplots(1, figsize=(w/my_dpi, h/my_dpi), dpi=my_dpi)
ax.set_position([0, 0, 1, 1]) # Critical!
# Do some stuff
ax.imshow(img)
ax.imshow(heatmap) # 4-channel RGBA
ax.plot([50, 100, 150], [50, 100, 150], color="red")
ax.axis("off")
fig.savefig("saved_img.png",
bbox_inches=Bbox([[0, 0], [w/my_dpi, h/my_dpi]]),
dpi=my_dpi)
So the solution depend on whether you adjust the subplot. If you specify plt.subplots_adjust (top, bottom, right, left), you don't want to use the kwargs of bbox_inches='tight' with plt.savefig, as it paradoxically creates whitespace padding. It also allows you to save the image as the same dims as the input image (600x600 input image saves as 600x600 pixel output image).
If you don't care about the output image size consistency, you can omit the plt.subplots_adjust attributes and just use the bbox_inches='tight' and pad_inches=0 kwargs with plt.savefig.
This solution works for matplotlib versions 3.0.1, 3.0.3 and 3.2.1. It also works when you have more than 1 subplot (eg. plt.subplots(2,2,...).
def save_inp_as_output(_img, c_name, dpi=100):
h, w, _ = _img.shape
fig, axes = plt.subplots(figsize=(h/dpi, w/dpi))
fig.subplots_adjust(top=1.0, bottom=0, right=1.0, left=0, hspace=0, wspace=0)
axes.imshow(_img)
axes.axis('off')
plt.savefig(c_name, dpi=dpi, format='jpeg')
You may try this. It solved my issue.
import matplotlib.image as mpimg
img = mpimg.imread("src.png")
mpimg.imsave("out.png", img, cmap=cmap)
In a Jupyter notebook, one can add this line:
%config InlineBackend.print_figure_kwargs = {'pad_inches':0}
Here is a minimal example
import matplotlib.pyplot as plt
import numpy as np
%config InlineBackend.print_figure_kwargs = {'pad_inches':0}
fig, ax = plt.subplots()
ax.axis("off")
ax.imshow(np.fromfunction(lambda i, j: np.sin(j), (15, 15)), cmap="YlGnBu")
This works for me saving a numpy array plotted with imshow to file
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(10,10))
plt.imshow(img) # your image here
plt.axis("off")
plt.subplots_adjust(top = 1, bottom = 0, right = 1, left = 0,
hspace = 0, wspace = 0)
plt.savefig("example2.png", box_inches='tight', dpi=100)
plt.show()

Categories