Reputation: 247
I have written a code on Python for animating the 'Stereographic Projection' from the Cicle onto the Real line. I have defined three functions named update_plot()
,update_texts()
and create_animation()
.(As shown in the code below). Now for the animation purpose I have to pass the former two functions in the animation.FuncAnimation()
. So I try to create and empty list named anim = []
and append()
two animation object to it. Now the animation corresponding to the function update_plot()
is okay but the update_texts()
didn't work as I expected. Actually I want to update the coordinates of the points (R_x, R_y)
(given in the definition of update_text
) in every frame.
I cannot understand how to recover this problem. Please help. Thank you.
I also attached a picture of a moment of the output of the following code.
My Code:
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
W = 3
H = 1.2
mpl.rc('text', usetex=True)
mpl.rc('font', family='serif')
plt.style.use(['ggplot', 'dark_background'])
def create_circle(x, y):
circle = plt.Circle((x, y), radius=1, fill=False,
edgecolor='skyblue', lw=2)
return circle
def stereo_project(p):
x = p[0]
y = p[1]
# transformation
x1 = x / (1 - y)
y1 = 0
return x1, y1
def rotate(p, angle):
vec = np.array([p[0], p[1]]).reshape(2, 1)
theta = angle
R = np.array([[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]])
point = R.dot(vec)
return point[0][0], point[1][0]
def update_plot(angle, plot, plot1, plot2, plot3):
p = (0, 1)
R_x, R_y = rotate(p, angle)
SR_x, SR_y = stereo_project((R_x, R_y))
x = [p[0], R_x]
y = [p[1], R_y]
x1 = [R_x, SR_x]
y1 = [R_y, SR_y]
plot.set_data(x, y)
plot1.set_data(x1, y1)
plot2.set_data([R_x], [R_y])
plot3.set_data([SR_x], [SR_y])
return plot, plot1
def update_texts(angle):
p = (0, 1)
R_x, R_y = rotate(p, angle)
plt.text(R_x, R_y, '$({0:.2f}, {1:.2f})$'.format(R_x, R_y),
horizontalalignment='right',
verticalalignment='center', fontsize=15, color='orange')
def create_animation():
fig = plt.figure()
ax = plt.axes(xlim=(-W, W), ylim=(-H, H))
plot = plt.plot([], [], '-o', markersize=5, color='c')[0]
plot1 = plt.plot([], [], '-o', markersize=5, color='c')[0]
plot2 = plt.plot([], [], '-o', markersize=5, color='m')[0]
plot3 = plt.plot([], [], '-o', markersize=5, color='lime')[0]
ax.set_aspect('equal')
circle = create_circle(0, 0)
ax.add_patch(circle)
l1 = [-3, 3]
l2 = [0, 0]
plt.plot(l1, l2)
title = 'Stereographic Projection: $\mathbf{S^{1}} \setminus \{(0, 1)\}$ ' \
'to $\mathbf{R}$'
plt.title(title, color='orange', y=1.09)
plt.grid(False)
plt.gca().spines['left'].set_visible(False)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['bottom'].set_visible(False)
plt.gca().set_xticks([])
plt.gca().set_yticks([])
anim = []
anim.append(animation.FuncAnimation(fig, update_plot,
fargs=(plot, plot1, plot2, plot3),
frames=np.arange(0, 2 * np.pi, 0.01),
interval=50, repeat=True))
anim.append(animation.FuncAnimation(fig, update_texts,
frames=np.arange(0, 2 * np.pi, 0.01),
interval=50, repeat=True))
plt.show()
if __name__ == '__main__':
create_animation()
Upvotes: 1
Views: 293
Reputation: 5686
Text is an artist
, so you can animate it like any other artist
.
So, just as in your code you get a handle on the Line2D
object returned from plt.plot
and then update the lines with set_data
, you can get a handle on the text
instance created by plt.text
and update its position and text with text.set_text
and text.set_position
.
I also altered your code to handle updating the text and the lines in a single function.
With this I got
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import animation
W = 3
H = 1.2
mpl.rc('text', usetex=True)
mpl.rc('font', family='serif')
plt.style.use(['ggplot', 'dark_background'])
def create_circle(x, y):
circle = plt.Circle((x, y), radius=1, fill=False,
edgecolor='skyblue', lw=2)
return circle
def stereo_project(p):
x = p[0]
y = p[1]
# transformation
x1 = x / (1 - y)
y1 = 0
return x1, y1
def rotate(p, angle):
vec = np.array([p[0], p[1]]).reshape(2, 1)
theta = angle
R = np.array([[np.cos(theta), -np.sin(theta)],
[np.sin(theta), np.cos(theta)]])
point = R.dot(vec)
return point[0][0], point[1][0]
def update_plot(angle, text, plot, plot1, plot2, plot3):
p = (0, 1)
R_x, R_y = rotate(p, angle)
SR_x, SR_y = stereo_project((R_x, R_y))
x = [p[0], R_x]
y = [p[1], R_y]
x1 = [R_x, SR_x]
y1 = [R_y, SR_y]
plot.set_data(x, y)
plot1.set_data(x1, y1)
plot2.set_data([R_x], [R_y])
plot3.set_data([SR_x], [SR_y])
R_x, R_y = rotate(p, angle)
text.set_text('$({0:.2f}, {1:.2f})$'.format(R_x, R_y))
text.set_position((R_x, R_y))
return text, plot, plot1
def create_animation():
fig = plt.figure()
ax = plt.axes(xlim=(-W, W), ylim=(-H, H))
plot = plt.plot([], [], '-o', markersize=5, color='c')[0]
plot1 = plt.plot([], [], '-o', markersize=5, color='c')[0]
plot2 = plt.plot([], [], '-o', markersize=5, color='m')[0]
plot3 = plt.plot([], [], '-o', markersize=5, color='lime')[0]
ax.set_aspect('equal')
circle = create_circle(0, 0)
ax.add_patch(circle)
l1 = [-3, 3]
l2 = [0, 0]
plt.plot(l1, l2)
p = (0, 1)
R_x, R_y = rotate(p, 0)
text = plt.text(R_x, R_y, '$({0:.2f}, {1:.2f})$'.format(R_x, R_y),
horizontalalignment='right',
verticalalignment='center', fontsize=15, color='orange')
title = 'Stereographic Projection: $\mathbf{S^{1}} \setminus \{(0, 1)\}$ ' \
'to $\mathbf{R}$'
plt.title(title, color='orange', y=1.09)
plt.grid(False)
plt.gca().spines['left'].set_visible(False)
plt.gca().spines['top'].set_visible(False)
plt.gca().spines['right'].set_visible(False)
plt.gca().spines['bottom'].set_visible(False)
plt.gca().set_xticks([])
plt.gca().set_yticks([])
anim = []
anim.append(animation.FuncAnimation(fig, update_plot,
fargs=(text, plot, plot1, plot2, plot3),
frames=np.arange(0, 2 * np.pi, 0.01),
interval=50, repeat=True))
plt.show()
if __name__ == '__main__':
create_animation()
Upvotes: 1