How to save a pyplot figure in its maximized state - python

I am trying to save a pyplot figure in its maximized form as displayed when I call plt.show() because maximizing the graph correctly displays the data, while a smaller 'windowed' version of the plot that is currently getting saved has the data incorrectly shifted/formatted.
Current code:
mng = plt.get_current_fig_manager()
mng.window.showMaximized()
plt.savefig(path + '.png', dpi=fig.dpi)
plt.show()
I use the current_fig_manager to force plot.show() to show in its maximized state which it does correctly, but plt.savefig() still saves the fig in the smaller format.
I am looking into ways to grab the dimensions of mng.window.showMaximized() in inches and then plugging that into savefig() but was wondering if there is a better approach?

Try to config the figure size before starting the code with plt.figure(figsize=(width, height)). See bellow a example:
plt.figure(figsize=(10,6)) #10,6 is the figure dimensions
plt.plot(...)
...
plt.savefig(...)
Doing that the savefig function will use the defined dimensions.

Solution is create a figure and set the size in inches there, then save the figure instead of the plot.
fig = matplotlib.pyplot.gcf()
fig.set_size_inches(18.5, 10.5)
fig.savefig('test2png.png', dpi=100)

Related

Matplotlib not showing histogram correctly when saving figure

Using matplotlib, I am plotting 2 histograms in one figure. The goal is to add them to a Latex document later. I am interested in the difference between the two, so I use a low transparency and plot them on top of each other. In Spyder, when I plot inline, the image looks fine. See wanted plot
When I export the image as a PNG using plt.savefig(), the image looks like this. However, this does not work well in Latex documents as the scaling gets ruined. When I try to export it as a PDF file, the bars of the histogram seem to overlap, making it seem like it has edges, like in ugly plot.
I think the cause of the problem is due to the vector format, when zooming in and out of the PDF, the overlap changes. When zoomed in completely, it looks identical to the PNG, when zoomed out the overlap becomes much larger. I would be very grateful if anyone knew the solution to this.
Things I have tried already:
changing linewidth/edgecolor
changing the matplotlibrc file
changing the distance of the bins using rwidth
Code I am using:
binwidth = (np.max(prediction) - np.min(prediction)) / (2*I**(1/3))
kwargs = dict(alpha=0.5, bins=np.arange(min(prediction), max(prediction) + binwidth, binwidth))
fig_path = '***.pdf'
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.hist(prediction.flatten(), **kwargs, label = 'NN')
ax.hist(hedging_error, **kwargs, label = 'BS')
ax.set_xlim((-3,3))
ax.set_xlabel('Hedging error')
ax.set_ylabel('Count')
ax.legend()
fig.savefig(fig_path)
To remove the bin edges use plt.hist(..., histtype='stepfilled')
https://matplotlib.org/stable/gallery/statistics/histogram_histtypes.html

setting up figure handle for basemap

I don't really understand how to use properly figure handles, for example in setting up a figure and clearing and/or closing it. Here, I am plotting using basemap in a for loop.
I fixed the overlapping problem of my colorbars appearing in my plots produced by the for loop, by adding the lines fig=plt.figure() and plt.clf() but I do not understand why or how I can use the 'fig' handle below in my script (is it the same as the 'cs' handle for the m.pcolor?)
I also get an error message that there are too many open figures when I have the below code in the for loop, and so added the line plt.close(fig)
fig=plt.figure()
cs = m.pcolor(LON_subset,LAT_subset,ma.masked_where(land_mask_subset,data))
# add colorbar
cbar = m.colorbar(cs,location='bottom', pad="3%")
cbar.set_label('J/m$^2$',size=17)
cbar.ax.tick_params(labelsize=16)
plt.clf()
plt.close(fig)
#plt.show()

Change Spyder and Matplotlib figure size for saved plots only

