Reputation: 41
Just for fun, I wanted to draw a circle and then continue into the sine wave for this circle.
Now, I have an error that I can't seem to get around: the " tail," which erases the circle, is connected to the point at which the circle ends.
Below is the code; I shall also attach an image of what I mean.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
# Generate circle data
theta = np.linspace(0, 2 * np.pi, 500) # Parameter for the circle
x_circle = np.cos(theta) # x-coordinate of the circle
y_circle = np.sin(theta) # y-coordinate of the circle
# Generate sine wave data
x_sine = np.linspace(0, 2 * np.pi, 500) # Sine wave parameter
y_sine = np.sin(x_sine) # Sine wave amplitude
# Align sine wave's starting point to the circle's last point
x_sine += x_circle[-1] # Add the circle's last x-coordinate
y_sine += y_circle[-1] # Add the circle's last y-coordinate
# Concatenate circle and sine wave data
x_combined = np.concatenate((x_circle, x_sine))
y_combined = np.concatenate((y_circle, y_sine))
# Create figure and axis for the animation
fig, ax = plt.subplots()
ax.set_aspect('equal')
ax.set_xlim(-1.5, x_sine[-1] + 0.5) # Adjust limits based on combined motion
ax.set_ylim(-1.5, 1.5)
ax.axis('off')
# Initialize the plot elements
line, = ax.plot([], [], lw=2, color='black') # Snake path
head, = ax.plot([], [], 'o', color='red') # "Head" of the snake
tail, = ax.plot([], [], 'o', color='blue') # "Tail" of the snake
def update(frame):
total_circle_frames = len(x_circle)
total_sine_frames = len(x_sine)
if frame < total_circle_frames:
# Stage 1: Draw the circle
line.set_data(x_circle[:frame], y_circle[:frame])
head.set_data([x_circle[frame]], [y_circle[frame]])
tail.set_data([], []) # Tail not visible during this stage
else:
# Stage 2: Transition to sine wave, tail erases the circle
head_frame = frame - total_circle_frames
tail_frame = frame - total_circle_frames
# Separate line parts: circle and sine wave
circle_part_x = []
circle_part_y = []
sine_part_x = []
sine_part_y = []
# Head draws the sine wave
if head_frame < total_sine_frames:
sine_part_x = x_sine[:head_frame]
sine_part_y = y_sine[:head_frame]
head.set_data([x_sine[head_frame]], [y_sine[head_frame]])
else:
sine_part_x = x_sine
sine_part_y = y_sine
head.set_data([], []) # Head disappears after completing the sine wave
# Tail erases the circle
if tail_frame < total_circle_frames:
erase_index = total_circle_frames - tail_frame - 1
circle_part_x = x_circle[:erase_index]
circle_part_y = y_circle[:erase_index]
tail.set_data([x_circle[erase_index]], [y_circle[erase_index]])
else:
tail_frame_in_sine = tail_frame - total_circle_frames
tail.set_data([x_sine[tail_frame_in_sine]], [y_sine[tail_frame_in_sine]])
# Combine visible parts
line.set_data(
np.concatenate((circle_part_x, sine_part_x)),
np.concatenate((circle_part_y, sine_part_y))
)
return line, head, tail
# Create animation
anim = FuncAnimation(fig, update, frames=len(x_combined) + len(x_circle), interval=10, blit=True)
# Display the animation
plt.show()
I have tried to play around with the np.concatenate
to make it work, but anything that I edit with regards to it just breaks the drawing of the sine wave. I'd appreciate some help not only with fixing it but also to explain so that I can learn to understand what is causing this.
Upvotes: 4
Views: 47
Reputation: 2055
To have the expected animation, you can update the last part of the code by:
using "tail_frame:" instead of ":erase_index" to correctly erase the start of the circle
and by adding necessary values to sine_part_x and y to erase the start of the sine
if tail_frame < total_circle_frames:
circle_part_x = x_circle[tail_frame:]
circle_part_y = y_circle[tail_frame:]
tail.set_data([x_circle[tail_frame]], [y_circle[tail_frame]])
else:
tail_frame_in_sine = tail_frame - total_circle_frames
sine_part_x = x_sine[tail_frame_in_sine:]
sine_part_y = y_sine[tail_frame_in_sine:]
tail.set_data([x_sine[tail_frame_in_sine]], [y_sine[tail_frame_in_sine]])
Upvotes: 0