0

Because i noticed that anim.save takes exponentially longer as more points are plotted, i'm trying to export animations of 400 points and then using ffmpeg to glue them together. However, i'm running into a TypeError: 'tuple' object is not callable and i have been unable to progress.

To accomplish this btw, i create a init function that instead of cleaning the canvas, plots all the previously plotted points statically and then i draw starting from there

My animation function:

def animate(i, pplotted):

    Pot = GenPwr[pplotted:i]
    t_pot = Time[pplotted:i]
    RotSp = RotSpeed[pplotted:i]
    RotTh = RotThrust[pplotted:i]
    WindV = WindVel[pplotted:i]

    # ___________GENPWR___________#
    ax1.text(max(Time) / 10, 1500, "GenPwr (kW)=" + str(GenPwr[i]), fontsize=8)
    ax1.set_xlabel("Time (s)").set_size(tittle_axes_size)
    ax1.grid(True, axis="y")

    # ___________ROTSPEED___________#
    ax2.text(
        max(Time) / 10,
        max(RotSpeed) / 13,
        "RotSpeed (rpm)=" + str(RotSpeed[i]),
        fontsize=8,
    )
    ax2.set_xlabel("Time (s)").set_size(tittle_axes_size)
    ax2.grid(True, axis="y")

    # ___________ROTTHRUST___________#
    ax3.text(
        max(Time) / 10,
        max(RotThrust) / 10,
        "RotThrust (kW)=" + str(RotThrust[i]),
        fontsize=8,
    )
    ax3.set_xlabel("Time (s)").set_size(tittle_axes_size)
    ax3.grid(True, axis="y")

    # ___________WINDVEL___________#
    ax4.text(
        max(Time) / 10, 1, "WindVel (m/s)=" + str(round(WindVel[i], 2)), fontsize=8
    )
    ax4.set_xlabel("Time (s)").set_size(tittle_axes_size)
    ax4.grid(True, axis="y")

    # updating line objects data
    line[0].set_data(t_pot, Pot)
    line[1].set_data(t_pot, RotSp)
    line[2].set_data(t_pot, RotTh)
    line[3].set_data(t_pot, WindV)

    return line,

my init function:

def init(pplotted, linesn, data):
    print(pplotted, linesn, data)
    for l in range(1, linesn + 1):
        print(l)
        line[l - 1].set_data(data[0][:pplotted], data[l][:pplotted])
    return line,

my animation call and save fragments loop:

fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, sharex=True)
plt.tight_layout()

(line1,) = ax1.plot([], [], lw=1)
(line2,) = ax2.plot([], [], lw=1, color="r")
(line3,) = ax3.plot([], [], lw=1, color="c")
(line4,) = ax4.plot([], [], lw=1, color="m")
line = [line1, line2, line3, line4]

Pot = []
RotSp = []
RotTh = []
WindV = []
t_pot = []

dataPointsNumber = len(Time)
shards = int(dataPointsNumber / 400)

for shardN in range(1, shards + 1):
    Pot = GenPwr[: 400 * (shardN - 1)]
    t_pot = Time[: 400 * (shardN - 1)]
    RotSp = RotSpeed[: 400 * (shardN - 1)]
    RotTh = RotThrust[: 400 * (shardN - 1)]
    WindV = WindVel[: 400 * (shardN - 1)]

    data = [t_pot, Pot, RotSp, RotTh, WindV]

    anim = animation.FuncAnimation(
        fig,
        animate(400, pplotted=400 * (shardN - 1)),
        init_func=init(pplotted=400 * (shardN - 1), linesn=4, data=data),
        frames=400,
        interval=20,
        blit=True,
        cache_frame_data=False,
    )
    plt.show()

    writer = animation.writers["ffmpeg"](fps=240)
    anim.save("animation_shard_%s.mp4" %shardN, writer=writer, dpi=200)
ghylander
  • 136
  • 8
  • I know that the issue does not come from the init function, becuase i can remove the call in the animation object and it will return the same error – ghylander Aug 02 '21 at 07:06
  • Also, if someone could give me pointers to how to animate the text im ebedding on the plots, it would be great too – ghylander Aug 02 '21 at 07:12

1 Answers1

0

Update:

On the one hand, digging through the source code i found out that when you create the animation object you have to call the animation funcition without arguments, and the specify a list of arguments using fargs. Instead of:

anim = animation.FuncAnimation(
        fig,
        animate(400, pplotted=400 * (shardN - 1)),
        init_func=init(pplotted=400 * (shardN - 1), linesn=4, data=data),
        frames=400,
        interval=20,
        blit=True,
        cache_frame_data=False,
    )

You have to write it like so:

pplotted = (400 * (shardN - 1))
anim = animation.FuncAnimation(
        fig,
        animate,
        init_func=init(pplotted=400 * (shardN - 1), linesn=4, data=data),
        frames=400,
        interval=20,
        blit=True,
        fargs=[pplotted]
        cache_frame_data=False,
    )

On the other hand, the init func must be called without arguments too. However, if no init function is specified, in the loop i created the same fig is constantly reused, so the plotting of new points will be always carried out over a "drawn" canvas

ghylander
  • 136
  • 8