plt.show() does nothing when used for the second time - python

I am just starting to learn data science using python on Data Camp and I noticed something while using the functions in matplotlib.pyplot
import matplotlib.pyplot as plt
year = [1500, 1600, 1700, 1800, 1900, 2000]
pop = [458, 580, 682, 1000, 1650, 6,127]
plt.plot(year, pop)
plt.show() # Here a window opens up and shows the figure for the first time
but when I try to show it again it doesn't..
plt.show() # for the second time.. nothing happens
And I have to retype the line above the show() to be able to show a figure again
Is this the normal thing or a problem?
Note: I am using the REPL

Answer
Yes, this is normal expected behavior for matplotlib figures.
Explanation
When you run plt.plot(...) you create on the one hand the lines instance of the actual plot:
>>> print( plt.plot(year, pop) )
[<matplotlib.lines.Line2D object at 0x000000000D8FDB00>]
...and on the other hand a Figure instance, which is set as the 'current figure' and accessible through plt.gcf() (short for "get current figure"):
>>> print( plt.gcf() )
Figure(432x288)
The lines (as well as other plot elements you might add) are all placed in the current figure. When plt.show() is called, the current figure is displayed and then emptied (!), which is why a second call of plt.show() doesn't plot anything.
Standard Workaround
One way of solving this is to explicitly keep hold of the current Figure instance and then show it directly with fig.show(), like this:
plt.plot(year, pop)
fig = plt.gcf() # Grabs the current figure
plt.show() # Shows plot
plt.show() # Does nothing
fig.show() # Shows plot again
fig.show() # Shows plot again...
A more commonly used alternative is to initialize the current figure explicitly in the beginning, prior to any plotting commands.
fig = plt.figure() # Initializes current figure
plt.plot(year, pop) # Adds to current figure
plt.show() # Shows plot
fig.show() # Shows plot again
This is often combined with the specification of some additional parameters for the figure, for example:
fig = plt.figure(figsize=(8,8))
For Jupyter Notebook Users
The fig.show() approach may not work in the context of Jupyter Notebooks and may instead produce the following warning and not show the plot:
C:\redacted\path\lib\site-packages\matplotlib\figure.py:459:
UserWarning: matplotlib is currently using a non-GUI backend, so
cannot show the figure
Fortunately, simply writing fig at the end of a code cell (instead of fig.show()) will push the figure to the cell's output and display it anyway. If you need to display it multiple times from within the same code cell, you can achieve the same effect using the display function:
fig = plt.figure() # Initializes current figure
plt.plot(year, pop) # Adds to current figure
plt.show() # Shows plot
plt.show() # Does nothing
from IPython.display import display
display(fig) # Shows plot again
display(fig) # Shows plot again...
Making Use of Functions
One reason for wanting to show a figure multiple times is to make a variety of different modifications each time. This can be done using the fig approach discussed above but for more extensive plot definitions it is often easier to simply wrap the base figure in a function and call it repeatedly.
Example:
def my_plot(year, pop):
plt.plot(year, pop)
plt.xlabel("year")
plt.ylabel("population")
my_plot(year, pop)
plt.show() # Shows plot
my_plot(year, pop)
plt.show() # Shows plot again
my_plot(year, pop)
plt.title("demographics plot")
plt.show() # Shows plot again, this time with title

Using command:
%matplotlib
in ipython3 help me to use separate window with plot

Start ipython3 and issue the commands:
import matplotlib.pyplot as plt
%matplotlib #plot in separate window
fig, ax = plt.subplots() #Appear empty Tcl window for image
ax.plot([1, 2, 3, 4], [5, 6, 7, 8]) #Appear graph in window

In some version of matplotlib, fig.show() does not block the window for showing plot multiple times. so, Quick fixes using self.fig.waitforbuttonpress() it waits user to press the button for next plot visualisation.
self.fig.show()
plt.pause(0.1)
self.fig.waitforbuttonpress()

Related

How can I save a Matplotlib figure after changing the background color?

