maxhumber / gif

The matplotlib Animation Extension

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Issues with decorated function arguments used for conditionals, and non-looping gifs

davidwych opened this issue · comments

In trying to plot an audio signal stored in the array piano as a function of time t, in increments of 1000 elements, with various parts of the signal highlighted as the animation goes on with axvspan, I created the function:

image

@gif.frame
def plot_progression(T):
    #f, ax = plt.subplots(figsize=(6,4), dpi=100)
    plt.plot(t[:(T+1)*1000], piano[0][:(T+1)*1000], c="k", alpha=0.7)
    plt.xlabel("Time (seconds)")
    plt.ylabel("Amplitude (?)")
    plt.xlim([0,20])
    plt.ylim([-0.4, 0.4])
    if 1.8 < t[T] < 4.5:
        plt.axvspan(1.8, t[T], facecolor="Red", ls="--", lw=2.0, label=r"$C_{3}$", alpha=0.2)
    elif t[T] > 4.5:
        plt.axvspan(1.8, 4.5, facecolor="Red", ls="--", lw=2.0, label=r"$C_{3}$", alpha=0.2)
        plt.legend(fontsize="small")
    elif 5.5 < t[T] < 7.8:
        plt.axvspan(5.5, t[T], facecolor="Orange", ls="--", lw=2.0, label=r"$E_{3}$", alpha=0.2)
    elif t[T] > 7.8:
        plt.axvspan(5.5, 7.8, facecolor="Orange", ls="--", lw=2.0, label=r"$E_{3}$", alpha=0.2)
    elif 8.9 < t[T] < 11.2:
        plt.axvspan(8.9, t[T], facecolor="Green", ls="--", lw=2.0, label=r"$G_{3}$", alpha=0.2)
    elif t[T] > 11.2:
        plt.axvspan(8.9, 11.2, facecolor="Green", ls="--", lw=2.0, label=r"$G_{3}$", alpha=0.2)
    elif 12.2 < t[T] < 15.3:
        plt.axvspan(12.2, t[T], facecolor="Purple", ls="--", lw=2.0, label=r"$C_{maj}$", alpha=0.2)
    elif t[T] > 15.3:
        plt.axvspan(12.2, 15.3, facecolor="Purple", ls="--", lw=2.0, label=r"$C_{maj}$", alpha=0.2)

with the gif creation loop:

frames = []
for T in range(382):
    frame = plot_progression(T)
    frames.append(frame)
    del frame
    
gif.save(frames, "./audio_progression.gif", duration=45.4)

Problem is, none of the conditionals ever get triggered. All I get is the audio signal, no vspans or inclusion of the legend elements:

audio_progression


Also, is there any way to have the gif not loop? I know in gif.py the setting have loop=0 what do we set that to to get it to not loop? Can this be added as an argument to gif.save()?

Hey @davidwych! Thanks for the issue and suggestion.

I can look at adding the non-loop parameter 👍 Can I ask why you want it? I've never had a scenario when I didn't want something to loop.

As for the other issue. Could you drop in your data, so I can poke at it?

@maxhumber

(1) The non-loop functionality would be useful for "one-time use" animations (e.g. in my case I'm creating this gif for a slide in a presentation, so I really just need the animation to run through once and then stay in the form it's in at the last frame for the remaining time I'm presenting the slide).

(2) Here's the piano data:
piano.npy.zip

to load it:

piano = np.load("piano.npy")
t = np.linspace(0, len(piano)/22050, len(piano))

n.b. in the code above: replace piano[0] with just piano

Okay, figured out your first thing!

Seems like you need to adjust your ifs. Basically, you need two for every note. One to track the note, and another to keep the color turned on.

See this reproducible example:

import gif
from matplotlib import pyplot as plt

x = list(range(100))
y = [10] * len(x)

@gif.frame
def plot(i):
    plt.plot(x[:i], y[:i])
    plt.xlim([0, max(x)])
    plt.ylim([0, max(y) * 2])
    # track the RED note
    if x[i] > 50 and x[i] < 70:
        plt.axvspan(50, x[i-1], facecolor="Red", ls="--", lw=2.0, alpha=0.2)
    # track the BLUE note
    if x[i] > 80 and x[i] < 90:
        plt.axvspan(80, x[i-1], facecolor="Blue", ls="--", lw=2.0, alpha=0.2)
    # make sure the RED stays on
    if x[i] >= 70:
        plt.axvspan(50, 70, facecolor="Red", ls="--", lw=2.0, alpha=0.2)
    # make sure the BLUE stays on
    if x[i] >= 90:
        plt.axvspan(80, 90, facecolor="Blue", ls="--", lw=2.0, alpha=0.2)

frames = []
for i in range(len(x)):
    frame = plot(i)
    frames.append(frame)

gif.save(frames, 'piano.gif', duration=30)

Output:

piano

As for the non-looping. Let me meditate on it... for now... just skip the slide a millisecond before it finishes 🤣

Thanks so much! Sorry if this wasn't really an "issue" so much as me not knowing how conditionals work... :|

I thought maybe it had something to do with how arguments are handled by the decorator.