Python Forum
Unable to generate animation
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Unable to generate animation
#1
Hi. I was trying to follow the code in a book to generate an animation in Jupyter Lab. However, the system shows 'RuntimeError'. I have already installed ffmpeg.exe in the folder, so I am not sure why I get the runtime error. Any help is appreciated.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML

x = np.linspace(0, 2*np.pi, 100)
y = x* np.sin(2*x)
fig, ax = plt.subplots()
dot,=ax.plot([],[],'ro',markersize=12)
plt.close()

def init():
    ax.plot(x,y)
def animate(i):
    dot.set_data(x[i],y[i])

ani=FuncAnimation(fig=fig, func=animate, frames=100, init_func=init, interval=50)
HTML(ani.to_html5_video())
Error:
RuntimeError Traceback (most recent call last) Cell In[3], line 18 15 dot.set_data(x[i],y[i]) 17 ani=FuncAnimation(fig=fig, func=animate, frames=100, init_func=init, interval=50) ---> 18 HTML(ani.to_html5_video()) File C:\myWork\myVenv\Lib\site-packages\matplotlib\animation.py:1289, in Animation.to_html5_video(self, embed_limit) 1285 Writer = writers[mpl.rcParams['animation.writer']] 1286 writer = Writer(codec='h264', 1287 bitrate=mpl.rcParams['animation.bitrate'], 1288 fps=1000. / self._interval) -> 1289 self.save(str(path), writer=writer) 1290 # Now open and base64 encode. 1291 vid64 = base64.encodebytes(path.read_bytes()) File C:\myWork\myVenv\Lib\site-packages\matplotlib\animation.py:1105, in Animation.save(self, filename, writer, fps, dpi, codec, bitrate, extra_args, metadata, extra_anim, savefig_kwargs, progress_callback) 1102 for data in zip(*[a.new_saved_frame_seq() for a in all_anim]): 1103 for anim, d in zip(all_anim, data): 1104 # TODO: See if turning off blit is really necessary -> 1105 anim._draw_next_frame(d, blit=False) 1106 if progress_callback is not None: 1107 progress_callback(frame_number, total_frames) File C:\myWork\myVenv\Lib\site-packages\matplotlib\animation.py:1140, in Animation._draw_next_frame(self, framedata, blit) 1136 def _draw_next_frame(self, framedata, blit): 1137 # Breaks down the drawing of the next frame into steps of pre- and 1138 # post- draw, as well as the drawing of the frame itself. 1139 self._pre_draw(framedata, blit) -> 1140 self._draw_frame(framedata) 1141 self._post_draw(framedata, blit) File C:\myWork\myVenv\Lib\site-packages\matplotlib\animation.py:1766, in FuncAnimation._draw_frame(self, framedata) 1762 self._save_seq = self._save_seq[-self._save_count:] 1764 # Call the func with framedata and args. If blitting is desired, 1765 # func needs to return a sequence of any artists that were modified. -> 1766 self._drawn_artists = self._func(framedata, *self._args) 1768 if self._blit: 1770 err = RuntimeError('The animation function must return a sequence ' 1771 'of Artist objects.') Cell In[3], line 15, in animate(i) 14 def animate(i): ---> 15 dot.set_data(x[i],y[i]) File C:\myWork\myVenv\Lib\site-packages\matplotlib\lines.py:665, in Line2D.set_data(self, *args) 662 else: 663 x, y = args --> 665 self.set_xdata(x) 666 self.set_ydata(y) File C:\myWork\myVenv\Lib\site-packages\matplotlib\lines.py:1289, in Line2D.set_xdata(self, x) 1276 """ 1277 Set the data array for x. 1278 (...) 1286 set_ydata 1287 """ 1288 if not np.iterable(x): -> 1289 raise RuntimeError('x must be a sequence') 1290 self._xorig = copy.copy(x) 1291 self._invalidx = True RuntimeError: x must be a sequence
Reply
#2
The initial error is from the matplotlib call on line 17 (your code)

Documentation for the matplotlib method is here

