WonderSteve
WonderSteve

Reputation: 927

matplotlib savefig() size control

I wrote a function that took a dataframe generated from Pandas and produce a heatmap:

def drawHeatMap(df, city, province, collector, classtype, color, titleposy):
    try:
        thePlot = pl.matshow(df.values, cmap='PuBuGn')
        pl.colorbar(thePlot, orientation='vertical')
        aTitle = (classtype + ' Composition Changes Over Time in ' + city + 
                ', ' + province + '\n' + collector + ' collector. ' + 'rs100')
        pl.title(aTitle, x=0.5, y=titleposy, style='oblique', weight='bold')
        pl.xlabel('Collection Time')
        pl.xticks(range(len(df.columns)), df.columns, rotation=90)
        pl.yticks(range(len(df.index)), df.index)
        fileName = (classtype + '-' + city + '-' 
                + province + '-' + collector + '.png')
        pl.savefig(fileName)
    except ZeroDivisionError:
        errorMessage = ('No Data Avaiable for ' + city + ', ' + province + 
                ' with ' + collector + ' collector.')
        print errorMessage

The problem I am having is, savefig() would save figures with the axis and graphics trimmed. I have to use show(), maximize the graph and manually save the figure with the GUI button myself.

How can I fix my function so savefig() would save the graphs properly? I tried to put a line like this before pl.savefig() to control my figure:

       pl.figure(figsize=....) 

but I end up producing some empty graphs. What is the proper way to write a matplotlib function that give me full control on saving the figure?

Updated with Example of a problem figure: enter image description here

Upvotes: 54

Views: 201623

Answers (9)

WHZW
WHZW

Reputation: 455

I added plt.tight_layout() before savefig(), and it solved the trimming issue I had. Maybe it will help yours as well.

EDIT: I also set the figure size at the begining matplotlib.rcParams['figure.figsize'] = 40, 12(you can set your own width and height)

Upvotes: 30

Mohammad Tehrani
Mohammad Tehrani

Reputation: 305

You can pass bbox_inches='tight' to the savefig

plt.savefig("image.png", bbox_inches='tight')

It will do the magic.

Upvotes: 6

HongchaoZhang
HongchaoZhang

Reputation: 4952

You need to use the set_size_inches function and the dpi parameter in savefig together to define the saved figure size in pixels.

  1. set the figure width and height in inches through plt.gcf().set_size_inches(10, 5).
  2. define the dpi while saving the figure plt.savefig('filename.png', dpi=100). dpi means "dot per inch".
  3. The saved figure width will be 1000(10x100) and the height will be 500(5x100). The saved figure size will be 1000x500 in pixels.

Sample code piece:

import matplotlib.pyplot as plt


def fig_size():
    plt.plot(range(0, 10), range(0, 10))
    plt.gcf().set_size_inches(10, 5)
    plt.savefig('charts/fig_size.png', dpi=200)

Upvotes: 14

Mohsen Liaghat
Mohsen Liaghat

Reputation: 49

you can use the dpi parameter to set The resolution in dots per inch in savefig method. so you can control the figure size. for example, if you this code :

import pandas as pd
import matplotlib.pyplot as plt


df = pd.DataFrame({ 
    'ser1' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] , 
    'ser2' : [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 
    })

df.plot()
plt.savefig("100.png" , dpi = 100)
plt.savefig("300.png" , dpi = 300)

100.png will be :

100.png

300.png will be :

300.png

Upvotes: 3

Zorro
Zorro

Reputation: 1519

To save figure on desired size

figure = plt.gcf()
figure.set_size_inches(width/100, height/100)
plt.axis('off')
plt.plot(x, y, color='black', linewidth=1)
plt.gca().set_position([0, 0, 1, 1])  
plt.savefig("image.png", dpi=100)

Upvotes: 1

Kumail Haider
Kumail Haider

Reputation: 127

before calling pl.savefig(fileName) do plt.tight_layout()

Upvotes: 6

Xiaorong Liao
Xiaorong Liao

Reputation: 1267

From the documentation, you can add a dpi argument to set the resolution.

savefig('foo.png', dpi=199)

Upvotes: 33

Maximilian
Maximilian

Reputation: 516

Short:
You just need to call pl.figure(figsize=...) before you call the pl.colorbar (and all the other stuff)

Explanation:
pl.figure creates a new figure (with given size), on which all pl.* methods will act in the following.
So pl.savefig just saves the last created figure, which is empty if you created a new one in the preceeding line.

Upvotes: 17

Mr. Squig
Mr. Squig

Reputation: 2825

The command pl.figure() makes a new matplotlib figure. The figure size is set at instantiation. You do want to set the figure size, but you already have a figure. So you were on the right track, but try this instead:

def drawHeatMap(df, city, province, collector, classtype, color, titleposy):
    try:
        fig = pl.figure(figsize=(....))
        ax = fig.add_subplot(111)
        ax.matshow(df.values, cmap='PuBuGn')
        pl.colorbar()
        aTitle = classtype + ' Composition Changes Over Time in ' + city + ', ' + province + '\n' + collector + ' collector. ' + 'rs100'
        ax.set_title(aTitle, x=0.5, y=titleposy, style='oblique', weight='bold')
        ax.set_xlabel('Collection Time')
        ax.set_xticks(range(len(df.columns)), df.columns, rotation=90)
        ax.set_yticks(range(len(df.index)), df.index)
        fileName = classtype + '-' + city + '-' + province + '-' + collector + '.png'
        fig.savefig(fileName)
    except ZeroDivisionError:
        errorMessage = 'No Data Available for ' + city + ', ' + province + ' with ' + collector + ' collector.'
        print errorMessage

Upvotes: 4

Related Questions