How to plot race bar chart in streamlit

Dear Community,
I’m trying to develop an streamlit webapp whch can create a racing bar chart using library ‘bar_chart_race’. Ihave successfully created and tested the base code in jupyter notebook. I put the code below:

import pandas as pd
import streamlit as st
import matplotlib.pyplot as plt
import bar_chart_race as bcr
import ffmpeg

sg=pd.read_csv('solar-energy-consumption.csv')
sg['Electricity from solar (TWh)']=1000*sg['Electricity from solar (TWh)']
sg.rename(columns={'Entity':'Country','Electricity from solar (TWh)':'Solar Energy Yield (GWh)'}, inplace=True)
sg = sg[["Country", "Year", "Solar Energy Yield (GWh)"]]
sg = sg.pivot(index = "Year", columns = "Country", values = "Solar Energy Yield (GWh)").reset_index().rename_axis(None, axis=1)
sg=sg.fillna(0)
del sg['Asia Pacific']
del sg['EU27+1']
del sg['EU-27']
del sg['Europe']
del sg['World']
del sg['North America']
sg.set_index("Year", inplace = True)
bcr.bar_chart_race(df = sg, title = "Top 10 Solar Energy Producing Countries from 1985-2020",n_bars=4)

But I am not able to figure out which function to use for plotting the video into a streamlit web app. Please help!!bcr_solar energy

Hi @amrit :wave:

If the returned object is an HTML string, you can use the static HTML component to render it:

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

components.html(
    bcr.bar_chart_race(
        df=sg, title="Top 10 Solar Energy Producing Countries from 1985-2020", n_bars=4
    )
)

Happy Streamlit’ing! :balloon:
Snehan

2 Likes

Dear @snehankekre ,
actually its a video that the code return as a file. Its in .m4v and the video file can be downloaded in .mp4 format. I have also tries with st.video but still no luck.

2021-08-30 21:58:22.987 INFO    matplotlib.animation: MovieWriter._run: running command: ffmpeg -f rawvideo -vcodec rawvideo -s 1084x504 -pix_fmt rgba -r 20.0 -loglevel error -i pipe: -vcodec h264 -pix_fmt yuv420p -y 'C:\Users\Amrit\AppData\Local\Temp\tmpk21bnrx8\temp.m4v'

The error message after using st.video()


  File "C:\Users\Amrit\Desktop\hydralit\bcr_solar_yield_v01.py", line 29, in <module>
    st.video(

  File "C:\Users\Amrit\anaconda3\lib\site-packages\streamlit\elements\media.py", line 100, in video
    marshall_video(coordinates, video_proto, data, format, start_time)

  File "C:\Users\Amrit\anaconda3\lib\site-packages\streamlit\elements\media.py", line 218, in marshall_video
    _marshall_av_media(coordinates, proto, data, mimetype)

  File "C:\Users\Amrit\anaconda3\lib\site-packages\streamlit\elements\media.py", line 178, in _marshall_av_media
    raise RuntimeError("Invalid binary data format: %s" % type(data))

RuntimeError: Invalid binary data format: <class 'IPython.core.display.HTML'>

The error while using components.html() is:

Traceback (most recent call last):

  File "C:\Users\Amrit\Desktop\hydralit\bcr_solar_yield_v01.py", line 29, in <module>
    components.html(

  File "C:\Users\Amrit\anaconda3\lib\site-packages\streamlit\elements\iframe.py", line 80, in _html
    marshall(

  File "C:\Users\Amrit\anaconda3\lib\site-packages\streamlit\elements\iframe.py", line 131, in marshall
    proto.srcdoc = srcdoc

TypeError: <IPython.core.display.HTML object> has type HTML, but expected one of: bytes, unicode


Hi @amrit,

Alright, from your error message, it looks like the returned object is of type HTML. The HTML string containing the video can be obtained by calling .data on the returned object. Try the following and make sure to adjust the height value to view the entire video:

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

components.html(
    bcr.bar_chart_race(
        df=sg, title="Top 10 Solar Energy Producing Countries from 1985-2020", n_bars=4
    ).data
)

OR

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

html_str = bcr.bar_chart_race(df=sg, title="Top 10 Solar Energy Producing Countries from 1985-2020", n_bars=4)
components.html(
    html_str.data
)

Best, :balloon:
Snehan

1 Like

Dear @snehankekre ,

thanks for the solution. Both the codes worked.

But, still there’s a problem of video dimension. It covers more than than standard web page size. i gave it width, height of all possible dimensions, but whenever the dimensions goes below 720p (1280x720), the video got cropped. I tried with st.components “st_player” but its solving the issue. Any thoughts on this? I mean how to make the video inside an embeded frame like what “st_player” is doing with YT videos?

Thanks & Regards,
Amrit

Hi @amrit,

This is a hacky workaround, but it works on my end:

import streamlit as st
import streamlit.components.v1 as components
import bar_chart_race as bcr
import base64

df = bcr.load_dataset("covid19_tutorial")
html_str = bcr.bar_chart_race(df=df).data

start = html_str.find('base64,')+len('base64,')
end = html_str.find('">')

video = base64.b64decode(html_str[start:end])
st.video(video)

bcr

Best, :balloon:
Snehan

Dear @snehankekre ,

Thanks a lot. It worked!! And I’m very sorry for my late response.

Thanks again,
Amrit Mandal