19

I used MatplotLib with Cartopy to generate some data images. The problem is that when I set the frame size to fullscreen and use plt.show() the image is perfect and the resolution is fine.

However, when I save this figure using 'plt.savefig()' the image saved keeps with its original size (not fullscreen).

Showing outcome images:

Showing the image - not saving it

Saving the image - not showing it

My code is the following:

def plot_tec_cartopy(descfile): global matrixLon, matrixLat, matrixTec

ax = plt.axes(projection=cartopy.crs.PlateCarree())

v = np.linspace(0, 80, 46, endpoint=True)
cp = plt.contourf(matrixLon, matrixLat, matrixTec, v, cmap=plt.cm.rainbow)
plt.clim(0, 80)
plt.colorbar(cp)

ax.add_feature(cartopy.feature.COASTLINE)
ax.add_feature(cartopy.feature.BORDERS, linestyle=':')
ax.set_extent([-85, -30, -60, 15])

# Setting X and Y labels using LON/LAT format
ax.set_xticks([-85, -75, -65, -55, -45, -35])
ax.set_yticks([-60, -55, -50, -45, -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15])
lon_formatter = LongitudeFormatter(number_format='.0f',
                                   degree_symbol='',
                                   dateline_direction_label=True)
lat_formatter = LatitudeFormatter(number_format='.0f',
                                  degree_symbol='')
ax.xaxis.set_major_formatter(lon_formatter)
ax.yaxis.set_major_formatter(lat_formatter)

plt.title('Conteúdo Eletrônico Total', style='normal', fontsize='12')

# Acquiring Date
year, julianday = check_for_zero(descfile.split('.')[2]), descfile.split('.')[3]
hour, minute = descfile.split('.')[4], descfile.split('.')[5].replace('h','')
date = datetime.datetime(int(year), 1, 1, int(hour), int(minute)) + datetime.timedelta(int(julianday)-1)
month = date.month
day = date.day

# Set common labels
ax.text(1.22, 1.05, 'TEC', style='normal',
    verticalalignment='top', horizontalalignment='right',
    transform=ax.transAxes,
    color='black', fontsize=11)
ax.text(1, 0.005, 'EMBRACE/INPE', style='italic',
    verticalalignment='bottom', horizontalalignment='right',
    transform=ax.transAxes,
    color='black', fontsize=10)
ax.text(1, 0.995, str(date) + ' UT', style='italic',
    verticalalignment='top', horizontalalignment='right',
    transform=ax.transAxes,
    color='black', fontsize=10)
ax.text(0.5, -0.08, 'Copyright \N{COPYRIGHT SIGN} 2017 INPE - Instituto Nacional de',
    style='oblique', transform=ax.transAxes,
    verticalalignment='bottom', horizontalalignment='center',
    color='black', fontsize=8)
ax.text(0.5, -0.108, 'Pesquisas Espacias. Todos direitos reservados',
    style='oblique', transform=ax.transAxes,
    verticalalignment='bottom', horizontalalignment='center',
    color='black', fontsize=8)

manager = plt.get_current_fig_manager()
manager.resize(*manager.window.maxsize())

figName = 'tec.map' + '.' + str(year) + '.' + str(julianday) + '.' + str(hour) + '.' + str(minute) + 'h.png'
#plt.show()
plt.savefig(figName, dpi=500)
plt.clf()

Maybe I need to set some parameter into savefig() to say it that it needs to save my modified frame? Can someone help me with this issue?

Thanks in advance.

Mad Physicist
  • 95,415
  • 23
  • 151
  • 231
Hollweg
  • 193
  • 1
  • 2
  • 8

2 Answers2

17

Coming from MATLAB, it is not intuitive that your displayed figure does not have to affect the saved one in terms of dimensions, etc. Each one is handled by a different backend, and you can modify the dpi and size_inches as you choose.

Increasing the DPI is definitely going to help you get a large figure, especially with a format like PNG, which does not know about the size in inches. However, it will not help you scale the text relative to the figure itself.

To do that, you will have to use the object oriented API, specifically, figure.set_size_inches, which I don't think has an equivalent in plt. Replace

plt.savefig(figName, dpi=500)

with

fig = plt.gcf()
fig.set_size_inches((8.5, 11), forward=False)
fig.savefig(figName, dpi=500)

The size 8.5, 11 is the width and height of the standard paper size in the US, respectively. You can set it to whatever you want. For example, you can use your screen size, but in that case be sure to get the DPI right as well.

Mad Physicist
  • 95,415
  • 23
  • 151
  • 231
  • Your solution is great and solved the problem! Thanks for your answer, Mad Physicist. :) – Hollweg Aug 05 '17 at 03:08
  • 4
    Traditionally, you would celebrate by marking the answer by clicking on the check mark next to it, and upvoting if you have the reputation for it. – Mad Physicist Aug 05 '17 at 06:47
  • 1
    @Hollweg you may not have enough reputation to upvote an answer, but you can always accept the answers that are good and useful for you. Accepting an answer to your question also removing your question from the `unanswered` list as it should be. – swatchai Sep 24 '17 at 14:01
  • 2
    why do I got this error? AttributeError: 'Figure' object has no attribute 'save' – Lei Yang Aug 10 '18 at 07:33
  • 2
    @Lei. Is it `savefig` or something in the new version? – Mad Physicist Aug 10 '18 at 14:00
  • @MadPhysicist for me `fig.savefig(...)` solved the AttributeError. – Shai Jun 30 '20 at 13:02
  • 1
    @Shai. Looks like they made the name consistent between the Figure class and pyplot in later versions. Thanks for checking. – Mad Physicist Jun 30 '20 at 13:06
  • @MadPhysicist would you consider edit your answer accordingly? – Shai Jun 30 '20 at 13:40
  • 1
    @Shai. I made the update. Change was pre-1.5. This is a pretty old answer I guess. – Mad Physicist Jun 30 '20 at 15:33
1

Just to add some context on @Mad Physicist answer. If someone is trying to use it with a new version of matplotlib, you will get an AttributeError: 'Figure' object has no attribute 'save'. You also need to be careful about when you call plt.show() otherwise you will get a blank image. You need to update the code as follow:

# Create a plot
plt.barh(range(top), imp, align='center')
plt.yticks(range(top), names)

# Get the current figure like in MATLAB
fig = plt.gcf()
plt.show() # show it here (important, if done before you will get blank picture)
fig.set_size_inches((8.5, 11), forward=False)
fig.savefig(figName, dpi=500) # Change is over here

Hope it helps!

Yacine Mahdid
  • 713
  • 4
  • 17