I am trying to dynamically update a matplotlib from a .txt file that periodically updates.
For this, I used the following tutorial.
https://pythonprogramming.net/python-matplotlib-live-updating-graphs/
The .txt file looks like such
1,2
2,3
3,6
4,9
5,4
6,7
7,7
8,4
9,3
10,10
The code looks like such:
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
def animate(i):
pullData = open("sampleText.txt","r").read()
dataArray = pullData.split('\n')
xar = []
yar = []
for eachLine in dataArray:
if len(eachLine)>1:
x,y = eachLine.split(',')
xar.append(int(x))
yar.append(int(y))
ax1.clear()
ax1.plot(xar,yar)
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
This output a figure with these points plotted.
When I update with a new line, such as 11,15, and save there is no updated figure.
How can I make this update to the current figure as a new line is added to the .txt file?
I have tried some of the solutions to these questions asked on stackoverflow without success:
live updating with matplotlib
What is the currently correct way to dynamically update plots in Jupyter/iPython?
I created the code with the understanding that the intent of the question was to draw a graph based on the row-by-row data by retrieving the values from an updated, localized text file. The main points that I modified are the initial settings and updating the values in the animation function.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
from matplotlib.animation import PillowWriter
#from IPython.display import HTML
pullData = open("sampleText.txt","r").read()
dataArray = pullData.split('\n')
frm = len(dataArray)
fig = plt.figure()
ax1 = plt.axes(xlim=(0, size), ylim=(0, size))
line, = ax1.plot([],[], 'r-', lw=3)
xar = []
yar = []
def animate(i):
if i < size:
x,y = dataArray[i].split(',')
xar.append(int(x))
yar.append(int(y))
line.set_data(xar, yar)
ax1.set_ylim(0, max(yar)+3)
return line
ani = animation.FuncAnimation(fig, animate, frames=frm, interval=200, repeat=False)
ani.save('plot_ani_test.gif', writer='pillow')
# jupyter lab
# plt.close()
# HTML(ani.to_html5_video())
Related
I am sorry for my poor English.
I have a matrix datas (10000 times 5000). It includes 10000 cases of data and the dimension of each data is 5000.
I want to make an animation to show each data one after another.
Following Code 1 works well.
(Code 1)
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
ims = []
for i in range(10000):
im = plt.plot(masks[i,:])
ims.append(im)
ani = animation.ArtistAnimation(fig, ims, interval=10)
plt.show()
ani.save('output.mp4', writer="ffmpeg")
I want to add the time-varying title to know which data (data index) is shown at a certain time.
And I wrote the following Code 2.
(Code 2)
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
ims = []
for i in range(10000):
im = plt.plot(masks[i,:])
tl = 'Data number:' + str(i+1) # ***added***
plt.title(tl) # ***added***
ims.append(im)
ani = animation.ArtistAnimation(fig, ims, interval=10)
plt.show()
ani.save('output.mp4', writer="ffmpeg")
However, I got an animation whose title is always 'Data number: 10000'.
How can I write the code to add the time-varying title?
I wrote plt.title(tl) before im = plt.plot(masks[i,:]) but nothing changed. Thank you for your help.
My environments are;
Python 3.6.9
matplitlib 3.3.3
We can imitate the figure title by annotating an axes object:
#test data generation
import numpy as np
np.random.seed(123)
masks = np.random.randn(10, 15)
#the animation routine starts here
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
ims = []
#iterating over the array
for i in range(masks.shape[0]):
#obtaining the Line2D object representing the line plot
im, = ax.plot(masks[i,:], color="blue")
#creating a centered annotation text above the graph
ann = ax.annotate(f"This is frame {i:.0f}.", (0.5, 1.03), xycoords="axes fraction", ha="center")
#collecting both objects for the animation
ims.append([im, ann])
ani = animation.ArtistAnimation(fig, ims, interval=300, repeat=False)
plt.show()
I've got some code similar to this
from matplotlib import animation
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
def animate(i):
x0,y0 = np.random.random(size=(2,))*4-2
x = np.random.normal(loc=x0, size=(1000,))
y = np.random.normal(loc=y0, size=(1000,))
for layer in prevlayers:
layer.remove()
prevlayers[:] = []
hexlayer = ax.hexbin(x,y, gridsize=10, alpha=0.5)
# the following line is needed in my code
hexlayer.remove()
prevlayers.append(hexlayer)
return hexlayer,
prevlayers = []
ani = animation.FuncAnimation(fig, animate, frames=12)
ani.save('teste.gif', writer='PillowWriter')
I'm trying to show only one frame at a time, but the code that I have written uses two ax.hexbin() calls and I have to remove one of them in order to show the correct graph. Is there a way to show one hexbin layer at a time using FuncAnimation?
You only need ax.clear() for each frame
from matplotlib import animation
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots()
def animate(i):
ax.clear()
x0,y0 = np.random.random(size=(2,))*4-2
x = np.random.normal(loc=x0, size=(1000,))
y = np.random.normal(loc=y0, size=(1000,))
hexlayer = ax.hexbin(x,y, gridsize=10, alpha=0.5)
return ax
ani = animation.FuncAnimation(fig, animate, frames=12)
ani.save('teste.gif', writer='PillowWriter')
this code produces
I am trying to construct a live graph in python to plot random numbers in a graph with a fixed plot window
The width of the plot window will be 20 samples. For the 21st sample, the 1st sample will dissappear from the right side. Here is my code. Cant figure out why is it not plotting.
import random
import time
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
#creating a subplot
ax1 = fig.add_subplot(1,1,1)
xs = []
ys = []
iter = 0
def animate(i,xs,ys,iter):
while True:
iter = iter+1
xs.append(iter)
ys.append(round(random.uniform(-120,20),2))
#I want only 20 data points on the plot i.e the plot window will be only showing 20 samples at a time
x = xs[-20:]
y = ys[-20:]
ax1.clear()
ax1.plot(x, y)
ax1.set_ylim([-120,20])
plt.xlabel('Value')
plt.ylabel('Time')
plt.title('Live Graph')
time.sleep(1)
ani = animation.FuncAnimation(fig, animate, fargs = (xs,ys,iter), interval=1000)
plt.show()
Check out the documentation for FuncAnimation.
The second parameter is a function that is repeatedly called for each consecutive frame, updating the figure with each call. Your function animate is an infinite loop, so the execution thread never returns back to FuncAnimation. Try something like this instead as a starting point:
import random
import time
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
xs = []
ys = []
line, = ax1.plot(xs, ys)
plt.xlabel('Value')
plt.ylabel('Time')
plt.title('Live Graph')
def animate(frame, xs, ys):
xs.append(frame)
ys.append(round(random.uniform(-120,20),2))
x = xs[-20:]
y = ys[-20:]
line.set_xdata(x)
line.set_ydata(y)
ax1.set_xlim(min(x)-1, max(x)+1)
ax1.set_ylim(min(y)-1, max(y)+1)
ax1.set_xticks(list(range(min(x), max(x)+1)))
return line
ani = animation.FuncAnimation(fig, animate, fargs = (xs,ys), interval=100)
plt.show()
Hi I am trying to create a movie of 15 Gaussian graphs that move to the left (thats essentially what the code is suppose to do)
However, my idea for how to create the for loop to create the 15 graphs has not created more than 1, it only speeds up the animation.
A similar code worked on matlab. It created 15 different Gaussian curves.
Here is a sample of my code.
any help would be appreciated.
Thanks
import numpy as np
import matplotlib.pyplot as plt
plt.switch_backend('agg')
import matplotlib.animation as animation
Gamma=0.0005
q=1.6e-19
m=0.067*9e-31
B=10
Ec=(1.0567e-34)*B/m
#e=2.78
#E0=0+(1.0567e-34)*x*i/m
fig, ax = plt.subplots()
pass
x = np.arange(0, 3.4e-3, 1.7e-5) # x-array, third number is interval here, x is energy
line, = ax.plot(x, np.e**(-(x-((1.0567e-34)*1*1/m))**2/Gamma**2))
def animate(i):
for p in xrange(1,3):
line.set_ydata(np.e**((-(x-((1.0567e-34)*p*i/m))**2)/Gamma**2)) # update the data
return line,
#Init only required for blitting to give a clean slate.
def init():
line.set_ydata(np.ma.array(x, mask=True))
return line,
ani = animation.FuncAnimation(fig, animate, np.arange(0, 2, .01), init_func=init,
interval=10, blit=True)
Writer = animation.writers['ffmpeg']
writer = Writer(fps=20, metadata=dict(artist='Me'), bitrate=1800)
ani.save('QHanimati.mp4', writer=writer)
plt.show()
You currently have exactly one line in your code. This line gets updated. If you want to have more lines, you need to create more lines.
You then also need to update all of those lines.
(Since the role of p isn't clear from the example I took it as some incrementing number here. I also restricted this to 8 curves not to overcrowd the image.)
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
Gamma=0.0005
q=1.6e-19
m=0.067*9e-31
B=10
Ec=(1.0567e-34)*B/m
fig, ax = plt.subplots()
n = 8 # number of lines
x = np.arange(0, 3.4e-3, 1.7e-5)
lines = [ax.plot(x, np.e**(-(x-((1.0567e-34)*1*1/m))**2/Gamma**2))[0] for _ in range(n)]
def animate(i):
for ln, line in enumerate(lines):
p = (ln+1)/10.
line.set_ydata(np.e**((-(x-((1.0567e-34)*p*i/m))**2)/Gamma**2)) # update the data
return lines
#Init only required for blitting to give a clean slate.
def init():
for line in lines:
line.set_ydata(np.ma.array(x, mask=True))
return lines
ani = animation.FuncAnimation(fig, animate, np.arange(0, 2, .01), init_func=init,
interval=10, blit=True)
plt.show()
I would like to create a animation where my data points would gradually appear on my graph and freeze when all the data points have appeared. I've seen in done with correlations i'm just not too sure how to do it with just individual points themselves
This isn't something that will show anything particularly useful but i though it would look cool since i am trying to visualize some location data on a map
I know this isn't very clear so please as for clarifications, I'm not too sure how to phrase my problem very well.
Thanks
matplotlib.animation.FuncAnimation is the right tool for you. First create an empty graph, and then gradually add data points to it in the function. The following piece of code will illustrate it:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.arange(10)
y = np.random.random(10)
fig = plt.figure()
plt.xlim(0, 10)
plt.ylim(0, 1)
graph, = plt.plot([], [], 'o')
def animate(i):
graph.set_data(x[:i+1], y[:i+1])
return graph
ani = FuncAnimation(fig, animate, frames=10, interval=200)
plt.show()
The result (saved as gif file) is shown below:
EDIT: To make the animation look stopped when finished in matplotlib window, you need to make it infinite (omit frames parameter in FuncAnimation), and set the frame counter to the last number in your frame series:
def animate(i):
if i > 9:
i = 9
graph.set_data(x[:i+1], y[:i+1])
return graph
ani = FuncAnimation(fig, animate, interval=200)
Or, which is better, you can set repeat parameter in FuncAnimation to False, as per answer to this question.
EDIT 2: To animate a scatter plot, you need a whole bunch of other methods. A piece of code is worth a thousand words:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = np.arange(10)
y = np.random.random(10)
size = np.random.randint(150, size=10)
colors = np.random.choice(["r", "g", "b"], size=10)
fig = plt.figure()
plt.xlim(0, 10)
plt.ylim(0, 1)
graph = plt.scatter([], [])
def animate(i):
graph.set_offsets(np.vstack((x[:i+1], y[:i+1])).T)
graph.set_sizes(size[:i+1])
graph.set_facecolors(colors[:i+1])
return graph
ani = FuncAnimation(fig, animate, repeat=False, interval=200)
plt.show()