Matplotlib Animation.FuncAnimation Support

Is there a way to display a matplotlib animation using the animation.FuncAnimation tool already developed in matplotlib.

For example, if I generate the animation:

ani = animation.FuncAnimation(fig, animate, interval=5000)

how to I show the output? Because streamlit.pyplot() does not show the real-time animation.

Please, any advice would be appreciated, I have tried every post related to animations and it does not work.

Hello @Zane_Venter,

I’ve discovered this little trick totally randomly, you can build HTML/JS out of a FuncAnimation and render it in Streamlit. Find it below :wink:

Hope it helps!
Fanilo

3 Likes

Hi,

I have tested the example (I think I did see it in a blog post), Streamlit loads the graph, but nothing gets displayed.

And then the following error gets displayed, due to the exit function (Its supposed to happen):

My Code example:

import mplfinance as mpf

import matplotlib.animation as animation

…A bunch of functions that get a pandas dataframe…

df = data

pkwargs=dict(type=‘candle’, tz_localize=False)

plt.style.use(‘fivethirtyeight’)

fig, axes = mpf.plot(data.iloc[0:20],returnfig=True,volume=False,
figsize=(11,8),
title=‘\n\nLive Data’,
**pkwargs)

ax_main = axes[0]

ax_emav = ax_main

def animate(ival):
if (20+ival) > len(df):
print(‘no more data to plot’)
ani.event_source.interval *= 3
if ani.event_source.interval > 600000:
exit()
return
data = df.iloc[ival:(20 + ival)]
data_c = data.copy()
df_reg = reg_calc(data_c, ival)
ValB, ValS = function_to_calculate_extra_stuff(df_reg)
df_reg[‘ValA’] = Buy
df_reg[‘ValB’] = Sell
df_reg_c = df_reg

reg_plot = [
    mpf.make_addplot(df_reg_c['Hreg'], ax=ax_emav, type='line', color='g'),
    mpf.make_addplot(df_reg_c['Lreg'], ax=ax_emav, type='line', color='r'),
    mpf.make_addplot(df_reg_c['ValA'], ax=ax_emav, type='scatter',markersize=200,marker='^', color='b'),
    mpf.make_addplot(df_reg_c['ValB'], ax=ax_emav, type='scatter',markersize=200,marker='v',color='black'),
        ]
ax_main.clear()
ax_emav.clear()
mc = mpf.make_marketcolors(up='g', down='r')
s = mpf.make_mpf_style(marketcolors=mc)

mpf.plot(data, ax=ax_main, addplot=reg_plot, style=s, **pkwargs)

ani = animation.FuncAnimation(fig, animate, interval=1000)

