31
votes

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

6

6 Answers

24
votes

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 rcParams['figure.figsize'] = 40, 12(you can set your own width and height)

20
votes

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

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

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.

3
votes

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

2
votes

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
0
votes

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)