Using the Spyder IDE, I have created a matplotlib plot and changed the face (background) color of both the figure object and the axes object to black. When I try to save the figure using plt.savefig(...) the axes, title, and axes label are not included.
I have tried implementing the standard advice of adding bbox_inches='tight' to the plt.savefig() function for when the axes are cut off:
plt.savefig("my_fig_name.png", bbox_inches='tight')
To no avail. Others suggested that I change the plotting method to "inline" from "automatic" within either Jupyter Notebook or Spyder. This had no effect. I also tried to make sure there was enough room in the figure for my axes using:
fig.add_axes([0.1,0.1,0.75,0.75])
This does not work either. Below is enough to reproduce my experience.
import matplotlib.pyplot as plt
xs, ys = [0,1], [0,1]
fig = plt.figure(figsize=(6, 6)) # Adding tight_layout=True has no effect
ax = fig.add_subplot(1, 1, 1)
# When the following block is commented out, the color of the
# plot is unchanged and the plt.savefig function works perfectly
fig.patch.set_facecolor("#121111")
ax.set_facecolor("#121111")
ax.spines['top'].set_color("#121111")
ax.spines['right'].set_color("#121111")
ax.spines['bottom'].set_color('white')
ax.spines['left'].set_color('white')
ax.xaxis.label.set_color('white')
ax.tick_params(axis='x', colors='white')
ax.yaxis.label.set_color('white')
ax.tick_params(axis='y', colors='white')
ax.set_title("My Graph's Title", color="white")
plt.plot(xs, ys)
plt.xlabel("x-label")
plt.ylabel("y-label")
plt.savefig("my_fig_name.png", bbox_inches="tight")
I am expecting to get an image like this:
What I Expect to Get
However, plt.savefig(...) gives me the following result:
What I Actually Get
Curiously, there seems to be white space around the plot which does not disappear even when I add the tight_layout=True parameter to the matplotlib figure constructor.
fig = plt.figure(figsize=(6, 6), tight_layout=True)
And, when I comment out the code which changes the face color of the plot, the figure is saved correctly with all the axes and labels displayed correctly.
In order to solve your problem, you just have to specify the facecolor keyword argument to your plt.savefig call, in this case :
plt.savefig("my_fig_name.png", bbox_inches="tight", facecolor="#121111")
which gives the intended .png output :
For more information, see plt.savefig documentation.

Trying to add additional traces to an existing Matplotlib figure

I am using a function which spits out a figure object of validation data. My script calculates a few model parameters that I would like to plot on top of this existing figure object. How can I do this? Whenever I try to plot my modeled data, it does so in a new window. Here's what my code looks like:
datafig = plotting_function(args) #Returning a figure object
datafig.show()
plt.plot([modeled_x],[modeled_y]) #Plotting in a new window
I've tried using plt.hold() / plt.hold(True) but this doesn't do anything. Any ideas?
Edit:
MCVE:
import matplotlib.pyplot as plt
def fig_create():
fig_1, ax_1 = plt.subplots()
ax_1.plot([0,1],[0,1])
fig_2, ax_2 = plt.subplots()
ax_2.plot([0,1],[0,5])
return fig_1, ax_1, fig_2, ax_2
figure_1, axes_1, figure_2, axes_2 = fig_create()
plt.close("all") # Spyder plots even without a plt.show(), so running the function generates figures. I'm closing them here.
figure_2.show()
plt.figure(2)
plt.plot([0,1],[0,10])
Result of the MCVE: https://i.imgur.com/FiCJX33.png
You need to specify which axis to plot on. plt.figure(2) will make a figure with a number of 2, regardless of whether an existing figure has that number or not! axes_2.plot(), however will plot whatever data you input directly onto axes_2 and whatever was there already. If it doesn't immediately show up you should add plt.draw() after the plot function.
Try not to mix plt, notation and ax notation as this will create confusion later on! If you are using fig and ax, stick with those!
You can specify which figure to plot to by calling plt.figure(my_figure_index) before any plt.plot (or any other plt plotting function) call.
For example:
plt.figure(10) # creates new figure if doesn't exist yet
plt.plot(...) # plots in figure 10
plt.figure(2) # creates new figure if doesn't exist yet
plt.plot(...) # plots in this figure 2
plt.figure(10) # figure already exists, just makes it the active one
plt.plot(...) # plots in figure 10 (in addition to already existing stuff)

Pandas save plot to file and don't show on the screen

I'm making some plots of fitted data and saving them to files nicely with.
# Make the main plot.
ax = df.plot(x=df.x, y=['counts', 'fit', 'res'], title=save_file_name,
style=['b', 'g--', 'r'], xlim=xlim, ylim=ylim)
# Over plot some individual gaussians from my fit_gaussians dataframe.
for i, fit_gaus in fit_gaussians.iterrows():
plt.plot(df.x, gaussian(df.x, fit_gaus.h, fit_gaus.mu,
fit_gaus.sigma), 'y', linestyle='--')
# Save to file.
fig = ax.get_figure()
fig.savefig('test.ps')
This works great, but it also opens a window and plots to the screen. I know I can easily use matplotlib directly to recreate what I'm doing with df.plot, and just never call plt.show, but I feel like there should be some way create plot in a file with pandas with out also opening a window.
If you only don't want the pop ups you can do %matplotlib inline otherwise before you define ax just do:
plt.ioff()
Then whenever you want to actually show it you can do plt.show()

Keeping multiple figures open with matplotlib after script is executed

