This may be more complicated of a solution than you’re looking for, but here is one way to accomplish this without a lot of repeated code, but creating a custom class that knows how to go down that “tree” that you’ve down if you choose yes or no. The essence of it is "display a button, if the Yes button is pressed, then keep track of that with st.session_state. This is necessary because a button doesn’t keep its state between app runs (unlike something like a text box or a checkbox).
from dataclasses import dataclass
from typing import Optional
import streamlit as st
@dataclass
class Choice:
"""
A choice for a question. A choice must have a label, and if you want to
show a different choice if yes or no is picked, you can specify that.
"""
label: str
if_true: Optional["Choice"] = None
if_false: Optional["Choice"] = None
# Create set of choices by starting at the bottom and working up
service = Choice("Call a service")
noise = Choice("Noise?", service)
oil = Choice("Oil?", noise)
vibrations = Choice("Vibrations?", oil)
warranty = Choice("Warranty?", vibrations)
broken = Choice("Pump Broken?", warranty)
# Create placeholders for the text, and the yes/no buttons
placeholder = st.empty()
col1, col2 = st.columns(2)
yes = col1.empty()
no = col2.empty()
def display_choice(choice: Optional[Choice] = None):
"""
Display a single choice, including yes and no buttons if applicable, and go to the next choice if
Yes or no is pressed
"""
yes.empty()
no.empty()
# IF there is no choice, we're done
if choice is None:
placeholder.write("No more choices")
yes.button("Start over?")
st.session_state.clear()
return
if choice.label not in st.session_state:
st.session_state[choice.label] = False
placeholder.write(choice.label)
if choice.if_true or choice.if_false:
if (
yes.button("Yes", key=choice.label + "Yes")
or st.session_state[choice.label]
):
st.session_state[choice.label] = True
display_choice(choice.if_true)
elif no.button("No", key=choice.label + "No"):
st.session_state[choice.label] = False
display_choice(choice.if_false)
# Call display_choice for the starting choice
display_choice(broken)
You are the best. Thank you so much. I like the solution without a lot of repeated code.
I tried to implement the code above to my real case and I would prefer a solution with the repeated code, because it would be optimal to add an unique image to the each question and there are several “No” answers, that are meaningfull (the image above was too simplified). Moreover I would like to style the text and the images. Could you provide a “nested” code (repeated), in order to have (at least for me) a freedom to customize the answers and to have a possibility to style the app.
All i need is an example of 4-5 nested buttons with: