Below my code. Why doesn't title updates every tick? I read this: Matplotlib animation with blit -- how to update plot title? but it wasn't useful.
#! /usr/bin/python3
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import time
import random as rr
plt.rc('grid', color='#397939', linewidth=1, linestyle='-')
plt.rc('xtick', labelsize=10)
plt.rc('ytick', labelsize=5)
width, height = matplotlib.rcParams['figure.figsize']
size = min(width, height)
fig = plt.figure(figsize=(size, size))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True, facecolor='#cfd98c')
ax.set_rmax(20.0)
plt.grid(True)
plt.title("")
def data_gen(t=0):
tw = 0
phase = 0
ctn = 0
while True:
ctn += 1
if ctn == 1000:
phase=round(rr.uniform(0,180),0)
tw = round(rr.uniform(0,20),0)
ctn = 0
yield tw, phase
def update(data):
tw, phase = data
print(data)
ax.set_title("|TW| = {}, Angle: {}°".format(tw, phase))
arr1 = plt.arrow(phase, 0, 0, tw, alpha = 0.5, width = 0.080,
edgecolor = 'red', facecolor = 'red', lw = 2, zorder = 5)
return arr1,
ani = animation.FuncAnimation(fig, update, data_gen, interval=100, blit=True, repeat=False)
plt.show()
EDIT n. 1 After @eyllanesc answer, I edit this piece of code:
def data_gen(t=0):
tw = 10
phase = 0
ctn = 0
while True:
if phase < 2*180:
phase += 1
else:
phase=0
yield tw, phase
def update(data):
tw, phase = data
angolo = phase /180 * np.pi
print("|TW| = {}, Angle = {}°".format(tw,phase))
ax.set_title("|TW| = {}, Angle: {}°".format(tw, phase))
arr1 = plt.arrow(angolo, 0, 0, tw, alpha = 0.5, width = 0.080, edgecolor = 'red', facecolor = 'red', lw = 2, zorder = 5)
plt.draw()
return arr1,
Now text works correctly, but the arrow updating is not "fluid" (it appeares and disappeares every update).
Matplotlib library of Python is a plotting tool used to plot graphs of functions or figures. It can also be used as an animation tool too. The plotted graphs when added with animations gives a more powerful visualization and helps the presenter to catch a larger number of audience.
Matplotlib can display plot titles centered, flush with the left side of a set of axes, and flush with the right side of a set of axes. Automatic positioning can be turned off by manually specifying the y keyword argument for the title or setting rcParams["axes. titley"] (default: None ) in the rcParams.
The problem arises when using blit=True
in the FuncAnimation
. This will store the background and only update the artists returned by the update function. However, the restored background will overwrite the title, since it is outside the axes.
Possible solutions are:
ArtistAnimation
instead of a FuncAnimation
would work as well. But I haven't tested it.Note that using plt.draw
or similar inside the updating function (as proposed in other answers) does not make sense, since it destroys all the advatages of using blitting and makes the animation even slower than in the case of not using blitting.
blit=True
)Instead of a title outside the axes, you may use a title = ax.text(..)
positionned inside the axes. This text can be updated for each iteration title.set_text("..")
and must then be returned by the updating function (return arr1, title,
).
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
plt.rc('grid', color='#397939', linewidth=1, linestyle='-')
plt.rc('xtick', labelsize=10)
plt.rc('ytick', labelsize=5)
width, height = matplotlib.rcParams['figure.figsize']
size = min(width, height)
fig = plt.figure(figsize=(size, size))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True, facecolor='#cfd98c')
ax.set_rmax(20.0)
plt.grid(True)
title = ax.text(0.5,0.85, "", bbox={'facecolor':'w', 'alpha':0.5, 'pad':5},
transform=ax.transAxes, ha="center")
def data_gen(t=0):
tw = 10
phase = 0
while True:
if phase < 2*180:
phase += 2
else:
phase=0
yield tw, phase
def update(data):
tw, phase = data
title.set_text(u"|TW| = {}, Angle: {}°".format(tw, phase))
arr1 = ax.arrow(np.deg2rad(phase), 0, 0, tw, alpha = 0.5, width = 0.080,
edgecolor = 'red', facecolor = 'red', lw = 2, zorder = 5)
return arr1,title,
ani = animation.FuncAnimation(fig, update, data_gen, interval=100, blit=True, repeat=False)
plt.show()
Note that I slightly changed the angle setting, since it the angle for arrow
must be in radiants instead of degrees.
blit=False
)You may decide not to use blitting, which makes sense when the requirements on the speed of the animation are not so high. Not using blitting allows to use a normal title outside the axes. However, in this case you would need to remove the artist for each iteration (otherwise one would end up with a lot of arrows in the plot).
import matplotlib
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
plt.rc('grid', color='#397939', linewidth=1, linestyle='-')
plt.rc('xtick', labelsize=10)
plt.rc('ytick', labelsize=5)
width, height = matplotlib.rcParams['figure.figsize']
size = min(width, height)
fig = plt.figure(figsize=(size, size))
ax = fig.add_axes([0.1, 0.1, 0.8, 0.8], polar=True, facecolor='#cfd98c')
ax.set_rmax(20.0)
plt.grid(True)
def data_gen(t=0):
tw = 10
phase = 0
while True:
if phase < 2*180:
phase += 2
else:
phase=0
yield tw, phase
arr1 = [None]
def update(data):
tw, phase = data
ax.set_title(u"|TW| = {}, Angle: {}°".format(tw, phase))
if arr1[0]: arr1[0].remove()
arr1[0] = ax.arrow(np.deg2rad(phase), 0, 0, tw, alpha = 0.5, width = 0.080,
edgecolor = 'red', facecolor = 'red', lw = 2, zorder = 5)
ani = animation.FuncAnimation(fig, update, data_gen, interval=100, blit=False, repeat=False)
plt.show()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With