3

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
#plt.rcParams["animation.html"] = "jshtml"
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(12, 8))
def update(frame):
 date = dates[frame]
 day_data = daily_groups[date]
 ax.scatter(
 day_data["Longitude"],
 day_data["Latitude"],
 s=day_data["TargetValue"],
 alpha=0.6,
 color="crimson",
 edgecolors="black"
 )
 
 ax.set_title(f"Confirmed Cases on {date}")
 ax.set_xlim([-300, -65])
 ax.set_ylim([24, 50])
 ax.set_xlabel("Longitude")
 ax.set_ylabel("Latitude")
 ax.grid(True)
 return ax,
anim = FuncAnimation(fig, update, frames=len(dates), interval=200)
plt.tight_layout()
plt.show()

This plot doesn't show, but I can save it

anim.save("us_cases_animation.mp4", writer="ffmpeg", fps=5)

Video runs, this happens both on VS code and Jupyter notebook. I only get a blank fig with axis. I used to get IPython undefined, I don't get that anymore though.

when I use this:

%matplotlib ipympl 

I get this error "Error displaying widget"

3
  • plt.show(block=True) should work Commented Oct 16 at 4:58
  • @ChandanSaroj When I use %matplotlib ipympl I get this error "Error displaying widget" Commented Oct 16 at 5:43
  • This wasn't close to being a minimal reproducible example as many thing were undefined. Thankfully, Chandan Saroj did the heavy lifting. However, please read How do I ask a good question?, especially the section 'Help others reproduce the problem', and follow it in the future. Commented Oct 16 at 16:22

2 Answers 2

3

FuncAnimation creates the animation object, but does not automatically render in the notebook. you just did plt.show() that works for scripts, but in Jupyter it only shows a static blank figure with axes.

To display animation it requires Explicit inline display:

from IPython.display import HTML
HTML(anim.to_jshtml())

Tried with sample code

# Required for Jupyter notebook
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML
 
dates = ["Sun", "Mon", "Tue", "Wed", "Thu"]
num_points = 20
 
latitudes = np.random.uniform(24, 50, (len(dates), num_points))
longitudes = np.random.uniform(-125, -65, (len(dates), num_points))
sizes = np.random.uniform(50, 300, (len(dates), num_points)) 
# figure and axis
fig, ax = plt.subplots(figsize=(10, 6))
ax.set_xlim([-130, -60])
ax.set_ylim([20, 55])
ax.set_xlabel("Longitude")
ax.set_ylabel("Latitude")
ax.grid(True)
# Initialize scatter 
scat = ax.scatter([], [], s=[], color='crimson', alpha=0.6, edgecolors='black')
# animation func
def update(frame):
 global scat
 # Required
 scat.remove()
 
 scat = ax.scatter(
 longitudes[frame],
 latitudes[frame],
 s=sizes[frame],
 color='crimson',
 alpha=0.6,
 edgecolors='black'
 )
 
 ax.set_title(f"Confirmed Cases: {dates[frame]}")
 return scat,
#Create animation 
anim = FuncAnimation(fig, update, frames=len(dates), interval=500, blit=True)
#Display animation
HTML(anim.to_jshtml())

and if it is blank canvas problem, remove previous points using scat.remove() before plotting new points.

answered Oct 16 at 5:41
Sign up to request clarification or add additional context in comments.

1 Comment

This worked, thank you!
0

This works fine with typical Jupyter with the ipykernel to use ipympl to display the animation without needing to save a file or make HTML:

%matplotlib ipympl
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
#plt.rcParams["animation.html"] = "jshtml"
dates = ["Sun", "Mon", "Tue", "Wed", "Thu"]
num_points = 20
latitudes = np.random.uniform(24, 50, (len(dates), num_points))
longitudes = np.random.uniform(-125, -65, (len(dates), num_points))
sizes = np.random.uniform(50, 300, (len(dates), num_points)) 
fig, ax = plt.subplots(figsize=(12, 8))
#day_data = daily_groups[date]
scat = ax.scatter(
 longitudes[0],
 latitudes[0],
 s=sizes[0],
 alpha=0.6,
 color="crimson",
 edgecolors="black"
 )
 
ax.set_title(f"Confirmed Cases on {dates[0]}")
ax.set_xlim([-300, -65])
ax.set_ylim([24, 50])
ax.set_xlabel("Longitude")
ax.set_ylabel("Latitude")
ax.grid(True)
def update(frame):
 x = longitudes[frame]
 y = latitudes[frame]
 s=sizes[frame]
 data = np.stack([x, y]).T
 scat.set_offsets(data)
 ax.set_title(f"Confirmed Cases: {dates[frame]}")
 return scat
anim = FuncAnimation(fig, update, frames=len(dates), interval=200)

See it in action without touching your own system...

To see it work without environment concenrs, go here, click on one if the 'launch binder' badges. When the temporary remote session comes up, open a new notebook and paste in the above code.

There are simpler versions of the framework for that under 'Use of Matplotlib's animation.FuncAnimation()' in the fifth and sixth code cells in that notebook of examples that starts up when the sessions starts. It is always best to start with a working example and adapt it to plot what you want.



For JupyterLite with the pyodide kernel, it seems at this time to use FuncAnimation() you need to generate the frames ahead of time/make HTML (,and so this case ends up being closer to what Chandan Saroj says).
Put this in the cell and run it:

