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()
Related
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())
I'm trying to grab data from a text file and plot it using the animation.FuncAnimation module from matplotlib. Here is my code that I'm trying to make run correctly
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
style.use('ggplot')
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
def animate(i):
graph_data = open('example.txt', 'r').read()
lines = graph_data.split('\n')
xs = []
ys = []
for line in lines:
x,y = line.split(',')
xs.append(x)
ys.append(y)
ax1.clear()
ax1.plot(xs, ys)
animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
example.txt is an 18-line text file (omitted for space reasons) which contain (x,y) pairs of data which I'd like to plot. However, matplotlib is not plotting the x values in order: once they reach 10, they 'wrap around' back to the beginning, sandwiching themselves between 1 and 2. Makes for a pretty bad graph.
I'm having some trouble figuring out what's wrong with my implementation. I've even tried sorting the values before plotting them, but the plot still comes out like this.
All help is appreciated! I've been scouring doc pages and StackOverflow for a while now, and I can't seem to find anyone whose had this same problem.
Quick answer: Working example below.
There are few aspects you should be aware of.
Firstly, FuncAnimation will execute animate function on each call, i.e. every interval milliseconds, which in your case is 1 second. You don't really want to read file again and again... do it once before and then update your view.
Secondly, creating each time whole axis (ax.plot) is very expensive and it'll slow down quickly.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from matplotlib import style
graph_data = open('example.txt', 'r').read()
lines = graph_data.split('\n')
xs = []
ys = []
for line in lines[:-1]:
x,y = line.split(',')
xs.append(float(x))
ys.append(float(y))
# This is where you want to sort your data
# sort(x, y, reference=x) # no such function
style.use('ggplot')
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
x, y = [], [] # Prepare placeholders for animated data
ln, = plt.plot(x, y, animated=True)
ax1.set_xlim(min(xs), max(xs)) # Set xlim in advance
ax1.set_ylim(min(ys), max(ys)) # ylim
def animate(i):
x.append(xs[i])
y.append(ys[i])
ln.set_data(x, y)
return ln,
ani = animation.FuncAnimation(fig, animate, frames=range(len(xs)),
interval=1000, repeat=False, blit=True)
plt.show()
Notice that we used repeat flag to False. This means that once it goes through whole frames list then it stops.
The numbers are not in order because you are treating them as strings not numbers. So append them as floats and it will solve it. Try:
xs.append(float(x))
ys.append(float(y))
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()
I am trying to get a better look on an animated graph using matplotlib but I have no idea on how to do that. For example, I have this animated graph as follow:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
fig, ax = plt.subplots()
x = np.arange(0, 2*np.pi, 0.01) # x-array
line, = ax.plot(x, np.sin(x))
def animate(i):
line.set_ydata(np.sin(x+i/10.0)) # 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(1, 200), init_func=init,
interval=25, blit=True)
plt.show()
What I want to do is to divide the graphic line in different colors by region. For example, I would like to have the curve from 0 < x < 2 red, from 2 < x < 4 green and from 4 < x < 6 blue. I have seen that the only possibility is to set a color for the whole line, but I have never seen this possibility of dividing line with different colors.
Thank so much for any help or hint on how to do that.
Thanks to Jake Vanderplas, I know how to start to code an animated plot with matplotlib. Here is a sample code:
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(0, 100))
line, = plt.plot([], [])
def init():
line.set_data([], [])
return line,
def animate(i):
line.set_data([0, 2], [0,i])
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()
Suppose now I'd like to plot tons of functions (say four here), defined with the help of a loop. I did some voodoo programming, trying to understand how to mimic the comma following line and here is what I got (needless to say that it does not work: AttributeError: 'tuple' object has no attribute 'axes').
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(0, 100))
line = []
N = 4
for j in range(N):
temp, = plt.plot([], [])
line.append(temp)
line = tuple(line)
def init():
for j in range(N):
line[j].set_data([], [])
return line,
def animate(i):
for j in range(N):
line[j].set_data([0, 2], [10 * j,i])
return line,
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()
Some my question is: how can I make it work? Bonus (probably linked): what is the difference between line, = plt.plot([], []) and line = plt.plot([], [])?
Thanks
In the solution below I showcase a bigger example (with also bar plot) that may help people understand better what should be done for other cases. After the code I explain some details and answer the bonus question.
import matplotlib
matplotlib.use('Qt5Agg') #use Qt5 as backend, comment this line for default backend
from matplotlib import pyplot as plt
from matplotlib import animation
fig = plt.figure()
ax = plt.axes(xlim=(0, 2), ylim=(0, 100))
N = 4
lines = [plt.plot([], [])[0] for _ in range(N)] #lines to animate
rectangles = plt.bar([0.5,1,1.5],[50,40,90],width=0.1) #rectangles to animate
patches = lines + list(rectangles) #things to animate
def init():
#init lines
for line in lines:
line.set_data([], [])
#init rectangles
for rectangle in rectangles:
rectangle.set_height(0)
return patches #return everything that must be updated
def animate(i):
#animate lines
for j,line in enumerate(lines):
line.set_data([0, 2], [10 * j,i])
#animate rectangles
for j,rectangle in enumerate(rectangles):
rectangle.set_height(i/(j+1))
return patches #return everything that must be updated
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20, blit=True)
plt.show()
Explanation
The idea is to plot what you need and then reuse the artists (see more here) returned by matplotlib. This is done by first plotting a dummy sketch of what you want and keeping the objects matplotlib gives you. Then on your init and animate functions you can update the objects that need to be animated.
Note that in plt.plot([], [])[0] we get a single line artist, thus I collect them with [plt.plot([], [])[0] for _ in range(N)]. On the other hand plt.bar([0.5,1,1.5],[50,40,90],width=0.1) returns a container that can be iterated for the rectangle artists. list(rectangles) just convert this container into a list to be concatenated with lines.
I separate the lines from the rectangles because they are updated differently (and are different artists) but init and animate return all of them.
Answer to bonus question:
line, = plt.plot([], []) assign the first element of the list returned by plt.plot to the veriable line.
line = plt.plot([], []) just assign the whole list (of only one element).
Here is a modified example which is more readable.
This is just the code from the matplotlib website with another piece added. What threw me was I wasn't initially realizing the plt functions were returning lists, overlooking the trailing comma, or even how things were being tied together, which seems to be getting handled pretty implicitly by the library itself. But the key is to create several update-able objects and return them from the two key functions as part of the same list and they will be synced when the animation is run.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
xdata, ydata = [], []
xdata2,ydata2= [], []
ln, = plt.plot([], [], 'ro')
ln2, = plt.plot([], [], 'ro')
def init():
ax.set_xlim(0, 2*np.pi)
ax.set_ylim(-1, 1)
return ln,ln2
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
xdata2.append(frame)
ydata2.append(np.cos(frame))
ln2.set_data(xdata2,ydata2)
return ln,ln2
ani = FuncAnimation(fig, update, frames=np.linspace(0, 2*np.pi, 128),
init_func=init, blit=True)
plt.show()
For more fun change the animation callback to the following:
def update(frame):
xdata.append(frame)
ydata.append(np.sin(frame))
ln.set_data(xdata, ydata)
delta = 2*np.pi/128
xdata2.append([frame*2,frame*2+delta])
ydata2.append([np.cos(frame*2), np.cos(frame*2+delta)])
ln2.set_data(xdata2,ydata2)
return ln,ln2