Getting multiple inputs from the loop

def calorie_counter():
    # Create widgets outside the loop
    food_type_widget = st.empty()
    frequency_per_week_widget = st.empty()
    times_per_day_widget = st.empty()
    quantity_widget = st.empty()
    

    food_dataset = load_food_data()
    drop_down_column = food_dataset["Food_Name"]
   
    ft = []
    fpw = []
    tpd = []
    quan = []
 
    carbohydrates_value = 0
    protein_value = 0
    fat_value = 0
    fiber_value = 0
    total_weekly_calories = 0

    food_items = []


    num_food_items = st.number_input("Enter the number of food items: ", step = 1)


    counter = 0
    while counter < num_food_items:
        food_type = food_type_widget.selectbox("Select the type of food:", drop_down_column, key=f"food_type_input_{len(ft)}")
        frequency_per_week = frequency_per_week_widget.number_input("Enter the frequency per week for food:", key=f"frequency_per_week_input_{len(fpw)}", step=1)
        times_per_day = times_per_day_widget.number_input("Enter how many times per day for food:", key=f"times_per_day_input_{len(tpd)}", step=1)
        quantity = quantity_widget.number_input("Enter the quantity in grams for food:", key=f"quantity_input_{len(quan)}", step=1)

        food_items.append({
            'food_type': food_type,
            'frequency_per_week': frequency_per_week,
            'times_per_day': times_per_day,
            'quantity': quantity
        }) 

        ft.append(food_type)
        fpw.append(frequency_per_week)
        tpd.append(times_per_day)
        quan.append(quantity)
        
        counter += 1

In the above code, I need to get the number of food items from the user and using that I need to run the loop and get different food type, frequency per week, times per day and quantity value. But the problem is I couldn’t get multiple values from the loop eventhough it is in a loop. The app is running locally in the streamlit version1.32.2

The key is to remember that a streamlit app just runs as a script from top to bottom. In your case, it doesn’t stop to wait for input, it just keeps adding widgets where you told it to, so if you tell it to loop 3 times, it will write over the food_type_widget three times, and only show the last one.

One way to solve this is to use st.session_state to keep track of what’s been entered, and add a submit button that updates the list of foods, and then reruns the app again for the next entry.

import streamlit as st

def load_food_data():
    food_dataset = {
        "Food_Name": ["Apple", "Banana", "Orange", "Mango", "Pineapple"],
        "Carbohydrates": [25, 27, 21, 30, 22],
        "Protein": [1, 1, 1, 1, 1],
        "Fat": [0, 0, 0, 0, 0],
        "Fiber": [4, 3, 3, 4, 2],
    }

    return food_dataset

if "num_entered" not in st.session_state:
    st.session_state.num_entered = 0

if "food_items" not in st.session_state:
    st.session_state.food_items = []

def calorie_counter():

    food_dataset = load_food_data()
    drop_down_column = food_dataset["Food_Name"]

    ft = []
    fpw = []
    tpd = []
    quan = []

    num_food_items = st.number_input("Enter the number of food items: ", step = 1)

    # Create widgets outside the loop
    food_type_widget = st.empty()
    frequency_per_week_widget = st.empty()
    times_per_day_widget = st.empty()
    quantity_widget = st.empty()


    counter = 0
    if st.session_state["num_entered"] < num_food_items:
        food_type = food_type_widget.selectbox("Select the type of food:", drop_down_column, key=f"food_type_input_{len(ft)}")
        frequency_per_week = frequency_per_week_widget.number_input("Enter the frequency per week for food:", key=f"frequency_per_week_input_{len(fpw)}", step=1)
        times_per_day = times_per_day_widget.number_input("Enter how many times per day for food:", key=f"times_per_day_input_{len(tpd)}", step=1)
        quantity = quantity_widget.number_input("Enter the quantity in grams for food:", key=f"quantity_input_{len(quan)}", step=1)

        if st.button("Submit"):

            st.session_state.food_items.append({
                'food_type': food_type,
                'frequency_per_week': frequency_per_week,
                'times_per_day': times_per_day,
                'quantity': quantity
            })

            ft.append(food_type)
            fpw.append(frequency_per_week)
            tpd.append(times_per_day)
            quan.append(quantity)

            st.session_state["num_entered"] += 1

            st.rerun()
    else:
        st.write("No more food to enter")

    st.write("Food items entered")
    st.write(st.session_state.food_items)

calorie_counter()

Thank you for your solution and it worked. But now i have to use the values of the food_items dictionary for further operations.

  1. I need to pass them on to two other functions. By taking the details of the food items, frequency, times per day and quantity, I calculate the total calories consumed by a person in a week and their nutritional composition. But I could not add up the total calories consumed per week value (Program given below for understanding*). Is it because of the st.session_state function usage.
  2. Similarly, what if I don’t know the number of food items to get in the first place in your given solution. How do we approach that too.
    Code*: (The food_items is passed as arguments in the following two functions)

def calculate_weekly_calories(food_items):
total_weekly_calorie = 0

food_dataset = load_food_data()

for food_item in food_items:
    food_type = food_item['food_type']
    frequency_per_week = food_item['frequency_per_week']
    times_per_day = food_item['times_per_day']
    quantity = food_item['quantity']

    st.write(food_type,frequency_per_week,times_per_day,quantity)

    # Filter the DataFrame based on the food_type
    food_row = food_dataset[food_dataset['Food_Name'] == food_type]

    st.write(food_row)

    # Check if the DataFrame is empty
    if not food_row.empty:
        # Calculate calories per serving
        calories_per_serving = (food_row['Calories']) * quantity
        st.write("Calories per serving",calories_per_serving)

        # Calculate total daily calories
        daily_calories = calories_per_serving * times_per_day
        st.write("daily calories",daily_calories)

        # Calculate total weekly calories for the current food item
        weekly_calories = daily_calories * frequency_per_week
        st.write("weekly calories",weekly_calories)

        total_weekly_calorie += weekly_calories
        st.write("total weekly calories",total_weekly_calorie)

    else:
        st.write(f"No data found for {food_type}")
st.write("Out of loop total week calorie",total_weekly_calorie)


return total_weekly_calorie

def calculate_nutritional_composition(food_items):
carbohydrates = 0
protein = 0
fat = 0
fiber = 0
food_dataset = load_food_data()

for food_item in food_items:
    food_type = food_item['food_type']
    frequency_per_week = food_item['frequency_per_week']
    times_per_day = food_item['times_per_day']
    quantity = food_item['quantity']

    # Filter the DataFrame based on the food_type
    food_row = food_dataset[food_dataset['Food_Name'] == food_type]


    # Check if the DataFrame is empty
    if not food_row.empty:
        # Calculate nutritional composition based on weekly calories
        carbohydrates += (food_row['Carbohydrates']) * quantity * frequency_per_week * times_per_day
        protein += (food_row['Protein']) * quantity * frequency_per_week * times_per_day
        fat += (food_row['Fat']) * quantity * frequency_per_week * times_per_day
        fiber += (food_row['Fiber']) * quantity * frequency_per_week * times_per_day
    else:
        st.write(f"No data found for {food_type}")

st.write(carbohydrates,protein,fat,fiber)

return carbohydrates, protein, fat, fiber

In the future, please make sure to format all your code as a code block using triple backticks ( `, no spaces)

All the information is stored in st.session_state.food_items, so you can simply loop through that list of dictionaries and do whatever you want with the info

for food_item in st.session_state.food_items:
    ...

This topic was automatically closed 2 days after the last reply. New replies are no longer allowed.