Setting the size of the plotting canvas in Matplotlib

40,547

Solution 1

This is one of my biggest frustrations with Matplotlib. I often work with raster data where for example i want to add a colormap, legend and some title. Any simple example from the matplotlib gallery doing so will result in a different resolution and therefore resampled data. Especially when doing image analysis you dont want any (unwanted) resampling.

Here is what i usually do, although i would love to know if there are simpler or better ways.

Lets start with loading a picture and outputting it just as it is with the same resolution:

import matplotlib.pyplot as plt
import urllib2

# load the image
img = plt.imread(urllib2.urlopen('http://upload.wikimedia.org/wikipedia/en/thumb/5/56/Matplotlib_logo.svg/500px-Matplotlib_logo.svg.png'))

# get the dimensions
ypixels, xpixels, bands = img.shape

# get the size in inches
dpi = 72.
xinch = xpixels / dpi
yinch = ypixels / dpi

# plot and save in the same size as the original
fig = plt.figure(figsize=(xinch,yinch))

ax = plt.axes([0., 0., 1., 1.], frameon=False, xticks=[],yticks=[])
ax.imshow(img, interpolation='none')

plt.savefig('D:\\mpl_logo.png', dpi=dpi, transparent=True)

Note that i manually defined the axes position so that spans the entire figure.

In a similar way as above you could add some margin around the image to allow for labels or colorbars etc.

This example adds a 20% margin above the image, which is then used for plotting a title:

fig = plt.figure(figsize=(xinch,yinch/.8))

ax = plt.axes([0., 0., 1., .8], frameon=False, xticks=[],yticks=[])
ax.imshow(img, interpolation='none')
ax.set_title('Matplotlib is fun!', size=16, weight='bold')

plt.savefig('D:\\mpl_logo_with_title.png', dpi=dpi)

So the figure y-size (height) is increased and the y-size of the axes is decreased equally. This gives a larger (overall) output image, but the axes area will still be the same size.

It might be nice the have a figure or axes property like .set_scale() to force a true 1-on-x output.

Solution 2

You can specify the following settings in Matplotlib rc:

import matplotlib
matplotlib.rcParams['figure.figsize'] = [10, 10] # for square canvas
matplotlib.rcParams['figure.subplot.left'] = 0
matplotlib.rcParams['figure.subplot.bottom'] = 0
matplotlib.rcParams['figure.subplot.right'] = 1
matplotlib.rcParams['figure.subplot.top'] = 1
Share:
40,547
Dario
Author by

Dario

Updated on July 09, 2022

Comments

  • Dario
    Dario almost 2 years

    I would like Matplotlib/Pyplot to generate plots with a consistent canvas size. That is, the figures can well have different sizes to accomodate the axis descriptions, but the plotting area (the rectangle within which the curves are drawn) should always have the same size.

    Is there a simple way to achieve that? The option figsize of pyplot.figure() seems to set the overall size of the figure, not that of the canvas, so I get a different canvas size whenever the axis description occupies more or less space.

  • tacaswell
    tacaswell about 11 years
    Can you use some vector format instead? It should (I think) draw each pixel as a rectangle. Or just way over sample.
  • Dario
    Dario about 11 years
    Thank you, your suggestion worked! By the way, I think I did find a slightly more elegant way using subplot_adjust(0,0,1,1) immediately after calling figure(). Then, you don't need to define the axes positions because they are already as big as the figure. Finally, you can call savefig() with the argument bbox_inches='tight' if you don't want to manually specify the margins. In this case, the plotting area will be exactly as defined by (xinch,yinch) and the figure will be large enough to accomodate the axis descriptions. (As pointed out by tcaswell, do not use tight_layout!)
  • Rutger Kassies
    Rutger Kassies about 11 years
    That sounds easier indeed, thanks for the tips. I'll try your suggestions later. @tcaswell, thanks, that might work in some situations, i think pcolor should be able to do that quite easily. Any other post-processing would be more difficult though.
  • tacaswell
    tacaswell about 11 years
    @Dario If you do that, then you have pushed all of your axis labels off. If you are doing raster images, you might do better using PIL to just save the images.
  • Dario
    Dario about 11 years
    @tcaswell It pushes to labels off, but you get them back if you call savefig(bbox_inches='tight'). Or am I missing your point?
  • tacaswell
    tacaswell about 11 years
    @Dario That is a terrifying abuse of the system. Does this work on every backend?