Summary
I have an app running in my company that shows a kpi number in a screen.
I want to know if it is possible to make something like a carousel in bootstrap that every 5 seconds makes a transition and shows another kpi.
I have an app running in my company that shows a kpi number in a screen.
I want to know if it is possible to make something like a carousel in bootstrap that every 5 seconds makes a transition and shows another kpi.
tried using slider with time module
โ got problems with reset to the beggining
โ got problems with duplicate widget api error
tried extra components switch pages
โ dont have the effect expected as it kinda flashes when switching page
tried other custom build components but none of them worked as expected.
I want to have something more powepoint-like transitions
Any suggestions??
Best solution i found so far is the elements module but so far i wasnโt able to implement an automatic change of elements:
import streamlit as st
from streamlit_elements import elements, mui, html, sync
IMAGES = [
"https://unsplash.com/photos/GJ8ZQV7eGmU/download?force=true&w=1920",
"https://unsplash.com/photos/eHlVZcSrjfg/download?force=true&w=1920",
"https://unsplash.com/photos/zVhYcSjd7-Q/download?force=true&w=1920",
"https://unsplash.com/photos/S5uIITJDq8Y/download?ixid=MnwxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNjUyOTAzMzAz&force=true&w=1920",
"https://unsplash.com/photos/E4bmf8BtIBE/download?ixid=MnwxMjA3fDB8MXxhbGx8fHx8fHx8fHwxNjUyOTEzMzAw&force=true&w=1920",
]
def slideshow_swipeable(images):
# Generate a session state key based on images.
key = f"slideshow_swipeable_{str(images).encode().hex()}"
# Initialize the default slideshow index.
if key not in st.session_state:
st.session_state[key] = 0
# Get the current slideshow index.
index = st.session_state[key]
# Create a new elements frame.
with elements(f"frame_{key}"):
# Use mui.Stack to vertically display the slideshow and the pagination centered.
# https://mui.com/material-ui/react-stack/#usage
with mui.Stack(spacing=2, alignItems="center"):
# Create a swipeable view that updates st.session_state[key] thanks to sync().
# It also sets the index so that changing the pagination (see below) will also
# update the swipeable view.
# https://mui.com/material-ui/react-tabs/#full-width
# https://react-swipeable-views.com/demos/demos/
with mui.SwipeableViews(index=index, resistance=True, onChangeIndex=sync(key)):
for image in images:
html.img(src=image, css={"width": "100%"})
# Create a handler for mui.Pagination.
# https://mui.com/material-ui/react-pagination/#controlled-pagination
def handle_change(event, value):
# Pagination starts at 1, but our index starts at 0, explaining the '-1'.
st.session_state[key] = value-1
# Display the pagination.
# As the index value can also be updated by the swipeable view, we explicitely
# set the page value to index+1 (page value starts at 1).
# https://mui.com/material-ui/react-pagination/#controlled-pagination
mui.Pagination(page=index+1, count=len(images), color="primary", onChange=handle_change)
if __name__ == '__main__':
st.title("Streamlit Elements Slideshow")
st.subheader("Swipeable slideshow")
slideshow_swipeable(IMAGES)
If you want to have a simple slide show you can always use streamlit.components.v1
and pass your own html code. For example:
import streamlit as st
import streamlit.components.v1 as components
components.html(
"""
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* {box-sizing: border-box;}
body {font-family: Verdana, sans-serif;}
.mySlides {display: none;}
img {vertical-align: middle;}
/* Slideshow container */
.slideshow-container {
max-width: 1000px;
position: relative;
margin: auto;
}
/* Caption text */
.text {
color: #f2f2f2;
font-size: 15px;
padding: 8px 12px;
position: absolute;
bottom: 8px;
width: 100%;
text-align: center;
}
/* Number text (1/3 etc) */
.numbertext {
color: #f2f2f2;
font-size: 12px;
padding: 8px 12px;
position: absolute;
top: 0;
}
/* The dots/bullets/indicators */
.dot {
height: 15px;
width: 15px;
margin: 0 2px;
background-color: #bbb;
border-radius: 50%;
display: inline-block;
transition: background-color 0.6s ease;
}
.active {
background-color: #717171;
}
/* Fading animation */
.fade {
animation-name: fade;
animation-duration: 1.5s;
}
@keyframes fade {
from {opacity: .4}
to {opacity: 1}
}
/* On smaller screens, decrease text size */
@media only screen and (max-width: 300px) {
.text {font-size: 11px}
}
</style>
</head>
<body>
<h2>Automatic Slideshow</h2>
<p>Change image every 2 seconds:</p>
<div class="slideshow-container">
<div class="mySlides fade">
<div class="numbertext">1 / 3</div>
<img src="https://unsplash.com/photos/GJ8ZQV7eGmU/download?force=true&w=1920" style="width:100%">
<div class="text">Caption Text</div>
</div>
<div class="mySlides fade">
<div class="numbertext">2 / 3</div>
<img src="https://unsplash.com/photos/eHlVZcSrjfg/download?force=true&w=1920" style="width:100%">
<div class="text">Caption Two</div>
</div>
<div class="mySlides fade">
<div class="numbertext">3 / 3</div>
<img src="https://unsplash.com/photos/zVhYcSjd7-Q/download?force=true&w=1920" style="width:100%">
<div class="text">Caption Three</div>
</div>
</div>
<br>
<div style="text-align:center">
<span class="dot"></span>
<span class="dot"></span>
<span class="dot"></span>
</div>
<script>
let slideIndex = 0;
showSlides();
function showSlides() {
let i;
let slides = document.getElementsByClassName("mySlides");
let dots = document.getElementsByClassName("dot");
for (i = 0; i < slides.length; i++) {
slides[i].style.display = "none";
}
slideIndex++;
if (slideIndex > slides.length) {slideIndex = 1}
for (i = 0; i < dots.length; i++) {
dots[i].className = dots[i].className.replace(" active", "");
}
slides[slideIndex-1].style.display = "block";
dots[slideIndex-1].className += " active";
setTimeout(showSlides, 2000); // Change image every 2 seconds
}
</script>
</body>
</html>
""",
height=600,
)
that works for me thank you!
Hi @kiko249 I have implemented a component which should do exactly that. You can check it out here, hope this helps.
Hello Tomas
I tried your component but iโm getting executing the code posted on pypi
TypeError: unsupported operand type(s) for |: โtypeโ and โNoneTypeโ
Iโm running streamlit 1.23 and python 3.9
Hi Kiko,
Do you have a code snippet that I can try to reproduce your error?
I think this had to do with a Python version compatibility issue. I have made a patch (i.e. version 0.0.4) which should solve the issue.
Could you please confirm?
Hello
Yes now it is working, good job
and thank you very much
Hey @kiko249 and @ThomasBouamoud,
Just wondering if mui.pagination works for images stored locally as well?
I mean to slideshow locally stored images in same format.
These cookies are necessary for the website to function and cannot be switched off. They are usually only set in response to actions made by you which amount to a request for services, such as setting your privacy preferences, logging in or filling in forms.
These cookies allow us to count visits and traffic sources so we can measure and improve the performance of our site. They help us understand how visitors move around the site and which pages are most frequently visited.
These cookies are used to record your choices and settings, maintain your preferences over time and recognize you when you return to our website. These cookies help us to personalize our content for you and remember your preferences.
These cookies may be deployed to our site by our advertising partners to build a profile of your interest and provide you with content that is relevant to you, including showing you relevant ads on other websites.