Dynamically updating a graphed line in python [duplicate] - python

This question already has answers here:
pylab.ion() in python 2, matplotlib 1.1.1 and updating of the plot while the program runs
(2 answers)
Closed 9 years ago.
I'm plotting a line using matplotlib and would like to update my line data as soon as new values are generated. However, once in the loop, no window appears. Even though the printed line indicates the loop is running.
Here's my code:
def inteprolate(u,X):
...
return XX
# generate initial data
XX = inteprolate(u,X)
#initial plot
xdata = XX[:,0]
ydata = XX[:,1]
ax=plt.axes()
line, = plt.plot(xdata,ydata)
# If this is in, The plot works the first time, and then pauses
# until the window is closed.
# plt.show()
# get new values and re-plot
while True:
print "!"
XX = inteprolate(u,XX)
line.set_xdata(XX[:,0])
line.set_ydata(XX[:,1])
plt.draw() # no window
How do I update my plot in real-time when the plt.show() is blocking and plt.draw doesn't update/display the window?

You need to call plt.pause in your loop to give the gui a chance to process all of the events you have given it to process. If you do not it can get backed up and never show you your graph.
# get new values and re-plot
plt.ion() # make show non-blocking
plt.show() # show the figure
while True:
print "!"
XX = inteprolate(u,XX)
line.set_xdata(XX[:,0])
line.set_ydata(XX[:,1])
plt.draw() # re-draw the figure
plt.pause(.1) # give the gui time to process the draw events
If you want to do animations, you really should learn how to use the animation module. See this awesome tutorial to get started.

You'll need plt.ion(). Take a look a this: pylab.ion() in python 2, matplotlib 1.1.1 and updating of the plot while the program runs. Also you can explore the Matplotlib animation classes : http://jakevdp.github.io/blog/2012/08/18/matplotlib-animation-tutorial/

An efficient way to do the same as #Alejandro is:
import matplotlib.pyplot as plt
import numpy as np
plt.ion()
x = np.linspace(0,2*np.pi,num=100)
y = np.sin(x)
plt.xlim(0,2*np.pi)
plt.ylim(-1,1)
plot = plt.plot(x[0], y[0])[0]
for i in xrange(x.size):
plot.set_data(x[0:i],y[0:i])
plt.draw()

I think this toy code clarify the answer of #ardoi:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0,2*np.pi,num=100)
plt.ion()
for i in xrange(x.size):
plt.plot(x[:i], np.sin(x[:i]))
plt.xlim(0,2*np.pi)
plt.ylim(-1,1)
plt.draw()
plt.clf()
Edit:
The previous code display a sinusoidal function by animating it in the screen.

Related

Run matplotlib without blocking the console

i try to make a dynamical plot in a method of a class. here is more or less the method
def plot():
axes = plt.gca(bock=False)
ydata = []
xdata = []
axes.set_xlim(0, 200)
axes.set_ylim(-1,1)
line, = axes.plot(ydata, 'r-')
i=0
while True:
xdata.append(i/10)
ydata.append(np.sin(i/10))
line.set_ydata(ydata)
line.set_xdata(xdata)
plt.draw()
plt.pause(1e-17)
i+=1
plt.show()
The problem is the fact that it's an infinity loop and during this loop function, i can do nothing. i can't use my Ipython console. I would like make run this method without block the console. i arrived to do something like that using just print and threading but matplotlib dont support threading. I tried using multiprocessing but that still block the console. any options?
So there were many problems with this code.
First: that bock argument you passed to plt.gca() threw errors.
Second: plt.show() stops execution so the animation will not start.
To go around this problem you must trigger the animation after plt.show() was called.
One way to do it is making use of events. You can read more about them here:
https://matplotlib.org/3.2.1/users/event_handling.html
Lastly, you can use a conditional and break to make sure the loop is not infinite.
Here is an example:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
def plot(lim=100):
"""
Parameters
----------
lim -> int: Iteration where you want to stop
"""
axes = plt.gca()#bock=False Was removed because it threw errors
fig = plt.gcf()
canvas = fig.canvas
ydata = []
xdata = []
axes.set_xlim(0, 200)
axes.set_ylim(-1,1)
line, = axes.plot(xdata, ydata,'r-')
#Now, we can't just start the loop because plt.show() will
#Stop execcution. Instead we can make a trigger that starts
#the loop. I will use a mouse event.
def start_loop():
i=0
while True:
xdata.append(i/10)
ydata.append(np.sin(i/10))
line.set_ydata(ydata)
line.set_xdata(xdata)
canvas.draw()
canvas.flush_events()#This makes the updating less laggy
plt.pause(1e-17)#Removable
i+=1
if i==lim:
break
canvas.mpl_connect("button_press_event",
lambda click: start_loop())
#Click the plot to start the animation
plt.show()
plot()
Furthermore, if you want faster execution, make use of blit or animation functions
from matplotlib like FuncAnimation.

