Using below code within a cell in Jupyter notebbok I'm attempting to update a simple graph :
%reset -f
import matplotlib.pyplot as plt
import pandas as pd
from datetime import datetime
import random
from matplotlib import animation, rc
from IPython.display import HTML
import numpy as np
%matplotlib inline
fig, ax = plt.subplots()
line, = ax.plot([], [], lw=2)
# initialization function: plot the background of each frame
def init():
line.set_data([], [])
return (line,)
# animation function. This is called sequentially
def animate(i):
line.set_data([1,random.randint(100,101)], [1,random.randint(100,101)])
return (line,)
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=100, interval=20)
rc('animation', html='jshtml')
HTML(anim.to_html5_video())
But this is the output that is rendered :
How to dynamically update the graph with data ?
Using line.set_data([1,random.randint(100,101)], [1,random.randint(100,101)]) is the not the correct method to add data ?
For now I'm just attempting to update within the result of a call to random but I plan to use this with the result of a REST service.
Related
first I would like to share the data of csv file.
date, total_cases, total_deaths
12-5-2020,6,2
13-5-2020,7,3
14-5-2020,10,2
15-5-2020,18,5
Now I want to make an animated comparison graph where the x axis will be plotted the dates and y axis will be plotted the total_cases and total_deaths.
from matplotlib import dates as mdate
from matplotlib import pyplot as plt
import matplotlib.animation as animation
import pandas as pd
m=pd.read_csv("covid-data.csv")
m['date']=pd.to_datetime(m['date'])
m.sort_values('date',inplace=True)
cdate=m['date']
ccase=m['total_cases']
cdeath=m['total_deaths']
fig = plt.figure()
ax1 = fig.add_subplot(111)
def animate(i):
ax1.clear()
ax1.plot(cdate,ccase)
ax1.plot(cdate,cdeath)
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
Now
I can't get our desired output or animation. How can I overcome this issue and get a solution?
Sorry for my english
Check this code:
from matplotlib import dates as mdate
from matplotlib import pyplot as plt
import matplotlib.animation as animation
import pandas as pd
m = pd.read_csv("covid-data.csv")
m['date'] = pd.to_datetime(m['date'], format = '%d-%m-%Y')
m.sort_values('date', inplace = True)
cdate = m['date']
ccase = m['total_cases']
cdeath = m['total_deaths']
fig = plt.figure()
ax1 = fig.add_subplot(111)
def animate(i):
ax1.clear()
ax1.plot(cdate[:i], ccase[:i], label = 'cases')
ax1.plot(cdate[:i], cdeath[:i], label = 'deaths')
ax1.legend(loc = 'upper left')
ax1.set_xlim([cdate.iloc[0],
cdate.iloc[-1]])
ax1.set_ylim([min(ccase.iloc[0], cdeath.iloc[0]),
max(ccase.iloc[-1], cdeath.iloc[-1])])
ax1.xaxis.set_major_locator(mdate.DayLocator(interval = 5))
ax1.xaxis.set_major_formatter(mdate.DateFormatter('%d-%m-%Y'))
ani = animation.FuncAnimation(fig, animate, interval = 1000)
plt.show()
I changed your animate function in order to use the i counter (which increases by 1 at each frame). You can control what you want to change during the animation with this counter. The I added some formatting in order to improve the visualization. The code above gives me this animation:
In order to get an appreciable animation, I added some "fake" data to the one you provided, in order to have more days over which run the animation. Replace them with your data.
In the case of the error
TypeError: 'builtin_function_or_method' object is not subscriptable
Replace the .iloc[0] with [m.index[0]] and the same for .iloc[-1] with [m.index[-1]]. For example ccase.iloc[0] becomes ccase[m.index[0]].
I have dataframes which I am trying to plot them in one single plot.
However, it needs to be step-by-step by iteration. Like the one single plot should be updated at each time loop runs.
What I am trying now is
for i in range(0, len(df))
plt.plot(df[i].values[:,0], df[i].values[:,1])
plt.show()
It seems work but it generates a graph at each iteration.
I want them all to be in one plot as it is being updated.
Thanks for your help.
Edit: Regarding the answers, you referred does not contain what I wanted.
That one is just superimposing two datasets.
What I wanted was that as a new graph is superimposed, the original figure created should be updated at the next iteration, not showing them all at once after the end of the loop.
Here's an example of a plot that gets updated automatically using matplotlib's animation feature. However, you could also call the update routine yourself, whenever necessary:
import numpy as np
import matplotlib.pyplot as plt
import pandas
import matplotlib.animation as animation
from matplotlib.animation import FuncAnimation
df = pandas.DataFrame(data=np.linspace(0, 100, 101), columns=["colA"])
fig = plt.figure()
ax = plt.gca()
ln, = ax.plot([], [], "o", mew=2, mfc="None", ms=15, mec="r")
class dataPlot(object):
def __init__(self):
self.objs = ax.plot(df.loc[0,"colA"], "g*", ms=15, mew=2, mec="g", mfc="None", label="$Data$")
fig.legend(self.objs, [l.get_label() for l in self.objs], loc="upper center", prop={"size":18}, ncol=2)
def update(self, iFrame):
for o in self.objs:
o.remove()
print("Rendering frame {:d}".format(iFrame))
self.objs = ax.plot(df.loc[iFrame,"colA"], "g*", ms=15, mew=2, mec="g", mfc="None", label="$Data$")
return ln,
dp = dataPlot()
ani = FuncAnimation(fig, dp.update, frames=df.index, blit=True)
plt.show()
I'm using Python 3.6 in jupyter notebook. plt.close does not close plot. I tried with plt.ion() also and many other ways.
I want to display image, then wait for pause or input() and then remove the previous image and show the new one.
import matplotlib.pyplot as plt
from time import sleep
from scipy import eye
plt.imshow(eye(3))
plt.show()
sleep(1)
plt.close()
Here is an example that shows a sequence of plots, each for one second. Essential are the commants plt.show(block = False) and plt.pause(1) instead of sleep(1):
import numpy as np
import matplotlib.pyplot as plt
def show_image(n):
fig, ax = plt.subplots()
x = np.linspace(0,1,100)
y = x**n
ax.plot(x,y, label = 'x**{}'.format(n))
ax.legend()
plt.show(block=False)
plt.pause(1)
plt.close(fig)
for i in range(10):
show_image(i)
If I understand correctly, what you want is to show a plot, wait 1 second, then let it close automatically.
This would be achieved as follows.
import matplotlib.pyplot as plt
from scipy import eye
plt.imshow(eye(3))
def show_and_close(sec):
timer = plt.gcf().canvas.new_timer(interval=sec*1000)
timer.add_callback(lambda : plt.close())
timer.single_shot = True
timer.start()
plt.show()
show_and_close(1)
I have a python animation script (using matplotlib's funcAnimation), which runs in Spyder but not in Jupyter. I have tried following various suggestions such as adding "%matplotlib inline" and changing the matplotlib backend to "Qt4agg", all without success. I have also tried running several example animations (from Jupyter tutorials), none of which have worked. Sometimes I get an error message and sometimes the plot appears, but does not animate. Incidentally, I have gotten pyplot.plot() to work using "%matplotlib inline".
Does anyone know of a working Jupyter notebook with a simple inline animation example that uses funcAnimation.
[Note: I am on Windows 7]
notebook backend
'Inline' means that the plots are shown as png graphics. Those png images cannot be animated. While in principle one could build an animation by successively replacing the png images, this is probably undesired.
A solution is to use the notebook backend, which is fully compatible with FuncAnimation as it renders the matplotlib figure itself:
%matplotlib notebook
jsanimation
From matplotlib 2.1 on, we can create an animation using JavaScript. This is similar to the ani.to_html5() solution, except that it does not require any video codecs.
from IPython.display import HTML
HTML(ani.to_jshtml())
Some complete example:
import matplotlib.pyplot as plt
import matplotlib.animation
import numpy as np
t = np.linspace(0,2*np.pi)
x = np.sin(t)
fig, ax = plt.subplots()
ax.axis([0,2*np.pi,-1,1])
l, = ax.plot([],[])
def animate(i):
l.set_data(t[:i], x[:i])
ani = matplotlib.animation.FuncAnimation(fig, animate, frames=len(t))
from IPython.display import HTML
HTML(ani.to_jshtml())
Alternatively, make the jsanimation the default for showing animations,
plt.rcParams["animation.html"] = "jshtml"
Then at the end simply state ani to obtain the animation.
Also see this answer for a complete overview.
There is a simple example within this tutorial here: http://louistiao.me/posts/notebooks/embedding-matplotlib-animations-in-jupyter-notebooks/
To summarise the tutorial above, you basically need something like this:
from matplotlib import animation
from IPython.display import HTML
# <insert animation setup code here>
anim = animation.FuncAnimation() # With arguments of course!
HTML(anim.to_html5_video())
However...
I had a lot of trouble getting that to work. Essentially, the problem was that the above uses (by default) ffmpeg and the x264 codec in the background but these were not configured correctly on my machine. The solution was to uninstall them and rebuild them from source with the correct configuration. For more details, see the question I asked about it with a working answer from Andrew Heusser: Animations in ipython (jupyter) notebook - ValueError: I/O operation on closed file
So, try the to_html5_video solution above first, and if it doesn't work then also try the uninstall / rebuild of ffmpeg and x264.
Another option:
import matplotlib.animation
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams["animation.html"] = "jshtml"
plt.rcParams['figure.dpi'] = 150
plt.ioff()
fig, ax = plt.subplots()
x= np.linspace(0,10,100)
def animate(t):
plt.cla()
plt.plot(x-t,x)
plt.xlim(0,10)
matplotlib.animation.FuncAnimation(fig, animate, frames=10)
Here is the answer that I put together from multiple sources including the official examples. I tested with the latest versions of Jupyter and Python.
Download FFmpeg ( http://ffmpeg.zeranoe.com/builds/ )
Install FFmpeg making sure that you update the environmental variable ( http://www.wikihow.com/Install-FFmpeg-on-Windows ).
Run this script in Jupyter below. The variable imageList is the only thing that you need to modify. It is an list of images (your input).
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
from IPython.display import HTML
#=========================================
# Create Fake Images using Numpy
# You don't need this in your code as you have your own imageList.
# This is used as an example.
imageList = []
x = np.linspace(0, 2 * np.pi, 120)
y = np.linspace(0, 2 * np.pi, 100).reshape(-1, 1)
for i in range(60):
x += np.pi / 15.
y += np.pi / 20.
imageList.append(np.sin(x) + np.cos(y))
#=========================================
# Animate Fake Images (in Jupyter)
def getImageFromList(x):
return imageList[x]
fig = plt.figure(figsize=(10, 10))
ims = []
for i in range(len(imageList)):
im = plt.imshow(getImageFromList(i), animated=True)
ims.append([im])
ani = animation.ArtistAnimation(fig, ims, interval=50, blit=True, repeat_delay=1000)
plt.close()
# Show the animation
HTML(ani.to_html5_video())
#=========================================
# Save animation as video (if required)
# ani.save('dynamic_images.mp4')
If you have a list of images and want to animate through them, you can use something like this:
from keras.preprocessing.image import load_img, img_to_array
from matplotlib import animation
from IPython.display import HTML
import glob
%matplotlib inline
def plot_images(img_list):
def init():
img.set_data(img_list[0])
return (img,)
def animate(i):
img.set_data(img_list[i])
return (img,)
fig = figure()
ax = fig.gca()
img = ax.imshow(img_list[0])
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=len(img_list), interval=20, blit=True)
return anim
imgs = [img_to_array(load_img(i)) for i in glob.glob('*.jpg')]
HTML(plot_images(imgs).to_html5_video())
Thank to Kolibril. I finally can run animation on Jupyter and Google Colab.
I modify some code which will generate animation of drawing random line instead.
import matplotlib.animation
import matplotlib.pyplot as plt
from itertools import count
import random
plt.rcParams["animation.html"] = "jshtml"
plt.rcParams['figure.dpi'] = 150
fig, ax = plt.subplots()
x_value = []
y_value = []
index = count();
def animate(t):
x_value.append(next(index))
y_value.append(random.randint(0,10))
ax.cla()
ax.plot(x_value,y_value)
ax.set_xlim(0,10)
matplotlib.animation.FuncAnimation(fig, animate, frames=10, interval = 500)
enter image description here
I want to save the output animation of the following program in mp4. The program does create a mp4 file, but the file is a blank file it does not contain the animation I wanted. What am I doing wrong here?
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import matplotlib.animation as animation
plt.rcParams['animation.ffmpeg_path'] ='C:\\ffmpeg\\bin\\ffmpeg.exe'
fig=plt.figure()
ax=fig.add_subplot(111,projection="3d")
x=np.linspace(100,150,100)
t=(x-100)/0.5
y=-.01*np.cos(t)+.5*np.sin(t)+100.01
z=.01*np.sin(t)+.5*np.cos(t)+99.5
def animate(i):
line.set_data(x[:i],y[:i])
line.set_3d_properties(z[:i])
ax.set_xlim3d([min(x),max(x)])
ax.set_ylim3d([min(y),max(y)])
ax.set_zlim3d([min(z),max(z)])
ax.set_title("Particle in magnetic field")
ax.set_xlabel("X")
ax.set_xlabel("Y")
ax.set_xlabel("Z")
line,=ax.plot([],[],[])
lin_ani=animation.FuncAnimation(fig,animate)
plt.legend()
FFwriter = animation.FFMpegWriter()
lin_ani.save('animation.mp4', writer = FFwriter, fps=10)
# plt.show()
As I learn up to know, you should write like this:
FFwriter = animation.FFMpegWriter(fps=10)
lin_ani.save('animation.mp4', writer = FFwriter)
I learned this from this site1
Add this line at the end of your function
return line,
so a complete function should look like:
def animate(i):
line.set_data(x[:i],y[:i])
line.set_3d_properties(z[:i])
return line,