try some of the examples here which will probably enlighten you as to what's going wrong.
Reply
#3
(Aug-15-2024, 10:12 AM)Larz60+ Wrote: The initial error is from the matplotlib call on line 17 (your code)

Documentation for the matplotlib method is here

try some of the examples here which will probably enlighten you as to what's going wrong.

Thank you for your reply. I am not sure what the problem is as I check that the component in line 17 should be correct, but the system keeps saying that x must be a sequence. I tried the exact same code in Colab and it works perfectly, showing me the desired animation. Would it be the problem with my JupyterLab?
Reply
#4
The message is very clear.
Error:
---> 15 dot.set_data(x[i],y[i]) . . . RuntimeError: x must be a sequence
Ok, maybe not that clear unless you are used to decoding the trace information. The rule of thumb for that is "the error is always your fault". So you trace back through the steps until you find code that you wrote. Using that as a guideline, lets look at your error info in revers (starting at bottom and workinng up.
Error:
Cell In[3], line 15, in animate(i) 14 def animate(i): ---> 15 dot.set_data(x[i],y[i]) File C:\myWork\myVenv\Lib\site-packages\matplotlib\lines.py:665, in Line2D.set_data(self, *args) Your code does this to set up for plotting: [python][/python] 662 else: 663 x, y = args --> 665 self.set_xdata(x) 666 self.set_ydata(y) File C:\myWork\myVenv\Lib\site-packages\matplotlib\lines.py:1289, in Line2D.set_xdata(self, x) 1276 """ 1277 Set the data array for x. 1278 (...) 1286 set_ydata 1287 """ 1288 if not np.iterable(x): -> 1289 raise RuntimeError('x must be a sequence') 1290 self._xorig = copy.copy(x) 1291 self._invalidx = True RuntimeError: x must be a sequence
Line 1276 through 1291 are in the file "matplotlib\lines.py". Not code you wrote, so the problem is not there.

Line 992 through 666 are in the file "matplotlib\lines.py". Not code you wrote, so the problem is not there.

Lines 14 and 15 are in Cell In[3], line 15. That is code you wrote, so the mistake is probably here. In particular here:
Error:
---> 15 dot.set_data(x[i],y[i])
The error message says x must be a sequence. Sequence are things like lists and tuples, and x is clearly a list. HOWEVER, the error is reported all the way down in line 1289 in matplotlib\lines.py
Error:
1288 if not np.iterable(x): -> 1289 raise RuntimeError('x must be a sequence')
This is where matplotlib figures out that you passed two floats to dot.set_data() instead of two "sequences".

To better understand why this is a problem we look at the matplotlib documentation. The first thing I want to check is what kind of arguments are expected for dot.set_data(). To look that up I need to know what "dot" is. I could determine this by looking at each instruction leading to assigning a value to "dot", or I could just print out the value of dot. I modify the code slightly to do this.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

x = np.linspace(0, 2 * np.pi, 100)
y = x * np.sin(2 * x)
fig, ax = plt.subplots()
(dot,) = ax.plot(0, 0, "ro", markersize=12)
print(dot)
Output:
Line2D(_child0)
dot is a Line2D object. I look that up in the matplotlib documentation

https://matplotlib.org/stable/api/_as_ge...ine2D.html

In particular I'm interested in Line2D.set_data()
Quote:set_data(*args)
Set the x and y data.

Parameters:
*args
(2, N) array or two 1D arrays
This says I need to provide either a 2D array, or two 1D arrays. Your call set_data() and pass two floats (x[i] and y[i]).

To fix the problem you need to pass an array, or sequence, like thing. You have two choices. You can do this:
def animate(i):
    dot.set_data(x[:i], y[:i])
When run, the animation first draws 1 dot, then two and so on until a dot is drawn for each x, y pair. Fun, but probably not what you want.

This code draws 1 dot which moves from the first x, y pair to the second and so on until it reaches the lst.
def animate(i):
    dot.set_data((x[i],), (y[i],))
(x[i],) is a tuple, a type of sequence, so matplotlib is happy. I need the trailing comma or python would think the parenthesis were used for grouping, as in (3 + 4) * 5.
leea2024 and Larz60+ like this post
Reply
#5
(Aug-15-2024, 08:20 PM)deanhystad Wrote: The message is very clear.
Error:
---> 15 dot.set_data(x[i],y[i]) . . . RuntimeError: x must be a sequence
Ok, maybe not that clear unless you are used to decoding the trace information. The rule of thumb for that is "the error is always your fault". So you trace back through the steps until you find code that you wrote. Using that as a guideline, lets look at your error info in revers (starting at bottom and workinng up.
Error:
Cell In[3], line 15, in animate(i) 14 def animate(i): ---> 15 dot.set_data(x[i],y[i]) File C:\myWork\myVenv\Lib\site-packages\matplotlib\lines.py:665, in Line2D.set_data(self, *args) Your code does this to set up for plotting: [python][/python] 662 else: 663 x, y = args --> 665 self.set_xdata(x) 666 self.set_ydata(y) File C:\myWork\myVenv\Lib\site-packages\matplotlib\lines.py:1289, in Line2D.set_xdata(self, x) 1276 """ 1277 Set the data array for x. 1278 (...) 1286 set_ydata 1287 """ 1288 if not np.iterable(x): -> 1289 raise RuntimeError('x must be a sequence') 1290 self._xorig = copy.copy(x) 1291 self._invalidx = True RuntimeError: x must be a sequence
Line 1276 through 1291 are in the file "matplotlib\lines.py". Not code you wrote, so the problem is not there.

Line 992 through 666 are in the file "matplotlib\lines.py". Not code you wrote, so the problem is not there.

Lines 14 and 15 are in Cell In[3], line 15. That is code you wrote, so the mistake is probably here. In particular here:
Error:
---> 15 dot.set_data(x[i],y[i])
The error message says x must be a sequence. Sequence are things like lists and tuples, and x is clearly a list. HOWEVER, the error is reported all the way down in line 1289 in matplotlib\lines.py
Error:
1288 if not np.iterable(x): -> 1289 raise RuntimeError('x must be a sequence')
This is where matplotlib figures out that you passed two floats to dot.set_data() instead of two "sequences".

To better understand why this is a problem we look at the matplotlib documentation. The first thing I want to check is what kind of arguments are expected for dot.set_data(). To look that up I need to know what "dot" is. I could determine this by looking at each instruction leading to assigning a value to "dot", or I could just print out the value of dot. I modify the code slightly to do this.
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

x = np.linspace(0, 2 * np.pi, 100)
y = x * np.sin(2 * x)
fig, ax = plt.subplots()
(dot,) = ax.plot(0, 0, "ro", markersize=12)
print(dot)
Output:
Line2D(_child0)
dot is a Line2D object. I look that up in the matplotlib documentation

https://matplotlib.org/stable/api/_as_ge...ine2D.html

In particular I'm interested in Line2D.set_data()
Quote:set_data(*args)
Set the x and y data.

Parameters:
*args
(2, N) array or two 1D arrays
This says I need to provide either a 2D array, or two 1D arrays. Your call set_data() and pass two floats (x[i] and y[i]).

To fix the problem you need to pass an array, or sequence, like thing. You have two choices. You can do this:
def animate(i):
    dot.set_data(x[:i], y[:i])
When run, the animation first draws 1 dot, then two and so on until a dot is drawn for each x, y pair. Fun, but probably not what you want.

This code draws 1 dot which moves from the first x, y pair to the second and so on until it reaches the lst.
def animate(i):
    dot.set_data((x[i],), (y[i],))
(x[i],) is a tuple, a type of sequence, so matplotlib is happy. I need the trailing comma or python would think the parenthesis were used for grouping, as in (3 + 4) * 5.

A big thank you for such a detailed explanation! Your way to look into my error is certainly helpful, especially for me who just started to learn programming.
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  unable to generate authentication key lokamaba 0 2,022 May-14-2020, 12:33 PM
Last Post: lokamaba
  Generate matplot animation on a link ambush 0 2,621 Apr-01-2019, 10:23 AM
Last Post: ambush

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020