How do I change the size of figures drawn with Matplotlib?
Asked Answered
H

16

3206

How do I change the size of figure drawn with Matplotlib?

Homograph answered 1/12, 2008 at 21:24 Comment(1)
These questions are similar and may be of interest Specify figure size in centimeter in matplotlib and Specifying and saving a figure with exact size in pixelsNewmown
S
1894

figure tells you the call signature:

from matplotlib.pyplot import figure

figure(figsize=(8, 6), dpi=80)

figure(figsize=(1,1)) would create an inch-by-inch image, which would be 80-by-80 pixels unless you also give a different dpi argument.

Sardius answered 12/3, 2009 at 12:41 Comment(0)
G
1168

If you've already got the figure created, you can use figure.set_size_inches to adjust the figure size:

fig = matplotlib.pyplot.gcf()
fig.set_size_inches(18.5, 10.5)
fig.savefig('test2png.png', dpi=100)

To propagate the size change to an existing GUI window, add forward=True:

fig.set_size_inches(18.5, 10.5, forward=True)

Additionally as Erik Shilts mentioned in the comments you can also use figure.set_dpi to "[s]et the resolution of the figure in dots-per-inch"

fig.set_dpi(100)
Gust answered 29/11, 2010 at 17:30 Comment(0)
S
772

Using plt.rcParams

There is also this workaround in case you want to change the size without using the figure environment. So in case you are using plt.plot() for example, you can set a tuple with width and height.

import matplotlib.pyplot as plt
plt.rcParams["figure.figsize"] = (20,3)

This is very useful when you plot inline (e.g., with IPython Notebook). As asmaier noticed, it is preferable to not put this statement in the same cell of the imports statements.

To reset the global figure size back to default for subsequent plots:

plt.rcParams["figure.figsize"] = plt.rcParamsDefault["figure.figsize"]

Conversion to cm

The figsize tuple accepts inches, so if you want to set it in centimetres you have to divide them by 2.54. Have a look at this question.

Scotney answered 18/1, 2017 at 10:55 Comment(0)
H
440

Deprecation note:
As per the official Matplotlib guide, usage of the pylab module is no longer recommended. Please consider using the matplotlib.pyplot module instead, as described by this other answer.

The following seems to work:

from pylab import rcParams
rcParams['figure.figsize'] = 5, 10

This makes the figure's width 5 inches, and its height 10 inches.

The Figure class then uses this as the default value for one of its arguments.

Homograph answered 1/12, 2008 at 21:28 Comment(0)
D
213

In case you're looking for a way to change the figure size in Pandas, you could do:

df['some_column'].plot(figsize=(10, 5))

where df is a Pandas dataframe. Or, to use an existing figure or axes:

fig, ax = plt.subplots(figsize=(10, 5))
df['some_column'].plot(ax=ax)

If you want to change the default settings, you could do the following:

import matplotlib

matplotlib.rc('figure', figsize=(10, 5))

For more details, check out the docs: pd.DataFrame.plot.

Dwain answered 29/9, 2016 at 12:54 Comment(0)
G
90

The first link in Google for 'matplotlib figure size' is AdjustingImageSize (Google cache of the page).

Here's a test script from the above page. It creates test[1-3].png files of different sizes of the same image:

#!/usr/bin/env python
"""
This is a small demo file that helps teach how to adjust figure sizes
for matplotlib

"""

import matplotlib
print "using MPL version:", matplotlib.__version__
matplotlib.use("WXAgg") # do this before pylab so you don'tget the default back end.

import pylab
import numpy as np

# Generate and plot some simple data:
x = np.arange(0, 2*np.pi, 0.1)
y = np.sin(x)

pylab.plot(x,y)
F = pylab.gcf()

# Now check everything with the defaults:
DPI = F.get_dpi()
print "DPI:", DPI
DefaultSize = F.get_size_inches()
print "Default size in Inches", DefaultSize
print "Which should result in a %i x %i Image"%(DPI*DefaultSize[0], DPI*DefaultSize[1])
# the default is 100dpi for savefig:
F.savefig("test1.png")
# this gives me a 797 x 566 pixel image, which is about 100 DPI

