Durra durra
Durra durra

Reputation: 41

Removing unwanted connecting line with np.concatenate

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

Answers (1)

rehaqds
rehaqds

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

Related Questions