How to save plot after the plot is zoomed - python

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

Related

How to save a pyplot figure in its maximized state

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)

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

Matplotlib/Latex issues when using \odot as marker

I'm trying to use the latex symbol \odot as a marker in a scatter plot but I also need latex style ticks, but for some reason these two are not playing well together. I can successfully use marker=$\\odot$ with usetex=False, like this, but when I set it equal to true (to get the tick font right), I get ! LaTeX Error: File 'type1cm.sty' not found. I've already gone through to make sure I have the sty file installed and in the correct directory and that I have all the dependencies installed (as suggested here). Plus, I can still have usetex=True and use any of the normal pyplot markers, just not anything involving math font, but can I can have \odot in the label for the legend. Ive also already tried appending the rc params with amsmath but still keep getting the type1cm error. I've also tried using the raw string literal to no avail.
So basically when usetex=True, I can use math symbols in the label for the legend, just not as the actual marker. Has anyone experienced this issue before?
My current work around involves just plotting a large unfilled circle and overplotting a small filled circle (basically simulating the odot). Then I run into an issue with the legend so I basically have to create a transparent legend showing the large unfilled circles and then plot the smaller filled circles behind it by hand like this which ends up wonky, but this has the axes tick font I need. This becomes very frustrating if I have to change axes limits though, because I have to repeat the process of figuring out where to plot the small filled circles all over again.
Does anyone know if there is a better work around than this? Would it be possible to use the overplotting scheme like I have been, but then create a custom proxy artist to display the \odot symbol (in the different colors/sizes) in the legend?
Mac OSX, matplotlib 1.4.2, python 2.7, matplotlib is using pdfTeX thru TeX Live 2017/Mac Ports 2017
Edit: Here is my code
plt.rc('text', usetex=True)
plt.rc('font', family='serif')
f, ax1 = plt.subplots(1,1)
x = np.arange(20)
y = x
ax1.scatter(x, y, marker='$\\odot$', edgecolors='b', s=200, label = 'Test') #used with usetex=False
#ax1.scatter(x, y, marker='o', edgecolors='b', s=200, label = 'Test') #used with usetex=True
ax1.tick_params(labelsize=24)
leg = ax1.legend(scatterpoints=1, loc='lower right', borderaxespad=0., handletextpad=0.)#, fontsize=18) # borderpad=0.,)
I'm not sure how much I can help without seeing your code, but this worked for me:
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
x1 = [1,2]; x2 = [1,2]
y1 = [1,1]; y2 = [2,2]
mpl.rc('text', usetex = True)
fig, ax = plt.subplots(1,1)
ax.scatter(x1,y1, label='A1', marker=r'$\odot$',s=150, c='b')
ax.scatter(x2,y2, label='A2', marker=r'$\odot$',s=50, c='b')
ax.set_xlim(0,3)
ax.set_ylim(0,3)
ax.legend()
fig.show()
If this doesn't help let me know!

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.

Categories