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.
Hi @kiko249 could you share with us about the things you’ve already tried?
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.
Hi @labhayl , the Carousel custom component does not currently support local images but I’m working on fixing this. It should be solved by the end of the week.
Great Solution. Thanks for this.
Could you please help with following issues:
I replaced the image path with “Images/myImage.png”. But the image is not displayed. The Images folder is there. And the file also exists.
Dots are not displayed if used st.set_page_config(layout=“wide”)
Got it fixed here.
Thanks.
Thanks for working on this. After pip install streamlit-carousel
, which installed v1.1.0, I have this error. Any idea how to resolve it?
ImportError: cannot import name 'NotRequired' from 'typing'
Edit: Downgraded to v1.0.0 works.
Thanks
Hi @lavint , that should be fixed in version 1.1.2
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.