Python Matplotlib Update Plot in the Background

I am using Matplotlib to plot a real time event in Anaconda prompt.
When I update plot by plt.draw() or plt.show(), I loose control of the thing I am doing. Plot window acts like its clicked and this blocks my other control on the command prompt.
I tried adding
plt.show(block=False)
but it didnt help.
The code is like below,
fig, ax = plt.subplots()
plt.ion()
plt.show(block=False)
while(True):
ax.plot(y_plt_points,x_plt_points,'ro')
plt.draw()
plt.pause(0.01)
This link has an example of real time plotting with matplotlib. I think the main takeaway is that you don't need to use plt.show() or plt.draw() on every call to plot. The example uses set_ydata instead. Simalarly set_xdata can be used to update your x_axis variables. Code below
import matplotlib.pyplot as plt
import numpy as np
# use ggplot style for more sophisticated visuals
plt.style.use('ggplot')
def live_plotter(x_vec,y1_data,line1,identifier='',pause_time=0.1):
if line1==[]:
# this is the call to matplotlib that allows dynamic plotting
plt.ion()
fig = plt.figure(figsize=(13,6))
ax = fig.add_subplot(111)
# create a variable for the line so we can later update it
line1, = ax.plot(x_vec,y1_data,'-o',alpha=0.8)
#update plot label/title
plt.ylabel('Y Label')
plt.title('Title: {}'.format(identifier))
plt.show()
# after the figure, axis, and line are created, we only need to update the y-data
line1.set_ydata(y1_data)
# adjust limits if new data goes beyond bounds
if np.min(y1_data)<=line1.axes.get_ylim()[0] or np.max(y1_data)>=line1.axes.get_ylim()[1]:
plt.ylim([np.min(y1_data)-np.std(y1_data),np.max(y1_data)+np.std(y1_data)])
# this pauses the data so the figure/axis can catch up - the amount of pause can be altered above
plt.pause(pause_time)
# return line so we can update it again in the next iteration
return line1
When I run this function on the example below I don't have any trouble using other applications on my computer
size = 100
x_vec = np.linspace(0,1,size+1)[0:-1]
y_vec = np.random.randn(len(x_vec))
line1 = []
i=0
while i<1000:
i=+1
rand_val = np.random.randn(1)
y_vec[-1] = rand_val
line1 = live_plotter(x_vec,y_vec,line1)
y_vec = np.append(y_vec[1:],0.0)
I think this is what you are looking for.
I had a similar issue, fixed it by replacing:
plt.pause(0.01)
with
fig.canvas.flush_events()
A more detailed explanation found here:
How to keep matplotlib (python) window in background?

How can I get matplotlib's imshow to refresh once every second?

