Differences between revisions 4 and 5

Deletions are marked like this. Additions are marked like this.
Line 5: Line 5:
 * Size in length units (inches, cm, pt, etc): i.e. 5"x7"
 * Size in pixels: i.e. 800x600 pixels
 * Dots per inch (dpi) i.e. 100 dpi
 * Size in length units (inches, cm, pt, etc): e.g. 5"x7"
 * Size in pixels: e.g. 800x600 pixels
 * Dots per inch (dpi) e.g. 100 dpi

This is a small demo file that helps teach how to adjust figure sizes for matplotlib

First a little introduction

There are three parameters define an image size (this is not MPL specific):

  • Size in length units (inches, cm, pt, etc): e.g. 5"x7"
  • Size in pixels: e.g. 800x600 pixels
  • Dots per inch (dpi) e.g. 100 dpi

Only two of these are independent, so if you define two of them, the third can be calculated from the others.

When displaying on a computer screen (or saved to a PNG), the size in length units is irrelevant, the pixels are simply displayed. When printed, or saved to PS, EPS or PDF (all designed to support printing), then the Size or dpi is used to determine how to scale the image.

Now I'm getting into how MPL works

  • 1) The size of a figure is defined in length units (inches), and can be set by Figure.set_figsize_inches( (w,h) )

  • 2) The layout of the figure is defined in 'figure units' so that as the figure size is changed, the layout (eg axes positions) will update.
  • 3) Size of text, width of lines, etc is defined in terms of length units (points?).
  • 4) When displaying to the screen, or creating an image (PNG) the pixel size of text and line widths, etc is determined by the dpi setting, which is set by Figure.set_dpi( val )

The trick here is that when printing, it's natural to think in terms of inches, but when creating an image (for a web page, for instance), it is natural to think in terms of pixel size. However, as of 0.84, pixel size can only be set directly in the GTK* back-ends, with the canvas.resize(w,h) method. (remember that you can only set two of the three size parameters, the third must be calculated from the other two).

Another trick

Figure.savefig() overrides the dpi setting in figure, and uses a default (which on my system at least is 100 dpi). If you want to overide it, you can specify the 'dpi' in the savefig call: Figure.savefig(filename, dpi=value)

The following code will hopefully make this more clear, at least for generating PNGs for web pages and the like.

MPL_size_test.py

   1 
   2 """
   3 This is a small demo file that helps teach how to adjust figure sizes
   4 for matplotlib
   5 
   6 """
   7 
   8 import matplotlib
   9 print "using MPL version:", matplotlib.__version__
  10 matplotlib.use("WXAgg") # do this before pylab so you don'tget the default back end.
  11 
  12 import pylab
  13 import matplotlib.numerix as N
  14 
  15 # Generate and plot some simple data:
  16 x = N.arange(0, 2*N.pi, 0.1)
  17 y = N.sin(x)
  18 
  19 pylab.plot(x,y)
  20 F = pylab.gcf()
  21 
  22 # Now check everything with the defaults:
  23 DPI = F.get_dpi()
  24 print "DPI:", DPI
  25 DefaultSize = F.get_size_inches()
  26 print "Default size in Inches", DefaultSize
  27 print "Which should result in a %i x %i Image"%(DPI*DefaultSize[0], DPI*DefaultSize[1])
  28 # the default is 100dpi for savefig:
  29 F.savefig("test1.png")
  30 # this gives me a 797 x 566 pixel image, which is about 100 DPI
  31 
  32 # Now make the image twice as big, while keeping the fonts and all the
  33 # same size
  34 F.set_figsize_inches( (DefaultSize[0]*2, DefaultSize[1]*2) )
  35 Size = F.get_size_inches()
  36 print "Size in Inches", Size
  37 F.savefig("test2.png")
  38 # this results in a 1595x1132 image
  39 
  40 # Now make the image twice as big, making all the fonts and lines
  41 # bigger too.
  42 
  43 F.set_figsize_inches( DefaultSize )# resetthe size
  44 Size = F.get_size_inches()
  45 print "Size in Inches", Size
  46 F.savefig("test3.png", dpi = (200)) # change the dpi
  47 # this also results in a 1595x1132 image, but the fonts are larger.

Putting more than one image in a figure

Suppose you have two images: 100x100 and 100x50 that you want to display in a figure with a buffer of 20 pixels (relative to image pixels) between them and a border of 10 pixels all around.

The solution isn't particularly object oriented, but at least it gets to the practical details.

   1 def _calcsize(matrix1, matrix2, top=10, left=10, right=10, bottom=10, buffer=20, height=4, scale = 1.):
   2    size1 = array(matrix1.shape) * scale
   3    size2 = array(matrix2.shape) * scale
   4    _width = float(size1[1] + size2[1] + left + right + buffer)
   5    _height = float(max(size1[0], size2[0]) + top + bottom)
   6    x1 = left / _width
   7    y1 = bottom / _height
   8    dx1 = size1[1] / _width
   9    dy1 = size1[0] / _height
  10    size1 = (x1, y1, dx1, dy1)
  11    x2 = (size1[1] + left + buffer) / _width
  12    y2 = bottom / _height
  13    dx2 = size2[1] / _width
  14    dy2 = size2[0] / _height
  15    size2 = (x2, y2, dx2, dy2)
  16    figure = pylab.figure(figsize=(_width * height / _height, height))
  17    axis1 = apply(pylab.axes, size1)
  18    pylab.imshow(X1, aspect='preserve')
  19    axis2 = apply(pylab.axes, size2)
  20    pylab.imshow(X2, aspect='preserve')
  21    return axes1, axes2, figure


Cookbook/Matplotlib/AdjustingImageSize (last edited 2011-09-23 20:47:35 by TimSwast)