# Now make the image twice as big, while keeping the fonts and all the
# same size
F.set_size_inches( (DefaultSize[0]*2, DefaultSize[1]*2) )
Size = F.get_size_inches()
print "Size in Inches", Size
F.savefig("test2.png")
# this results in a 1595x1132 image

# Now make the image twice as big, making all the fonts and lines
# bigger too.

F.set_size_inches( DefaultSize )# resetthe size
Size = F.get_size_inches()
print "Size in Inches", Size
F.savefig("test3.png", dpi = (200)) # change the dpi
# this also results in a 1595x1132 image, but the fonts are larger.

Output:

using MPL version: 0.98.1
DPI: 80
Default size in Inches [ 8.  6.]
Which should result in a 640 x 480 Image
Size in Inches [ 16.  12.]
Size in Inches [ 16.  12.]

Two notes:

  1. The module comments and the actual output differ.

  2. This answer allows easily to combine all three images in one image file to see the difference in sizes.

Glucosuria answered 2/12, 2008 at 16:1 Comment(0)
D
71

Adjust the figsize= parameter in matplotlib.pyplot.figure, which is similar to this answer, but uses the standard plt import alias, and doesn't directly import figure from the pyplot namespace.

import numpy as np
import matplotlib.pyplot as plt

N = 50
np.random.seed(2022)  # creates a repetitive sample data
x = np.random.rand(N)
y = np.random.rand(N)
area = np.pi * (15 * np.random.rand(N))**2

fig = plt.figure(figsize=(10, 10))
plt.scatter(x, y, s=area, alpha=0.5)
plt.show()

Without fig = plt.figure(figsize=(10, 10))

enter image description here

With fig = plt.figure(figsize=(10, 10))

enter image description here

Desiccator answered 14/3, 2014 at 8:22 Comment(0)
S
64

You can simply use (from matplotlib.figure.Figure):

fig.set_size_inches(width,height)

As of Matplotlib 2.0.0, changes to your canvas will be visible immediately, as the forward keyword defaults to True.

If you want to just change the width or height instead of both, you can use

fig.set_figwidth(val) or fig.set_figheight(val)

These will also immediately update your canvas, but only in Matplotlib 2.2.0 and newer.

For Older Versions

You need to specify forward=True explicitly in order to live-update your canvas in versions older than what is specified above. Note that the set_figwidth and set_figheight functions don’t support the forward parameter in versions older than Matplotlib 1.5.0.

Sanford answered 30/10, 2017 at 15:23 Comment(0)
I
43

This works well for me:

from matplotlib import pyplot as plt

F = plt.gcf()
Size = F.get_size_inches()
F.set_size_inches(Size[0]*2, Size[1]*2, forward=True) # Set forward to True to resize window along with plot in figure.
plt.show() # Or plt.imshow(z_array) if using an animation, where z_array is a matrix or NumPy array

This forum post might also help: Resizing figure windows

Issie answered 28/5, 2014 at 5:47 Comment(0)
M
37

Comparison of different approaches to set exact image sizes in pixels

This answer will focus on:

  • savefig: how to save to a file, not just show on screen
  • setting the size in pixels

Here is a quick comparison of some of the approaches I've tried with images showing what the give.

Summary of current status: things are messy, and I am not sure if it is a fundamental limitation, or if the use case just didn't get enough attention from developers. I couldn't easily find an upstream discussion about this.

Baseline example without trying to set the image dimensions

Just to have a comparison point:

base.py

#!/usr/bin/env python3

import sys

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