st.markdown(“https://matplotlib.org/gallery/animation/basic_example.html”)
components.html(ani.to_jshtml(), height=1000)

I hope that it makes sense. I really have been trying to get this to work on Streamlit.

Also, Its using live data, its not a fixed dataframe upload. Therefore the figure is plotted dynamically, this whole dynamic plot is getting to me…

Ah, unfortunately Matplotlib relies on generating static images at every Streamlit script rerun, so the FuncAnimation will also somewhere on the line be transformed to static animations, that doesn’t make it very friendly for live data. I usually go for Plotly, Altair or ECharts for dynamic plotting of data in the browser.
Then I would save the latest n points of live data in Streamlit cache and plot it on every tick.

GitHub - ash2shukla/streamlit-stream-stonks: An extended example of streaming application in streamlit of a Stocks Monitoring Dashboard. is my GOTO template for realtime plotting of windowed data in Streamlit and mostly uses this cycle. It uses asyncio (here a smaller example to reproduce locally) to pull data every n seconds, put it in a window cache and plot the results afterwards.

It’s a lot of information at once, but hope it does get you started on this solution!

1 Like

Hi @Zane_Venter, I agree with @fanilo, but in case you want to follow in this direction, I’ve managed to show the animation, hope it is good for you:
(Edit: I had some lines missing, here is the corrected code :point_down: :sweat_smile:)

import streamlit as st
import streamlit.components.v1 as components

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

def func(t, line):
    t = np.arange(0,t,0.1)
    y = np.sin(t)
    line.set_data(t, y)
    return line
 
fig = plt.figure()
ax = plt.axes(xlim=(0, 100), ylim=(-1.2, 1.22))
redDots = plt.plot([], [], 'ro')
line = plt.plot([], [], lw=2)
 

# Creating the Animation object
line_ani = animation.FuncAnimation(fig, func, frames=np.arange(1,100,0.1), fargs=(line), interval=100, blit=False)
#line_ani.save(r'Animation.mp4')
 
 

#HtmlFile = line_ani.to_html5_video()
with open("myvideo.html","w") as f:
  print(line_ani.to_html5_video(), file=f)
  
HtmlFile = open("myvideo.html", "r")
#HtmlFile="myvideo.html"
source_code = HtmlFile.read() 
components.html(source_code, height = 900,width=900)
2 Likes

Hi @andfanilo and @napoles3d ,

Thank you so much. This definitely helped me to get an better Idea of the solution, its still not 100% there but progress is progress and the guidance really helped me!

I have combined both recommendations, and its working with streamlit.

Thank you very much.

PS, I am getting this error, where I dont have permission to “add” the html file. When deploying the app.

mhhh, this is strange. I need to try to see what’s happening. Are you deploying in Streamlit Share?? Could you provide the link to the repo?

Hello All,

Thanks first for everything in this thread, as I have gotten quite far with visualizing matplotlib animations in streamlit.

I’m trying to use streamlit to make a sort algorithm visualizer, where I am just using the rather simple bubble sort algo to test.

The problem I’m having is that the code posted works and works in streamlit but only interates once through the sort function, thus sorting only one number in the array. I’m new to matplotlib and streamlit, so I can’t tell if there is a way to create my own animation, or get FuncAnimation to behave differently (I read the docs and seems pretty straightforward as a function repeater).

Any pointers are appreciated. Thanks.

import streamlit as st
import streamlit.components.v1 as components
import time
import numpy as np
import scipy as sp
import random
import matplotlib.pyplot as plt
import matplotlib.animation as anim

# Sorting Algorithms.


def bubble_sort(arr):
    for i in range(len(arr) - 1, 0, -1):
        for j in range(i):
            if arr[j] > arr[j + 1]:
                arr[j], arr[j + 1] = arr[j + 1], arr[j]
            yield arr


n = 100 # int(input("Enter the number of elements: "))
array = [i + 1 for i in range(n)]
algo = bubble_sort(array) # int(input(f"Choose algorithm: \n 1.Bubble: "))
random.shuffle(array)
title = "Bubble Sort"

# if alg == 1:
#     title = "Bubble Sort"
#     algo = bubble_sort(array)

# Initialize fig
fig, ax = plt.subplots()
ax.set_title(title)

bar_rec = ax.bar(range(len(array)), array, align='edge')

ax.set_xlim(0, n)
ax.set_ylim(0, int(n * 1.06))

text = ax.text(0.02, 0.95, "0", transform=ax.transAxes)

epochs = [0]


def update_plot(array, rec, epochs):
    for rec, val in zip(rec, array):
        rec.set_height(val)
    epochs[0] += 1
    text.set_text("No.of operations :{}".format(epochs[0]))


anima = anim.FuncAnimation(fig, update_plot, fargs=(bar_rec, epochs), frames=algo, interval=1, repeat=False)
# plt.show()
# st.pyplot(plt)

components.html(anima.to_jshtml(), height=1000)

I figured it out. It’s a matplotlib.funcanimation parameter ‘save_count’ which sets the number of saved frames and nothing to do with streamlit. Streamlit rocks to be able to do this so easily, despite my newbie difficulties.

Thanks guys!

2 Likes

Hey @marxmarxmarx could You post here your final code, un orden that this helps others?, that would be awesome.

Regards!