Specifying and saving a figure with exact size in pixels Specifying and saving a figure with exact size in pixels python python

Specifying and saving a figure with exact size in pixels


Matplotlib doesn't work with pixels directly, but rather physical sizes and DPI. If you want to display a figure with a certain pixel size, you need to know the DPI of your monitor. For example this link will detect that for you.

If you have an image of 3841x7195 pixels it is unlikely that you monitor will be that large, so you won't be able to show a figure of that size (matplotlib requires the figure to fit in the screen, if you ask for a size too large it will shrink to the screen size). Let's imagine you want an 800x800 pixel image just for an example. Here's how to show an 800x800 pixel image in my monitor (my_dpi=96):

plt.figure(figsize=(800/my_dpi, 800/my_dpi), dpi=my_dpi)

So you basically just divide the dimensions in inches by your DPI.

If you want to save a figure of a specific size, then it is a different matter. Screen DPIs are not so important anymore (unless you ask for a figure that won't fit in the screen). Using the same example of the 800x800 pixel figure, we can save it in different resolutions using the dpi keyword of savefig. To save it in the same resolution as the screen just use the same dpi:

plt.savefig('my_fig.png', dpi=my_dpi)

To to save it as an 8000x8000 pixel image, use a dpi 10 times larger:

plt.savefig('my_fig.png', dpi=my_dpi * 10)

Note that the setting of the DPI is not supported by all backends. Here, the PNG backend is used, but the pdf and ps backends will implement the size differently. Also, changing the DPI and sizes will also affect things like fontsize. A larger DPI will keep the same relative sizes of fonts and elements, but if you want smaller fonts for a larger figure you need to increase the physical size instead of the DPI.

Getting back to your example, if you want to save a image with 3841 x 7195 pixels, you could do the following:

plt.figure(figsize=(3.841, 7.195), dpi=100)( your code ...)plt.savefig('myfig.png', dpi=1000)

Note that I used the figure dpi of 100 to fit in most screens, but saved with dpi=1000 to achieve the required resolution. In my system this produces a png with 3840x7190 pixels -- it seems that the DPI saved is always 0.02 pixels/inch smaller than the selected value, which will have a (small) effect on large image sizes. Some more discussion of this here.


This worked for me, based on your code, generating a 93Mb png image with color noise and the desired dimensions:

import matplotlib.pyplot as pltimport numpyw = 7195h = 3841im_np = numpy.random.rand(h, w)fig = plt.figure(frameon=False)fig.set_size_inches(w,h)ax = plt.Axes(fig, [0., 0., 1., 1.])ax.set_axis_off()fig.add_axes(ax)ax.imshow(im_np, aspect='normal')fig.savefig('figure.png', dpi=1)

I am using the last PIP versions of the Python 2.7 libraries in Linux Mint 13.

Hope that helps!


The OP wants to preserve 1:1 pixel data. As an astronomer working with science images I cannot allow any interpolation of image data as it would introduce unknown and unpredictable noise or errors. For example, here is a snippet from a 480x480 image saved via pyplot.savefig():Detail of pixels which matplotlib resampled to be roughly 2x2, but notice the column of 1x2 pixels

You can see that most pixels were simply doubled (so a 1x1 pixel becomes 2x2) but some columns and rows became 1x2 or 2x1 per pixel which means the the original science data has been altered.

As hinted at by Alka, plt.imsave() which will achieve what the OP is asking for. Say you have image data stored in image array im, then one can do something like

plt.imsave(fname='my_image.png', arr=im, cmap='gray_r', format='png')

where the filename has the "png" extension in this example (but you must still specify the format with format='png' anyway as far as I can tell), the image array is arr, and we chose the inverted grayscale "gray_r" as the colormap. I usually add vmin and vmax to specify the dynamic range but these are optional.

The end result is a png file of exactly the same pixel dimensions as the im array.

Note: the OP specified no axes, etc. which is what this solution does exactly. If one wants to add axes, ticks, etc. my preferred approach is to do that on a separate plot, saving with transparent=True (PNG or PDF) then overlay the latter on the image. This guarantees you have kept the original pixels intact.