62
votes

I have created a figure using matplotlib but I have realised the plot axis and the drawn line gets zoomed out. enter image description here

Reading this earlier discussion thread, it explains how to set the figure size.

fig, ax = plt.subplots()

fig.set_size_inches(3, 1.5)

plt.savefig(file.jpeg, edgecolor='black', dpi=400, facecolor='black', transparent=True)

With the above code (other configurations removed for brevity), I do get a resulting image file with 1200 X 600 desired dimensions(should we say resolution too?) and desired file size.

The projected image is scaled out in an unusual way, annotations for example are enlarged. While I can set the size of the labels on the axis, the figure doesn't look proportional with respect to the scale since the bottom and right spines are large and so are the plotted lines.

The question therefore is, what configurations are going wrong?

1
I do not quite understand the issue. But what I can say is that when both, figure size in inches and dpi, should be fixed you need to change the size of the objects you perceive as "too large", i.e. setting the font size, the line width, tickmarks etc. smaller. Usually you would just either fix dpi or size in inches to achieve a desired figure.ImportanceOfBeingErnest
@ImportanceOfBeingErnest I created a picture which turned out with the desired dimensions and the file size is within the desire range. However the graph drawn turned out to be too zoomed/scaled out. Reading other threads it seems there is a scaling and aspect-ratio issue that could be at play. Your suggestion to declare each element size sounds rather unusual as I would think that there should be a way to adjust all elements in the canvas automatically with respect to the previously set parameters of figsize() and dpi.qboomerang
Let me try again: If e.g. the pixel dimension is to be 1200 X 600, you would usually create a figure with size (12 x 6) inches and 100 dpi, in which case the lines are probably adequately sized. Using a dpi of 400 instead makes each point in the figure 4 times as large. Apparently that is not what you want. But if you need it, you can scale down the elements (e.g. make the linewith 0.25 instead of 1). (There is no scaling or aspect issue here, this is all how it works and as expected.)ImportanceOfBeingErnest
Looking at the comment you mention, this is about something completely different; it tells you that you do not get a square axes, even if you use a square figure. This is completely unrelated to you problem here.ImportanceOfBeingErnest
I think I get your point. My understanding of the relationship between dpi and figsize(x,y) was slightly different from what you have explained. Based on your comment, I have tested your suggestion and it looks promising. Perhaps I should change the title of the question...qboomerang

1 Answers

149
votes

Figure size (figsize) determines the size of the figure in inches. This gives the amount of space the axes (and other elements) have inside the figure. The default figure size is (6.4, 4.8) inches in matplotlib 2. A larger figure size will allow for longer texts, more axes or more ticklabels to be shown.

Dots per inches (dpi) determines how many pixels the figure comprises. The default dpi in matplotlib is 100. A figure of figsize=(w,h) will have

px, py = w*dpi, h*dpi  # pixels
# e.g.
# 6.4 inches * 100 dpi = 640 pixels

So in order to obtain a figure with a pixel size of e.g. (1200,600) you may chose several combinations of figure size and dpi, e.g.

figsize=(15,7.5), dpi= 80
figsize=(12,6)  , dpi=100
figsize=( 8,4)  , dpi=150
figsize=( 6,3)  , dpi=200
etc.

Now, what is the difference? This is determined by the size of the elements inside the figure. Most elements like lines, markers, texts have a size given in points.
Matplotlib figures use Points per inch (ppi) of 72. A line with thickness 1 point will be 1./72. inch wide. A text with fontsize 12 points will be 12./72. inch heigh.

Of course if you change the figure size in inches, points will not change, so a larger figure in inches still has the same size of the elements. Changing the figure size is thus like taking a piece of paper of a different size. Doing so, would of course not change the width of the line drawn with the same pen.

On the other hand, changing the dpi scales those elements. At 72 dpi, a line of 1 point size is one pixel strong. At 144 dpi, this line is 2 pixels strong. A larger dpi will therefore act like a magnifying glass. All elements are scaled by the magnifying power of the lens.

A comparisson for constant figure size and varying dpi is shown in the image below on the left. On the right you see a constant dpi and varying figure size. Figures in each row have the same pixel size.

enter image description here

Code to reproduce:

import matplotlib.pyplot as plt
%matplotlib inline

def plot(fs,dpi):
    fig, ax=plt.subplots(figsize=fs, dpi=dpi)
    ax.set_title("Figsize: {}, dpi: {}".format(fs,dpi))
    ax.plot([2,4,1,5], label="Label")
    ax.legend()

figsize=(2,2)
for i in range(1,4):
    plot(figsize, i*72)

dpi=72
for i in [2,4,6]:
    plot((i,i), dpi)