%matplotlib ipympl
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
#plt.rcParams["animation.html"] = "jshtml"
dates = ["Sun", "Mon", "Tue", "Wed", "Thu"]
num_points = 20
latitudes = np.random.uniform(24, 50, (len(dates), num_points))
longitudes = np.random.uniform(-125, -65, (len(dates), num_points))
sizes = np.random.uniform(50, 300, (len(dates), num_points)) 
fig, ax = plt.subplots(figsize=(12, 8))
#day_data = daily_groups[date]
scat = ax.scatter(
 longitudes[0],
 latitudes[0],
 s=sizes[0],
 alpha=0.6,
 color="crimson",
 edgecolors="black"
 )
 
ax.set_title(f"Confirmed Cases on {dates[0]}")
ax.set_xlim([-300, -65])
ax.set_ylim([24, 50])
ax.set_xlabel("Longitude")
ax.set_ylabel("Latitude")
ax.grid(True)
def update(frame):
 x = longitudes[frame]
 y = latitudes[frame]
 s=sizes[frame]
 data = np.stack([x, y]).T
 scat.set_offsets(data)
 ax.set_title(f"Confirmed Cases: {dates[frame]}")
 return scat
anim = FuncAnimation(fig, update, frames=len(dates), interval=200)
plt.close(fig) # Prevent static plot display
from IPython.display import HTML
HTML(anim.to_jshtml())

Use the controller with the play button below the plot to run the animation frames.

How you can try this in JupyterLite:

Go to here and click on 'try lite now' badge.

Alternatively, go to Try Jupyter Page and click on either of the top two tiles here for the 'JupyterLab' or 'Jupyter Notebook' tile.

When the interface opens, make a new notebook and then follow the steps above.



Alternative implementations compatible with either typical ipykernel or JupyterLite pyodide kernel

If you don't stipulate needing FuncAnimation(), these are compatible with either kernel-type so don't require as much adapting for use in different locations at this time:

First, based on the examples at the top of here using clear_output() with a pause that don't use player widget and calculate frames in advance of displaying the animation (so it is more of a live display of the current state):

from IPython.display import clear_output
from matplotlib import pyplot as plt
import numpy as np
import time
dates = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri","Sat"]
num_points = 20
latitudes = np.random.uniform(24, 50, (len(dates), num_points))
longitudes = np.random.uniform(-125, -65, (len(dates), num_points))
sizes = np.random.uniform(50, 300, (len(dates), num_points)) 
def live_plot(frame,date):
 clear_output(wait=True)
 #day_data = daily_groups[date]
 plt.figure(figsize=(12, 8))
 plt.scatter(
 longitudes[frame],
 latitudes[frame],
 s=sizes[frame],
 alpha=0.6,
 color="crimson",
 edgecolors="black"
 )
 plt.title(f"Confirmed Cases on {date}")
 plt.xlim([-300, -65]) 
 plt.ylim([24, 50]) 
 plt.xlabel("Longitude")
 plt.ylabel("Latitude")
 plt.grid(True)
 plt.show()
 time.sleep(0.75) # extend delay between adding next frame in animation
for indx,date in enumerate(dates):
 live_plot(indx,date)

Second, based on the example for ipywidget's interact() near the top of here:

# based on https://stackoverflow.com/q/76212356/8508004
import ipywidgets as widgets
import numpy as np
import matplotlib.pyplot as plt
dates = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri","Sat"]
num_points = 20
latitudes = np.random.uniform(24, 50, (len(dates), num_points))
longitudes = np.random.uniform(-125, -65, (len(dates), num_points))
sizes = np.random.uniform(50, 300, (len(dates), num_points)) 
def plt_func(t):
 plt.figure(figsize=(10, 10))
 plt.scatter(
 longitudes[t],
 latitudes[t],
 s=sizes[t],
 alpha=0.6,
 color="crimson",
 edgecolors="black"
 )
 date = dates[t]
 plt.title(f"Confirmed Cases on {date}")
 plt.xlim([-300, -65]) 
 plt.ylim([24, 50]) 
 plt.xlabel("Longitude")
 plt.ylabel("Latitude")
 plt.grid(True)
 plt.show()
 
widgets.interact(plt_func, t = widgets.Play(min=0, max = len(dates)-1, interval = 450), continuous_update = True);

Like the main offered JupyterLite-compatible version there, the interact()-based version involves a controller widget. This particular one uses a 'play' widget in the upper left corner that you have to activate to start things by pressing the 'play' button.
This controller widget is more limited though than the one from anim.to_jshtml(), with only play and stop and a toggle for looping.

answered Oct 16 at 16:23

3 Comments

Hi, Wayne, thanks for the answer but this would not render on my local notebook either. There seems to be some sort of issue with the ipympl magic command itself: "Error displaying widget"
Then you have something that is not installed properly or using old Jupyter? I have linked to a place you can see it working with new stuff. That content in the example notebook has been working for a year and several months. There the session you'll get from 'launch binder' takes it from the situation 'it works on my computer'. Or in this case, doesn't work. ipympl & ipywidgets can be difficult. Did you do a hard refresh of your notebook browser page after restarting the kernel and restarting everything, ev
Any chance you are using JupyterLite? I added example for that now. At this time, with JupyterLite it is more along the line of what Chandan Saroj proposes.

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.