Matplotlib animate plot - Figure not responding until loop is done - python

I am trying to animate a plot where my two vectors X,Y are updating through a loop.
I am using FuncAnimation. The problem I am running into is the Figure would show Not Responding or Blank until the loop is completed.
So during the loop, I would get something like:
But if I stopped the loop or at the end, the figure would appear.
I have set my graphics backend to automatic.
Here is the example of the code:
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
def animate( intermediate_values):
x = [i for i in range(len(intermediate_values))]
y = intermediate_values
plt.cla()
plt.plot(x,y, label = '...')
plt.legend(loc = 'upper left')
plt.tight_layout()
x = []
y = []
#plt.ion()
for i in range(50):
x.append(i)
y.append(i)
ani = FuncAnimation(plt.gcf(), animate(y), interval = 50)
plt.tight_layout()
#plt.ioff()
plt.show()

The structure of animation in matplotlib is that the animation function is not used in the loop process, but the animation function is the loop process. After setting up the initial graph, the animation function will update the data.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
x = []
y = []
fig = plt.figure()
ax = plt.axes(xlim=(0,50), ylim=(0, 50))
line, = ax.plot([], [], 'b-', lw=3, label='...')
ax.legend(loc='upper left')
def animate(i):
x.append(i)
y.append(i)
line.set_data(x, y)
return line,
ani = FuncAnimation(fig, animate, frames=50, interval=50, repeat=False)
plt.show()

Related

How to show only 'x' amount of values on a graph in python

I am new to python and am carrying out some little projects along side watching tutorials to enable me to learn.
I have recently been working with some APIs to collect data - I save this data in a CSV file and then open the CSV file to show the data as a graph.
I want the graph to show the data LIVE, but in doing so I only want 10 values on the screen at once, so when the 11th value is plotted, the 1st is no longer visible unless the scrolling function is used to look back at it..
I have managed to pull together the code that plots the live data from the CSV file, as well as some code that creates the graph in the desired format - but as I am quite new to python I am unsure of how I'd make them work together.. Any advice would be greatly appreciated.
Below is the code that I have created to read and plot from a CSV file:
import random
from itertools import count
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
index = count()
def animate(i):
data = pd.read_csv('x.csv')
x = data['Time']
y = data['R1Temp']
y1 = data['R2Temp']
y2 = data['R3Temp']
plt.cla()
plt.plot(x, y, marker = 'o', label='Room 1 Temp')
plt.plot(x, y1, marker = 'o', label='Room 2 Temp')
plt.plot(x, y2, marker = 'o', label='Room 3 Temp')
plt.xlabel("Time")
plt.ylabel("Temperature °C")
plt.title("Live temperature of Rooms")
plt.legend(loc='upper left')
plt.tight_layout()
ani = FuncAnimation(plt.gcf(), animate, interval=1000)
plt.tight_layout()
plt.show()
Below is the code that shows the way in which I'd like the graph to format the data plots:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
def update(frame):
global x, y
start = x[max(frame-PAN//2, 0)]
start = x[max(frame-PAN+1, 0)]
end = start + PAN
ax.set_xlim(start, end)
start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end, TICK))
ax.figure.canvas.draw()
line1.set_data(x[0:frame+1], y[0:frame+1])
return (line1,)
# main
NUM = 100
TICK = 1
PAN = 10
x = np.arange(start=1, stop=NUM + 1, step=1)
for i in range(NUM):
y = np.random.rand(NUM) * 100
fig, ax = plt.subplots()
ax.set_xlim(0, PAN)
start, end = ax.get_xlim()
ax.xaxis.set_ticks(np.arange(start, end, TICK))
ax.set_ylim(0, 100)
line1, = ax.plot([], [], color="r")
ani = animation.FuncAnimation(fig, update, frames=len(x), interval=1000, repeat=False)
plt.show()
I have tried many ways to merge them together, but I just cant seem to find the correct way to go about it.
Thanks in advance!!
Showing the last N time points is quite easy. Just use DataFrame.tail() to get the last N rows of your dataframe.
Note that when doing an animation, the recommended way is to create your axes and artists outside the animation code, and only update your artists' data inside the animate code.
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
fig, ax = plt.subplots()
l1, = ax.plot([], [], marker='o', label='Room 1 Temp')
l2, = ax.plot([], [], marker='o', label='Room 2 Temp')
l3, = ax.plot([], [], marker='o', label='Room 3 Temp')
plt.xlabel("Time")
plt.ylabel("Temperature °C")
plt.title("Live temperature of Rooms")
plt.legend(loc='upper left')
plt.tight_layout()
def animate(i, N):
data = pd.read_csv('x.csv').tail(N)
l1.set_data(data['Time'], data['R1Temp'])
l2.set_data(data['Time'], data['R2Temp'])
l3.set_data(data['Time'], data['R3Temp'])
ax.relim()
ax.autoscale_view()
return l1, l2, l3
ani = FuncAnimation(fig, animate, interval=1000, frames=None, fargs=(10,))
plt.show()

Changing graphs in real-time using matplotlib

