Setting the size of the plotting canvas in Matplotlib
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
Dario
Updated on July 09, 2022Comments
-
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 about 11 yearsCan you use some vector format instead? It should (I think) draw each pixel as a rectangle. Or just way over sample.
-
Dario about 11 yearsThank 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 about 11 yearsThat 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 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 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 about 11 years@Dario That is a terrifying abuse of the system. Does this work on every backend?