I have a question regarding windows/figures in matplotlib. I'm not sure if this is possible, but would like to know if it is.
Basically when I run my whole script, at the end a graph is plotted using matplotlib. In order to produce a new graph after running my script again I have to close that graph window.
Is there a way of keeping open the figure without closing it?
Let me give an example:
I would plot graph x by running my script.
I would then like to keep this graph on my screen, make a change to my script, plot the graph again so you may see the old graph and the new graph. Therefore n number of graphs may be visible.
Please note that I do NOT want to plot a new figure within my script. I simply would like to be able to see the graph, make a change and see the new graph WITHOUT having to save the graph.
EDIT:
This is the plotting secion of my code:
def plot_data(atb_mat_2, sd_index, sd_grad):#, rtsd):#, sd_index, sd_grad):
fig = plt.figure()
fig, (ax0, ax1, ax4, ax2, ax3) = plt.subplots(nrows=5, figsize=(15,10), num='Current Relative Method'+' ' + path)
ax0.plot(atb_mat_2)
ax0.set_title('Relative Track',fontsize=11)
ax0.set_ylim([-10,10])
if len(sd_index)!=0:
if len(sd_index)>1:
for i in range(1, len(sd_index)):
if sd_grad[i]==1:
ax0.axvspan(sd_index[i-1],sd_index[i], edgecolor='r', lw=None, alpha=0.1)
ax1.plot(rtsd)
ax1.set_title('RT Standard Deviation',fontsize=11)
ax1.set_ylim([0,250])
ax4.plot(abs_track_data)
ax4.set_title('Absolute Track',fontsize=11)
ax4.set_ylim([3000,5000])
ax2.plot(splitpo)
ax2.set_title('Track Split',fontsize=11)
ax2.set_ylim([0,20])
ax3.plot(ts)
ax3.set_title('TS Standard Deviation',fontsize=11)
ax3.set_ylim([0,100])
fig.tight_layout()
plt.show()
Thanks alot of any advice and sorry if this answer is obvious as I'm fairly new.
You can do it using ipython.
Write your script and save it as (for example) test.py. The script should create a figure, do the plotting and show the plot:
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
x = np.linspace(-1, 1, 100)
y = np.sin(x)
plt.plot(x, y)
plt.show()
Start the ipython console using:
ipython --pylab=qt
Or whatever backend you want to use.
In the ipython shell type:
%run /path/to/the/test.py
This will create a figure, and show the plot.
After that change your script. For example change the 5th line to:
x = np.linspace(-0, 2, 100)
Repeat the %run command in the ipython shell:
%run /path/to/the/test.py
Another figure will pop up with the new plot. Old figure will be also visible (this won't remove it or replace it).

When to use cla(), clf() or close() for clearing a plot in matplotlib?

Matplotlib offers these functions:
cla() # Clear axis
clf() # Clear figure
close() # Close a figure window
When should I use each function and what exactly does it do?
They all do different things, since matplotlib uses a hierarchical order in which a figure window contains a figure which may consist of many axes. Additionally, there are functions from the pyplot interface and there are methods on the Figure class. I will discuss both cases below.
pyplot interface
pyplot is a module that collects a couple of functions that allow matplotlib to be used in a functional manner. I here assume that pyplot has been imported as import matplotlib.pyplot as plt.
In this case, there are three different commands that remove stuff:
See matplotlib.pyplot Functions:
plt.cla() clears an axis, i.e. the currently active axis in the current figure. It leaves the other axes untouched.
plt.clf() clears the entire current figure with all its axes, but leaves the window opened, such that it may be reused for other plots.
plt.close() closes a window, which will be the current window, if not specified otherwise.
Which functions suits you best depends thus on your use-case.
The close() function furthermore allows one to specify which window should be closed. The argument can either be a number or name given to a window when it was created using figure(number_or_name) or it can be a figure instance fig obtained, i.e., usingfig = figure(). If no argument is given to close(), the currently active window will be closed. Furthermore, there is the syntax close('all'), which closes all figures.
methods of the Figure class
Additionally, the Figure class provides methods for clearing figures.
I'll assume in the following that fig is an instance of a Figure:
fig.clf() clears the entire figure. This call is equivalent to plt.clf() only if fig is the current figure.
fig.clear() is a synonym for fig.clf()
Note that even del fig will not close the associated figure window. As far as I know the only way to close a figure window is using plt.close(fig) as described above.
There is just a caveat that I discovered today.
If you have a function that is calling a plot a lot of times you better use plt.close(fig) instead of fig.clf() somehow the first does not accumulate in memory. In short if memory is a concern use plt.close(fig) (Although it seems that there are better ways, go to the end of this comment for relevant links).
So the the following script will produce an empty list:
for i in range(5):
fig = plot_figure()
plt.close(fig)
# This returns a list with all figure numbers available
print(plt.get_fignums())
Whereas this one will produce a list with five figures on it.
for i in range(5):
fig = plot_figure()
fig.clf()
# This returns a list with all figure numbers available
print(plt.get_fignums())
From the documentation above is not clear to me what is the difference between closing a figure and closing a window. Maybe that will clarify.
If you want to try a complete script there you have:
import numpy as np
import matplotlib.pyplot as plt
x = np.arange(1000)
y = np.sin(x)
for i in range(5):
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, y)
plt.close(fig)
print(plt.get_fignums())
for i in range(5):
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
ax.plot(x, y)
fig.clf()
print(plt.get_fignums())
If memory is a concern somebody already posted a work-around in SO see:
Create a figure that is reference counted
plt.cla() means clear current axis
plt.clf() means clear current figure
also, there's plt.gca() (get current axis) and plt.gcf() (get current figure)
Read more here: Matplotlib, Pyplot, Pylab etc: What's the difference between these and when to use each?

Categories

Resources