0

I am trying to animate a figure with 3 subplots for some data from a tensor log. I've made generator and animation functions which appear to yield the correct data, however when I do plt.show(), nothing shows on the plot, and when I try to save as mp4, nothing is plotted on the generated video, and it only iterates up to the 100th value (out of 609) and then stops.

Here is the minimal code:

import os
import matplotlib.pyplot as plt
import numpy as np
import matplotlib

def gendat():

    res = list(np.random.random_sample(size=609))
    lens = list(np.random.random_sample(size=609))
    loss = list(np.random.random_sample(size=609))
    for i, (r, le, lo) in enumerate(zip(res,lens,loss)):
        yield i, r, le , lo


figure, axis = plt.subplots(1,3, figsize=(15,5))

line1, = axis[0].plot([],[])
axis[0].set_xlabel("Episodes")
axis[0].set_ylabel("Average Reward")
axis[0].set_title("Reward")

line2, = axis[1].plot([],[])
axis[1].set_xlabel("Episodes")
axis[1].set_ylabel("Average Episode Length")
axis[1].set_title("Episode Length")

line3, = axis[2].plot([],[])
axis[2].set_xlabel("Episodes")
axis[2].set_ylabel("Average Loss")
axis[2].set_title("Loss")

line = [line1,line2,line3]

def init():
    line[0].set_data([],[])
    line[1].set_data([],[])
    line[2].set_data([],[])

    return line

figure.tight_layout()

def animate(dat):

    i,r, le , lo = dat

    print("got",i,r,le,lo)
    line[0].set_data(i,r)
    line[1].set_data(i,le)
    line[2].set_data(i,lo)

    return line

FFwriter = matplotlib.animation.FFMpegWriter(fps=30, extra_args=['-vcodec', 'libx264'])
ani = matplotlib.animation.FuncAnimation(figure, animate, init_func=init, frames=gendat, interval=20, repeat=False, blit=True)

plt.show()

ani.save("results.mp4",writer=FFwriter, dpi=500)
#plt.savefig("results.png",transparent=True, dpi=500)
Trenton McKinney
  • 56,955
  • 33
  • 144
  • 158
scrungal
  • 13
  • 3

1 Answers1

0

Two things to fix:

  1. The axis limits for all subplots.
  2. set_data requires lists of coordinates, not numbers!
import os
import matplotlib.pyplot as plt
import numpy as np
import matplotlib

N = 609
def gendat():

    res = list(np.random.random_sample(size=609))
    lens = list(np.random.random_sample(size=609))
    loss = list(np.random.random_sample(size=609))
    for i, (r, le, lo) in enumerate(zip(res,lens,loss)):
        yield i, r, le , lo


figure, axis = plt.subplots(1,3, figsize=(15,5))

line1, = axis[0].plot([],[])
axis[0].set_xlabel("Episodes")
axis[0].set_ylabel("Average Reward")
axis[0].set_title("Reward")
axis[0].set_xlim(0, N)
axis[0].set_ylim(-10, 10)

line2, = axis[1].plot([],[])
axis[1].set_xlabel("Episodes")
axis[1].set_ylabel("Average Episode Length")
axis[1].set_title("Episode Length")
axis[1].set_xlim(0, N)
axis[1].set_ylim(-10, 10)

line3, = axis[2].plot([],[])
axis[2].set_xlabel("Episodes")
axis[2].set_ylabel("Average Loss")
axis[2].set_title("Loss")
axis[2].set_xlim(0, N)
axis[2].set_ylim(-10, 10)

line = [line1,line2,line3]

def init():
    line[0].set_data([],[])
    line[1].set_data([],[])
    line[2].set_data([],[])

    return line

figure.tight_layout()

def append_to_line(line, x, y):
    xd, yd = [list(t) for t in line.get_data()]
    xd.append(x)
    yd.append(y)
    line.set_data(xd, yd)
    print(xd)
    
def animate(dat):
    i, r, le, lo = dat

    append_to_line(line[0], i, r)
    append_to_line(line[1], i, le)
    append_to_line(line[2], i, lo)

# FFwriter = matplotlib.animation.FFMpegWriter(fps=30, extra_args=['-vcodec', 'libx264'])
ani = matplotlib.animation.FuncAnimation(figure, animate, frames=gendat, interval=20, repeat=False)

plt.show()

ani.save("results.mp4",writer=FFwriter, dpi=500)
Davide_sd
  • 10,578
  • 3
  • 18
  • 30
  • This is amazing cheers. Do you have any idea why the mp4 writer only does the first 100 frames though? it just stops at 99 for me. – scrungal May 03 '22 at 14:31
  • No idea, I never had to save an animation... Don't forget to mark this answer as the solution to the question! – Davide_sd May 03 '22 at 14:41