Have a sensor that gives me an 8x8 grid of temps that I am to display on a live heatmap. I have made an 8x8 rand to simulate that data. This heatmap should be able to run until I tell it not to run anymore. I'm using python3 and matplotlib to attempt this visualization.
I've tried may ways to make this work, including clearing the screen, turning the plt into a figure, telling show() to not block, etc. You can see many of my attempts in the comments. It either displays once only, or never displays at all (e.g. ion() and plt.show(block=False) never display any data). I've hit my head against a wall for 2 whole work days and I can't figure out why it won't display properly.
import time
import socket
import matplotlib.pyplot as plt
import numpy as np
import random
first = True
randArray = []
#plt.ion()
plt.show(block=False)
#fig = plt.figure()
#str1 = ''.join(str(e) for e in amg.pixels)
#print (type(str1))
while True:
#create a bunch of random numbers
randArray = np.random.randint(0,50, size=(8,8))
#print the array, just so I know you're not broken
for x in randArray:
print(x)
#This is my attempt to clear.
if (first == False):
plt.clf()
first = False
#basical visualization
plt.imshow(randArray, cmap='hot', interpolation='nearest')
plt.draw()
plt.show()
#fig.canvas.draw()
#plt.canvas.draw()
#plt.display.update
print("Pausing...")
time.sleep(5)
I expect the code to generate a new set of numbers every 5 seconds, and then refresh the screen with the colors of those new numbers. This should be able to run for hours if I don't interrupt, but the screen never refreshes.
More: I have tried everything listed in the post "How to update a plot in matplotlib?" and everything they do just makes it so that no graph ever populates. The launcher acts like it's going to do something by showing up in the task bar, but then does nothing. I've tried it on a Mac and a Pi, both have the same issue. Maybe it's because that post is 8 years old, and this is python 3 not python 2? Maybe it's because I use imshow() instead of plot()? I haven't figured out how to make their code work on my machine either.
Edit: I've gotten it to work on the raspberry pi thanks to the first commenters recommendations. But now I'm left wondering.... what's wrong with my Mac??
This is a similar question to this one.
You could try to modify your code to something like this:
import time
import socket
import matplotlib.pyplot as plt
import numpy as np
import random
first = True
randArray = []
#plt.ion()
plt.show(block=False)
#fig = plt.figure()
#str1 = ''.join(str(e) for e in amg.pixels)
#print (type(str1))
fig = plt.figure()
for i in range(0,5):
#create a bunch of random numbers
randArray = np.random.randint(0,50, size=(8,8))
#print the array, just so I know you're not broken
for x in randArray:
print(x)
#This is my attempt to clear.
if (first == False):
plt.clf()
first = False
#basical visualization
ax = fig.add_subplot(111)
ax.imshow(randArray, cmap='hot', interpolation='nearest')
fig.canvas.draw()
fig.canvas.flush_events()
#fig.canvas.draw()
#plt.canvas.draw()
#plt.display.update
print("Pausing...")
time.sleep(2)
Have a nice day and get some rest :).
Try this one:
import matplotlib.pyplot as plt
import numpy as np
while True:
#create a bunch of random numbers
random_array = np.random.randint(0,50, size=(8,8))
#print the array, just so I know you're not broken
print(random_array)
#clear the image because we didn't close it
plt.clf()
#show the image
# plt.figure(figsize=(5, 5))
plt.imshow(random_array, cmap='hot', interpolation='nearest')
plt.colorbar()
print("Pausing...")
plt.pause(5)
#uncomment this line and comment the line with plt.clf()
# plt.close()
The magic is with the line plt.pause(5), it shows the image for five seconds. It's up to you if you want to close it (plt.close()) or clear it (plt.clf()). When you want to update constantly your plot, you don't use plt.show() or plt.draw(), you use plt.pause().
Uncomment some lines to try some variations... of course, some of them won't work.

How to update Matplotlib graph when new data arrives?

I'm building a bot which fetches data from the internet every 30 seconds.
I want to plot this data using matplotlib and be able to update the graphs when I fetch some new one.
At the beginning of my script I initialise my plots.
Then I run a function to update these plots every 30 seconds, but my plot window freezes at this moment.
I've done some research but can't seem to find any working solution:
plt.show(block=False)
plt.pause(0.001)
What am I doing wrong ?
General structure of the code:
import matplotlib.pyplot as plt
import time
def init_plots():
global fig
global close_line
plt.ion()
fig = plt.figure()
main_fig = fig.add_subplot(111)
x = [datetime.fromtimestamp(x) for x in time_series]
close_line, = main_fig.plot(x, close_history, 'k-')
plt.draw()
def update_all_plots():
global close_line
x = [datetime.fromtimestamp(x) for x in time_series]
close_line.set_xdata(time_series)
close_line.set_ydata(close_history)
plt.draw()
# SCRIPT :
init_plots()
while(True):
# Fetch new data...
# Update time series...
# Update close_history...
update_plots()
time.sleep(30)
There is a module in matplotlib for specifically for plots that change over time: https://matplotlib.org/api/animation_api.html
Basically you define an update function, that updates the data for your line objects. That update function can then be used to create a FuncAnimation object which automatically calls the update function every x milliseconds:
ani = FuncAnimation(figure, update_function, repeat=True, interval=x)
There is a simple way to do it, given a panda dataframe . You would usually do something like this to draw(df is dataframe) :
ax = df.plot.line()
Using
df.plot.line(reuse_plot=True,ax=ax)
one can reuse the same figure to redraw it elegantly and probably fast enough.
Possibly duplicate of Matplotlib updating live plot

Dynamically update figure with plot

I want to update my plot every loop iteration. So I don't want to use animation I know there is a lot of examples in network, but on my PC it works only in debug mode. So common case look something like this
import numpy as np
from matplotlib import pyplot as plt
plt.ion() # set plot to animated
ydata = [0] * 50
ax1=plt.axes()
# make plot
line, = plt.plot(ydata)
plt.ylim([10,40])
# start data collection
i=0
while True:
i=i+1
ymin = float(min(ydata))-10
ymax = float(max(ydata))+10
plt.ylim([ymin,ymax])
ydata.append(i)
del ydata[0]
line.set_xdata(np.arange(len(ydata)))
line.set_ydata(ydata) # update the data
plt.draw() # update the plot
And it works grate when I run program step by step, but when I run it in normal mode my figure with plot freezes.

Categories