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!