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:
@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:
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
As for the other issue. Could you drop in your data, so I can poke at it?
(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 if
s. 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:
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.