I am working on to display Movie recommendations; I am able to display 10 movies when a user input from st.selectbox and click on “Show Recommendation” Button.
I am also able to get the button on caption of each movie but when i click on the button for one of the movies, it is not calling the function again.
It is going to the first page of “Show Recommendation” with st.selectbox showing the movie name for which i got the 10 movies.
When user click on the movie it shld display the next 10 movie related to that movie.
Steps to reproduce
if st.button('Show Recommendations'):
Buttons don’t have a persistent state. They will return True immediately after clicking them, but go back to False if the user interacts with anything else. So upon clicking a button within your movie_name function, your page will reload with st.button('Show Recommendations') being false and it will look like the first page load.
You can either use a checkbox so that there is some retained state, or you can use session state to keep a memory of your button clicks.
Here’s an example creating some memory for the outer button. You can do the same for more nested buttons as needed.
# Initialize some state for showing recommendations
if 'show_recommendation' not in st.session_state:
st.session_state.show_recommendation = False
# Callback function to make sure the state changes with each button click
st.session_state.show_recommendation = not st.session_state.show_recommendation
# Independent button, with attached callback function
st.button('Show Recommendations', on_click=change_show)
# Conditional called on the key stored in session state instead of directly on the button value
st.write('Movie recommendations showing here')
st.button('Another button here')
If you want any persistence with the effect of a button, make sure you are not passing the button directly into your conditional. The point of the callback function is to store information in session state that will survive past what the button remembers. You want to base your conditionals on that session state information.
So instead of:
Set the button outside of the conditional with the callback to record info in session state, then set your conditional on that session state value:
st.button(‘Show Recommendations’, on_click=set_stage, args=(1,))
if st.session_state.stage > 0:
But now…it is trying to display both from “first button and then second button” because of which it is throwing key error " DuplicateWidgetID : There are multiple identical st.button widgets with key='11' ."
Initially is should show first 10 movies…then if I click on one of the movies…the first 10 should clear up and then next 10 corresponding to the movie I clicked should show up.
Thanks for the help!!!
st.session_state.stage = stage
if “stage” not in st.session_state:
st.session_state.stage = 0
Ok, I see what you tried to do. Assuming you want the “Show Recommendations” button to present the 10 movies, then from there click any of the movies button shows some additional information for that movie:
You would probably be best served having two distinct keys in session state to separate the concepts of “where you are in the process” and “what option among many was selected.” I don’t know if you have any further buttons beyond the two steps shown, but you can create a different key to register the last button clicked among the recommendations. If you need to nest more layers of buttons, you can adjust callback functions to update the stage key also.
You can condense down where you are listing out the 10 recommendations with their buttons like this:
# New callback for the individual movie buttons
st.session_state.selected = i
# initialize a new key
if 'selected' not in st.session_state:
st.session_state.selected = None
# get your columns as a list so it's easier to increment through them
columns = st.columns(5)
# increment through your 10 items in the list, by index
for i in range(10):
# increment through your columns by index, using mod 5 to loop through 0 to 4, twice
# now the individual movie buttons affect the 'selected' key instead of the 'stage' key
st.button(recommended_movies[i], on_click=selected, args=(i,), key=recommended_movies[i])
if st.session_state.selected is not None:
i = st.session_state.selected
If you need each movie button to work like an on/off switch and potentially show more than one secondary result at once, that’s possible too but would have a different structure to save more than a single index number at a time.
You can append an extra digit or string to your widget keys representing the tier they are displayed in to keep the keys unique. For example, the first 10 would have recommended_movies[i]+'first' as the key and when you are showing them in the next tier, you would use recommended_movies[i]+'second'. But if you are going to nest these expansions of 10 movies at a time further, you will either need additional keys or you’ll need to make your “selection” a list so it can keep track of a series of selections.
You can create buttons with new callback functions to reset whichever keys you want for your process.