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).
Related
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()
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)
I am using Matplotlib on MacOS with Sulime Text.
I use Python 3.5 and Matplotlib 2.0.
When I work on a figure, I usually have a script that plot the data, and save the figure in a .pdf file with plt.savefig(). Then I use Skim (a pdf viewer) in order to refresh the file each time I modify and run the script. This allows me to set my working layout as clean as: there is one window for the script, and one window for the figure which is automatically refreshing.
I would like to do keep the same layout, but using the Matplotlib figures (because they are interactive). I am looking for a way to use plt.show() but always in the same figure that has been created the first time I've run the script.
For instance:
1. First run
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.figure()
noise = np.random.rand(1, 100)
ax(noise)
plt.show()
2. Following runs
import matplotlib.pyplot as plt
import numpy as np
# This is the super command I am looking for
fig = plt.get_previous_run_figure()
ax = fig.axes
noise = np.random.rand(1, 100)
ax.plot(noise)
plt.draw()
In that case of course, I would have to do a first-run script separately from the main script. Does anyone know if it is possible ?
You want to have multiple consecutive python sessions share a common Matplotlib window. I see no way to share this windows from separate processes, especially when the original owner may terminate at any point in time.
However, you could do something similar to your current workflow in which you have an external pdf viewer to view a output file which you update from multiple python instances.
See this question/answer on how to pickle a matplotlib figure:
Store and reload matplotlib.pyplot object
In every script, output your matplotlib figure as a pickled object, rather than calling plt.show():
import matplotlib.pyplot as plt
import numpy as np
import pickle
ax = plt.subplot(111)
x = np.linspace(0, 10)
y = np.exp(x)
plt.plot(x, y)
pickle.dump(ax, file('myplot.pickle', 'w'))
Then, start a dedicated python session which loads this pickled object and calls plt.show(). Have this script run in a loop, checking for updates of the pickled file on disk, and reloading when necessary:
import matplotlib.pyplot as plt
import pickle
while True:
ax = pickle.load(file('myplot.pickle'))
plt.show()
Alternative
Instead of having separate python sessions, I usually have a single Ipython session in which I run different script. By selecting the same figure windows, I end up with a mostly similar setup as you describe, in which the same figure window is reused throughout the day.
import matplotlib.pyplot as plt
fig = plt.figure(0)
fig.clf()
plt.show()
In principle establishing a connection between two different scripts could be done using a system-wide clipboard. (As far as I know the clipboard in windows and macos are system-wide.)
So the idea can be to set up an application using tk or pyqt, and implement a generic FigureCanvas. This application could have an event listener for changes in the clipboard.
The other main workflow script would then call some function that wraps the current figure into a pickle object and sends it to the clipboard, from where it gets caught by the GUI application, is unpickled and shown in the canvas.
This sounds like a little bit of work, but should meet the very restrictive requirements from the question.
The alternative from Daan worked for me. Here's a bit more code. I used this in a Tkinter interactive GUI for reusing/updating a matplotlib figure window:
fig1 = None
if fig1:
#if exists, clear figure 1
plt.figure(1).clf()
plt.suptitle("New Fig Title", fontsize=18, fontweight='bold')
#reuse window of figure 1 for new figure
fig1 = plt.scatter(points.T[0], points.T[1], color='red', **plot_kwds)
else:
#initialize
fig1 = plt.figure(num=1,figsize=(7, int(7*imgRatio)), dpi=80)
plt.tick_params(axis='both', which='major', labelsize=14)
plt.tick_params(axis='both', which='minor', labelsize=14)
plt.suptitle("Title", fontsize=18, fontweight='bold')
fig1 = plt.scatter(points.T[0], points.T[1], color='red', **plot_kwds)
The figure is reusing the (interactive) plt window. For this to work, I had to set interactive : True in the matplotlibrc file (see my comment here)
Hi I would like to show a few figures in matplotlib without stopping calculations. I would like the figure to show up right after the calculations that concern it are finished for example:
import numpy as np
import pylab as py
x=np.linspace(0,50,51)
y=x
fig, axs = plt.subplots(1, 1)
cs = axs.plot(x, y)
now i want to show the plot without blocking the possibility to make some other calculations
plt.show(block=False)
plt.pause(5)
I create the second plot
y1=2*x
fig1, axs1 = plt.subplots(1, 1)
cs1 = axs1.plot(x, y1)
plt.show()
This works however the first freezes (after 5 secound pause which I added) until I call plt.show() at the end. It is crucial that the first figure shows and works, then after calculations another figure is added to it.
The following code should do what you want. I did this in an IPython Notebook.
from IPython import display
import matplotlib.pyplot as plt
def stream_plot(iterable, plotlife=10.):
for I in iterable:
display.clear_output(wait=True)
output = do_calculations_on_i(I)
plt.plot(output)
display.display(plt.gca());
time.sleep(plotlife); #how long to show the plot for
the wait=True will wait to clear the old plot until it has something new to plot, or any other output is printed.
I put the sleep in there so I can observe each plot before it is wiped away. This was useful for having to observe distributions for several entities. You may or may not need it for what you want to do.
I will not be able to put the code here because it is my assignment.
My program is printing multiple graphs on one plot. Please look at the example figure on the following link: Python: Plot multiple graphs on the same figure
The link above is just an example. That is not my code nor do I have the same program. My topic is completely different. That figure is just for reference.
The line of code I am using to achieve this is: plot(a,b, label=str(meters))
What I want to do is get any one of those graph from those three curves and also plot it separately as if it is the main graph. I am doing all this inside a function, and I have created an array of numbers to loop through these different values to get three different graphs.
Do you mean something like this?
import numpy as np
import matplotlib.pyplot as plt
plt.ion()
a = np.arange(5)
line1, = plt.plot(a, a**2) # a new figure instance is opened automatically
line2, = plt.plot(a, a**3-a)
line3, = plt.plot(a, 4*a-a**2/2.)
fig_handle = plt.figure() # Force a new figure instance to open
plt.plot(a, a**2) # This will replot 'line1', but in this new figure instance.
If not, please update your question, perhaps showing the code you already have.
Note that this is information you could find on the matplotlib pyplot tutorial.