This is the code.
import matplotlib.pyplot as plt
import random
x = []
y = []
for i in range(10):
x.append(i)
y.append(random.randint(0,100))
graph = plt.bar(x,y)
plt.show()
Whenever I change any value of y, say y[4] = 7, then I want that to be
reflected in the graph. I want that graph to move.
I tried searching the solution for this but none of them worked for me.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import random
x = []
y = []
for i in range(10):
x.append(i)
y.append(random.randint(0,100))
fig, ax = plt.subplots()
bar, = ax.plot(x,y)
def animate(i):
x = []
y = []
for i in range(10):
x.append(i)
y.append(random.randint(0,100))
bar.set_xdata(x)
bar.set_ydata(y)
return bar,
animation = FuncAnimation(fig, animate, interval = 1000)
plt.show()
I want similar results, but in form of bar graph. Any help is appreciated.
The data displayed in the bar chart is not linked to the data in your list. There is no listener attached to the list that lets pyplot know when the list has been modified.
You will need to change the heights of the bars manually. You can do this by grabbing the children of your graph object, which is a list of bars, and updating the height of the bar.
Please note, the code below works because x and the indices of the bars are the same. If x started at 1 or a was range(0, 100, 10), the code gets more complicated.
import matplotlib.pyplot as plt
import random
# turn on interactive graphing
plt.ion()
x = []
y = []
for i in range(10):
x.append(i)
y.append(random.randint(0,100))
graph = plt.bar(x,y)
plt.show()
y[4] = 7
graph.get_children()[4].set_height(7)
Finally got what I wanted
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import random
X = []
Y = []
for i in range(20):
Y.append(random.randint(1, 100))
X.append(i)
fig, ax = plt.subplots(figsize=(10, 6))
ax.bar(X, Y, color="#ff7f7f")
ax.set_yticks([])
ax.set_xticks(X)
for number in range(len(Y)):
ax.text(number, Y[number], Y[number],
horizontalalignment='center', va="baseline", fontsize=13)
def draw_barchart(year):
ax.clear()
X.clear()
Y.clear()
for i in range(20):
Y.append(random.randint(1, 100))
X.append(i)
ax.bar(X, Y, color="#ff7f7f")
ax.set_yticks([])
ax.set_xticks(X)
ax.set_yticks([])
ax.set_xticks(X)
for number in range(len(Y)):
ax.text(number, Y[number], Y[number], horizontalalignment='center', va="baseline", fontsize=13)
plt.box(False)
animator = animation.FuncAnimation(fig, draw_barchart, interval=1000)
plt.show()

Extra Figure in Matplotlib Animation using Smopy

I'm trying to create an animated map plot using smopy and matplotlib in jupyter, but when I run the code I get two figures instead of one. The first figure is shown above the map and empty. Can anyone tell me how to fix this so that only the animation is drawn?
import smopy
import matplotlib.animation as animation
n= 1000
%matplotlib notebook
def update(curr):
if curr == n-100:
a.event_source.stop()
lons = crime_df.X[curr:curr+100]
lats = crime_df.Y[curr:curr+100]
x,y = map.to_pixels(lats,lons)
ax.scatter(x, y, c='r', alpha=0.7, s=200)
plt.title(curr)
fig = plt.figure()
ax = smopy.Map((37.6624,-122.5168,37.8231,-122.3589), z=12)
ax = ax.show_mpl(figsize=(8,8))
a = animation.FuncAnimation(fig, update, interval=100)
You should not create an additional figure, if that is undersired: Leave out plt.figure().
import smopy
import matplotlib.pyplot as plt
import matplotlib.animation as animation
n= 1000
%matplotlib notebook
def update(curr):
if curr == n-100:
a.event_source.stop()
lons = crime_df.X[curr:curr+100]
lats = crime_df.Y[curr:curr+100]
x,y = map.to_pixels(lats,lons)
ax.scatter(x, y, c='r', alpha=0.7, s=200)
plt.title(curr)
m = smopy.Map((37.6624,-122.5168,37.8231,-122.3589), z=12)
ax = m.show_mpl(figsize=(8,8))
a = animation.FuncAnimation(ax.figure, update, interval=100)
Alternatively create the figure beforehands,
fig, ax = plt.subplots(figsize=(8,8))
m = smopy.Map((37.6624,-122.5168,37.8231,-122.3589), z=12)
m.show_mpl(ax = ax)
a = animation.FuncAnimation(fig, update, interval=100)

Not able to plot real time graph using matplotlib

I have written the following code with the help of online search. My intention here is to get a real time graph with time on x axis and some randomly generated value on y axis
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
import numpy as np
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
def animate(i):
xar = []
yar = []
x,y = time.time(), np.random.rand()
xar.append(x)
yar.append(y)
ax1.clear()
ax1.plot(xar,yar)
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()
With the above code I just see the range of y axis changing continuously and the graph will not appear in the figure.
The problem is that you never update xvar and yvar. You can do that by moving the definitions of the lists outside the definition of animate.
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
import numpy as np
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
xar = []
yar = []
def animate(i):
x,y = time.time(), np.random.rand()
xar.append(x)
yar.append(y)
ax1.clear()
ax1.plot(xar,yar)
ani = animation.FuncAnimation(fig, animate, interval=1000)
plt.show()

Syntax for plotting three points' movement using FuncAnimation

My code:
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d')
def animate(i):
ax.set_data(ax.scatter(ptx1, pty1, ptz1, c='red'),
ax.scatter(ptx2, pty2, ptz2, c='blue'),
ax.scatter(ptx3, pty3, ptz3, c='green'))
ani = FuncAnimation(fig, animate, frames=10, interval=200)
plt.show()
I'm trying to plot the movement of three points. Each ptx/y/z/1/2/3 is a list of floats giving the coordinates of the point. I'm just not sure how to use FuncAnimation to animate my points. Any help would be greatly appreciated!
Simple example. animate is called many times and everytime you have to use different data to see animation.
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import random
# create some random data
ptx1 = [random.randint(0,100) for x in range(20)]
pty1 = [random.randint(0,100) for x in range(20)]
fig = plt.figure()
ax = fig.add_subplot(111)
def animate(i):
# use i-th elements from data
ax.scatter(ptx1[:i], pty1[:i], c='red')
# or add only one element from list
#ax.scatter(ptx1[i], pty1[i], c='red')
ani = FuncAnimation(fig, animate, frames=20, interval=500)
plt.show()

Categories