I would like to view matplotlib plots inside Spyders IPython console in one size and save figures to a multipage PDF in a different size.
Currently I set the figure size as follows:
plt.rc('axes', grid=True)
plt.rc('figure', figsize=(12, 8))
plt.rc('legend', fancybox=True, framealpha=1)
Then I plot some figures and save them to a list for saving a PDF later on. This works just fine when used alone. The plots are approriately sized for viewing in Spyder IPython console.
At the end of my script I have a loop to go through each of the figures I want to save. In here I want to set the layout and figure size exactly for better printing on an A3 paper.
with PdfPages('multi.pdf') as pdf:
for fig in figs:
fig.tight_layout()
fig.set_size_inches(420/25.4, 297/25.4)
pdf.savefig(figure=fig)
The output PDF is just like I want it to be, but the problem is with the plots shown inside Spyder. Changing the figure size while saving also affects the plots viewed inside Spyder. And using the size of an A3 makes the plots way too big.
So the question is: How do I change the size of saved PDF figures without changing the size of figures shown inside Spyder?
As suggested by #ImportanceOfBeingErnest, changing the figure size back after saving should work and may probably solved you problem.
But, depending on your specific problem, it is possible that you are going to face scaling issues since the size of the figures saved in the pdf is much bigger than the size of those displayed in the IPython console. If you scale everything to look great on the pdf, then it is possible that everything is going to look too big in IPython as shown in the example below:
If you don't need the plot to be interactive in IPython, a solution may be to generate your figures to look good for the pdf and display a scaled bitmap version of them in the IPython console as shown in the code below:
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
import numpy as np
from IPython.display import Image, display
try: # Python 2
from cStringIO import StringIO as BytesIO
except ImportError: # Python 3
from io import BytesIO
# Generate a matplotlib figures that looks good on A3 format :
fig, ax = plt.subplots()
ax.plot(np.random.rand(150), np.random.rand(150), 'o', color='0.35', ms=25,
alpha=0.85)
ax.set_ylabel('ylabel', fontsize=46, labelpad=25)
ax.set_xlabel('xlabel', fontsize=46, labelpad=25)
ax.tick_params(axis='both', which='major', labelsize=30, pad=15,
direction='out', top=False, right=False, width=3, length=10)
for loc in ax.spines:
ax.spines[loc].set_linewidth(3)
# Save figure to pdf in A3 format:
w, h = 420/25.4, 297/25.4
with PdfPages('multi.pdf') as pdf:
fig.set_size_inches(w, h)
fig.tight_layout()
pdf.savefig(figure=fig)
plt.close(fig)
# Display in Ipython a sclaled bitmap using a buffer to save the png :
buf = BytesIO()
fig.savefig(buf, format='png', dpi=90)
display(Image(data=buf.getvalue(), format='png', width=450, height=450*h/w,
unconfined=True))
which shows in the IPython console as:
Thank you #ImportanceOfBeingErnest for pointing out the solution.
I went with a solution that allows me to set plt.rc in the beginning to my taste and then revert to the set values after exporting the figures to a PDF.
First I set the values I use:
plt.rc('axes', grid=True)
plt.rc('figure', figsize=(12, 8))
plt.rc('legend', fancybox=True, framealpha=1)
With these I can plot what I need with just the default values. Then I create the PDF with:
with PdfPages('multi.pdf') as pdf:
for fig in figs:
fig.set_size_inches(420/25.4, 297/25.4)
pdf.savefig(figure=fig, bbox_inches='tight')
fig.set_size_inches(plt.rcParams.get('figure.figsize'))
With this I can get the fig.tight_layout() only on the exported figure and restore the figure size to the default value set earlier.

matplotlib - How to save an array as image with overlayed text?

I have a 2D array that I need to save as a png. I also need to add a text label to the image. So far, I have tried two approaches, none of which is optimal:
I use the matplotlib.image module to save the array directly as an image:
matplotlib.image.imsave(FILENAME, ARRAY, cmap=plt.cm.binary)
However I am unable to add text using that command. I could use PIL to read and edit after saving the raw images, but the I/O cost on a large data set would be unacceptable.
I use the pyplot interface to convert the array to a figure and then add a legend. However when I save it as a file, there is unnecessary whitespace. I have tried turning axes off, setting padding to 0 etc., but there is always some whitespace margin I cannot get rid of:
import matplotlib.pyplot as plt
plt.imshow(ARRAY, cmap=plt.cm.binary)
plt.axis('off')
plt.savefig(FILENAME, dpi=100, pad_inches=0.0, bbox_inches='tight')
Is there a way to generate an image from a 2D array, overlay text, and save as .png speedily with no whitespace? Preferably a solution using matplotlib/PIL, but if there's anything better out there, I can look into it.
I was able to solve my problem by using an object oriented approach from the start:
import matplotlib.pyplot as plt
fig = plt.figure(dpi=100, tight_layout=True, frameon=False, figsize=(resolution/100.,resolution/100.)) # dpi & figsize of my choosing
fig.figimage(ARRAY, cmap=plt.cm.binary)
fig.text(X,Y,TEXT, size='medium', backgroundcolor='white', alpha=0.5)
plt.savefig(FILENAME)
plt.close(fig)
Additional documentation for the figure class can be found here.
Note: For sizing figures, I found this relationship useful:
size in inches = resolution in pixels / DPI

How to save plot after the plot is zoomed

Last few days I have been facing a problem in saving the matplotlib figure, three days before the code was working fine and saves the plot with changes made through the code, but now the changes (zoomed plot) is not saving rather it saves as it is when the plot is shown any changes made after does not reflects using the save command, don't know why?
ax = pd.rolling_mean(dataToPlot_plot[startTime:endTime][['plotValue']],mar).plot(linestyle='-', linewidth=3, markersize=9, color='#FECB00')
ax.legend().set_visible(False)
plt.show()#showing the plot
fig = ax.get_figure()
fig.set_size_inches(12, 6)#setting the size of the plot, to fix in the PDF file
fig.savefig('graph1.jpg')#saving the plot
even if I call a function, the new changed plot is not saved...
def callmeto_plot()
ax = pd.rolling_mean(dataToPlot_plot[startTime:endTime][['plotValue']],mar).plot(linestyle='-', linewidth=3, markersize=9, color='#FECB00')
ax.legend().set_visible(False)
plt.show()#showing the plot
fig = ax.get_figure()
return fig
fig = callmeto_plot()
fig.set_size_inches(12, 6)
fig.savefig('graph1.jpg')
How do I save the plot (zoomed one with changes) through code? Note: I have noticed that the plot window appearance is also changed, 1 Plot window appearance before 2 Plot window appearance now all the plot window configuration buttons are shifted from bottom to top, does this change affects only in the plot or affects the coding as well?. Please help me to fix this... Thanks in advance.
You could move all the plot changing code above the plt.show() and then save the figure manually from the pop-up window. The right most icon at the bottom left saves the current figure as is currently displayed
Even better you could use plt.axis([xStart, xFinish, yBottom, yTop]) or ax.set_xlim(), ax.set_ylim

Categories