fig, ax = plt.subplots()
print('fig.dpi = {}'.format(fig.dpi))
print('fig.get_size_inches() = ' + str(fig.get_size_inches())
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(0., 60., 'Hello', fontdict=dict(size=25))
plt.savefig('base.png', format='png')

Run:

./base.py
identify base.png

Outputs:

fig.dpi = 100.0
fig.get_size_inches() = [6.4 4.8]
base.png PNG 640x480 640x480+0+0 8-bit sRGB 13064B 0.000u 0:00.000

Enter image description here

My best approach so far: plt.savefig(dpi=h/fig.get_size_inches()[1] height-only control

I think this is what I'll go with most of the time, as it is simple and scales:

get_size.py

#!/usr/bin/env python3

import sys

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

height = int(sys.argv[1])
fig, ax = plt.subplots()
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(0., 60., 'Hello', fontdict=dict(size=25))
plt.savefig(
    'get_size.png',
    format='png',
    dpi=height/fig.get_size_inches()[1]
)

Run:

./get_size.py 431

Outputs:

get_size.png PNG 574x431 574x431+0+0 8-bit sRGB 10058B 0.000u 0:00.000

Enter image description here

and

./get_size.py 1293

Outputs:

main.png PNG 1724x1293 1724x1293+0+0 8-bit sRGB 46709B 0.000u 0:00.000

Enter image description here

I tend to set just the height because I'm usually most concerned about how much vertical space the image is going to take up in the middle of my text.

plt.savefig(bbox_inches='tight' changes image size

I always feel that there is too much white space around images, and tended to add bbox_inches='tight' from: Removing white space around a saved image

However, that works by cropping the image, and you won't get the desired sizes with it.

Instead, this other approach proposed in the same question seems to work well:

plt.tight_layout(pad=1)
plt.savefig(...

which gives the exact desired height for height equals 431:

Enter image description here

Fixed height, set_aspect, automatically sized width and small margins

Ermmm, set_aspect messes things up again and prevents plt.tight_layout from actually removing the margins... this is an important use case that I don't have a great solution for yet.

Asked at: How to obtain a fixed height in pixels, fixed data x/y aspect ratio and automatically remove remove horizontal whitespace margin in Matplotlib?

plt.savefig(dpi=h/fig.get_size_inches()[1] + width control

If you really need a specific width in addition to height, this seems to work OK:

width.py

#!/usr/bin/env python3

import sys

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

h = int(sys.argv[1])
w = int(sys.argv[2])
fig, ax = plt.subplots()
wi, hi = fig.get_size_inches()
fig.set_size_inches(hi*(w/h), hi)
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(0., 60., 'Hello', fontdict=dict(size=25))
plt.savefig(
    'width.png',
    format='png',
    dpi=h/hi
)

Run:

./width.py 431 869

Output:

width.png PNG 869x431 869x431+0+0 8-bit sRGB 10965B 0.000u 0:00.000

Enter image description here

and for a small width:

./width.py 431 869

Output:

width.png PNG 211x431 211x431+0+0 8-bit sRGB 6949B 0.000u 0:00.000

Enter image description here

So it does seem that fonts are scaling correctly, we just get some trouble for very small widths with labels getting cut off, e.g. the 100 on the top left.

I managed to work around those with Removing white space around a saved image

plt.tight_layout(pad=1)

which gives:

width.png PNG 211x431 211x431+0+0 8-bit sRGB 7134B 0.000u 0:00.000

Enter image description here

From this, we also see that tight_layout removes a lot of the empty space at the top of the image, so I just generally always use it.

Fixed magic base height, dpi on fig.set_size_inches and plt.savefig(dpi= scaling

I believe that this is equivalent to the approach mentioned at: https://mcmap.net/q/40762/-specifying-and-saving-a-figure-with-exact-size-in-pixels

magic.py

#!/usr/bin/env python3

import sys

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

magic_height = 300
w = int(sys.argv[1])
h = int(sys.argv[2])
dpi = 80
fig, ax = plt.subplots(dpi=dpi)
fig.set_size_inches(magic_height*w/(h*dpi), magic_height/dpi)
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(0., 60., 'Hello', fontdict=dict(size=25))
plt.savefig(
    'magic.png',
    format='png',
    dpi=h/magic_height*dpi,
)

Run:

./magic.py 431 231

Outputs:

magic.png PNG 431x231 431x231+0+0 8-bit sRGB 7923B 0.000u 0:00.000

Enter image description here

And to see if it scales nicely:

./magic.py 1291 693

Outputs:

magic.png PNG 1291x693 1291x693+0+0 8-bit sRGB 25013B 0.000u 0:00.000

Enter image description here

So we see that this approach also does work well. The only problem I have with it is that you have to set that magic_height parameter or equivalent.

Fixed DPI + set_size_inches

This approach gave a slightly wrong pixel size, and it makes it is hard to scale everything seamlessly.

set_size_inches.py

#!/usr/bin/env python3

import sys

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

w = int(sys.argv[1])
h = int(sys.argv[2])
fig, ax = plt.subplots()
fig.set_size_inches(w/fig.dpi, h/fig.dpi)
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(
    0,
    60.,
    'Hello',
    # Keep font size fixed independently of DPI.
    # https://mcmap.net/q/40766/-matplotlib-change-figsize-but-keep-fontsize-constant
    fontdict=dict(size=10*h/fig.dpi),
)
plt.savefig(
    'set_size_inches.png',
    format='png',
)

Run:

./set_size_inches.py 431 231

Outputs:

set_size_inches.png PNG 430x231 430x231+0+0 8-bit sRGB 8078B 0.000u 0:00.000

So the height is slightly off, and the image:

Enter image description here

The pixel sizes are also correct if I make it 3 times larger:

./set_size_inches.py 1291 693

Outputs:

set_size_inches.png PNG 1291x693 1291x693+0+0 8-bit sRGB 19798B 0.000u 0:00.000

Enter image description here

We understand from this however that for this approach to scale nicely, you need to make every DPI-dependant setting proportional to the size in inches.

In the previous example, we only made the "Hello" text proportional, and it did retain its height between 60 and 80 as we'd expect. But everything for which we didn't do that, looks tiny, including:

  • line width of axes
  • tick labels
  • point markers

SVG

I could not find how to set it for SVG images, my approaches only worked for PNG, e.g.:

get_size_svg.py

#!/usr/bin/env python3

import sys

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl

height = int(sys.argv[1])
fig, ax = plt.subplots()
t = np.arange(-10., 10., 1.)
plt.plot(t, t, '.')
plt.plot(t, t**2, '.')
ax.text(0., 60., 'Hello', fontdict=dict(size=25))
plt.savefig(
    'get_size_svg.svg',
    format='svg',
    dpi=height/fig.get_size_inches()[1]
)

Run:

./get_size_svg.py 431

And the generated output contains:

<svg height="345.6pt" version="1.1" viewBox="0 0 460.8 345.6" width="460.8pt"

And identify says:

get_size_svg.svg SVG 614x461 614x461+0+0 8-bit sRGB 17094B 0.000u 0:00.000

And if I open it in Chromium 86 the browser debug tools mouse image hover confirm that height as 460.79.

But of course, since SVG is a vector format, everything should in theory scale, so you can just convert to any fixed sized format without loss of resolution, e.g.:

inkscape -h 431 get_size_svg.svg -b FFF -e get_size_svg.png

gives the exact height:

Enter image description here

I use Inkscape instead of ImageMagick's convert here because you need to mess with -density as well to get sharp SVG resizes with ImageMagick:

And setting <img height="" on the HTML should also just work for the browser.

It was tested on matplotlib 3.2.2.

Macintosh answered 10/11, 2020 at 10:31 Comment(0)
N
16

Generalizing and simplifying psihodelia's answer:

If you want to change the current size of the figure by a factor sizefactor:

import matplotlib.pyplot as plt

# Here goes your code

fig_size = plt.gcf().get_size_inches() # Get current size
sizefactor = 0.8 # Set a zoom factor
# Modify the current size by the factor
plt.gcf().set_size_inches(sizefactor * fig_size) 

After changing the current size, it might occur that you have to fine tune the subplot layout. You can do that in the figure window GUI, or by means of the command subplots_adjust

For example,

plt.subplots_adjust(left=0.16, bottom=0.19, top=0.82)
Nev answered 29/11, 2019 at 16:18 Comment(0)
R
15

This resizes the figure immediately even after the figure has been drawn (at least using Qt4Agg/TkAgg - but not Mac OS X - with Matplotlib 1.4.0):

matplotlib.pyplot.get_current_fig_manager().resize(width_px, height_px)
Ramirez answered 28/10, 2014 at 5:8 Comment(0)
P
5

I usually care more about the relative sizes of height/width rather than the actual values in inches. So, I use plt.figaspect() to set the aspect ratio.

# Make the image 3x as wide as it is tall
fix, ax = plt.subplots(figsize=plt.figaspect(1/3))
plt.title("I'm 3x as wide as I am tall")
plt.show()

enter image description here

Profitsharing answered 3/3, 2023 at 15:4 Comment(0)
G
3

I always use the following pattern:

x_inches = 150*(1/25.4)     # [mm]*constant
y_inches = x_inches*(0.8)
dpi = 96

fig = plt.figure(1, figsize = (x_inches,y_inches), dpi = dpi, constrained_layout = True)

With this example you are able to set figure dimensions in inches or in millimetres. When setting constrained_layout to True, plots fill your figure without borders.

Gynaecocracy answered 22/10, 2020 at 20:42 Comment(0)
P
0

You can also set the default size of figures in a custom style sheet used with matplotlib.style.use. In your .mplstyle file, include a line setting rcParams['figure.figsize']:

figure.figsize : 8, 6

The space between the numbers is optional, and you can use integers or floating-point.

Then, call use before creating the plot, ex. if your style file is my_style_file.mplstyle in the same directory:

matplotlib.style.use('my_style_file.mplstyle')

The numbers in the style file (8 and 6 in my example) are equivalent to the numbers you'd supply in the figsize argument: plt.figure(... figsize = (8,6) ...), but the behavior will be similar to setting rcParams['figure.figsize'] at the beginnining of the file, i.e., every new figure will be that size without needing to specify the size in every new figure.

Patrology answered 12/1 at 21:49 Comment(0)
M
0

TL;DR: Change dpi

This is especially useful if you want to scale a figure without changing the size of every element in it. There are two ways one can set dpi: (a) pass it in a figure constructor via dpi= parameter, or (b) call to set_dpi on the figure instance. The following shows how to set dpi=50.

data = [3, 5, 1, 7, 6, 7, 2]

# case 1a
plt.figure(dpi=50)
plt.plot(data)

# case 1b
fig, ax = plt.subplots(dpi=50)
ax.plot(data)

# case #2
plt.plot(data)
plt.gcf().set_dpi(50)

The following image shows how dpi affects figure size. Note that figsize is the same for both figures.

result

If your plot is generated by a third party library such as pandas or seaborn, then you can access the figure instance using .figure on the Axes object and change its dpi.

# pandas example
s = pd.Series([3, 5, 1, 7, 6, 7, 2])
ax = s.plot()
ax.figure.set_dpi(72)   # <--- change dpi via Axes

# seaborn example
ax = sns.lineplot(s)
ax.figure.set_dpi(72)   # <--- change dpi via Axes

How does it work?

The size of every matplotlib element is determined by the interaction of three properties:

  1. Size in inches: Get current size via: fig.get_size_inches() and change it via fig.set_size_inches(). The default size is (6.4, 4.8).
  2. dpi (dots/pixels per inch): Get current dpi via: fig.get_dpi() and change it via fig.set_dpi(). The default dpi is 100. A figure using the default settings is drawn using 307,200 pixels(=6.4x100x4.8x100). By changing the number of pixels, we can change the size of the figure (and everything drawn on it such as lines, markers, ticklabels, borders, labels, titles etc.).
  3. ppi (points per inch): This is fixed at ppi=72. A point is the unit of matplotlib element size (linewidth, markersize, fontsize etc.). For example, a line with lw=1 is 1/72 inch wide, a letter with fontsize=10 is 10/72 inch tall etc. If dpi=100, lw=1 line is 100/72 pixels wide, a letter with fontsize=10 is 1000/72 pixels tall etc.

Suppose we have a figure with figsize=(4,2) and dpi=100. If we decrease the figwidth 4->2, then that change in pixels is 400->200. However, since ppi is constant, the size of everything on the plot stays the same, i.e. lw=1 line will still be 1/72" (100/72 pixels) wide even though the figure its drawn on is 200 pixels wide now. Visually, everything on a plot will look bigger/thicker relative to the figure size.

On the other hand, if we decrease dpi, everything becomes smaller proportionally. If we decrease dpi from 100 to 50, then the figwidth changes from 400 pixels to 200 pixels, lw=1 line changes from 100/72 pixels to 50/72 pixels wide, etc., in other words, the size of every element in pixels is halved.

comparison


Code used to produce the above figures:

for figsize, dpi in [((4,2), 100), ((4,2), 50), ((2,1), 100)]:
    plt.figure(figsize=figsize, dpi=dpi)
    plt.plot([3,5,1,7,6,7,2])
    plt.title(f"figsize={figsize}, dpi={dpi}")
Mylohyoid answered 7/4 at 3:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.