St.text_input: value not updating

Hi,

New to streamlit, this is my issue: I’m trying to provide the user with an interface to annotate some data. For each item the user should give a label and may optionally leave a comment, and they can navigate across the different items with ‘prev’ and ‘next’ buttons. A basic version of the code is here:

import streamlit as st

N=10

choices_values = ['No label', 'YES','NO', 'NA/unclear']
choices_position = { choice:i for i,choice in enumerate(choices_values) }
map_choice_to_value = { 'No label': None, 'YES': 1, 'NO': 0, 'NA/unclear': -1}
map_value_to_choice = { value:key for key, value in map_choice_to_value.items() }

# go to next pair
def next_pair():
    st.session_state.current_index += 1

# go to previous pair
def prev_pair():
    st.session_state.current_index -= 1

# save 
def change_label():
    choice = st.session_state.select_label
    st.session_state.labels[st.session_state.current_index] = map_choice_to_value[choice]

def edit_comment_area():
    st.session_state.comments[st.session_state.current_index] = st.session_state.comment_area



top_text = st.markdown('**Loading data...**')
# initialize state variables
if 'labels' not in st.session_state:
    st.session_state.labels = [None] * N
if 'comments' not in st.session_state:
    st.session_state.comments = [None] * N
if 'current_index' not in st.session_state:
    st.session_state.current_index = 0
n_labels = sum(x is not None for x in st.session_state.labels)
top_text.markdown(f"**Item {st.session_state.current_index+1}/{N}** ({n_labels}/{N} annotated)")


# User input: label choice
current_label = st.session_state.labels[st.session_state.current_index]
st.radio('Are these two reports similar?', 
                    options= choices_values,
                    index = choices_position[map_value_to_choice[current_label]],
                    key = 'select_label',
                    on_change=change_label)

# User input: optional comments
st.text(st.session_state.comments[st.session_state.current_index])
st.text_area('Comment (optional)', 
                key='comment_area',
                value = st.session_state.comments[st.session_state.current_index],
                on_change=edit_comment_area)

# UI: Previous and next buttons to navigate across the pairs
#
prev_button = st.button('Previous', 
                        on_click=prev_pair, 
                        disabled=st.session_state.current_index == 0)
next_button = st.button('Next', 
                        on_click=next_pair,
                        disabled=st.session_state.current_index == N-1)

The labels part work well: when the user changes a label for item X, navigates to other items, then comes back to item X, they will find the last label they selected for X.

However the comments don’t work: when the user enters a comment it is correctly stored in st.session_state.comments and it can be printed by st.write, but even though the value arg in st.text_area is set to the right text, it does not show up in the text area as expected.

I noticed a few things: entering a comment for item X then another comment for the previous or next item and immediately going back makes the comment appear in the text_area for X. However navigating again in other comments makes both disappear, even though st.session_state.comments contains the correct value.

Am I missing something? How do I obtain the expected behaviour?

Debugging info:

  1. running locally
  2. NA
  3. code included in the post
  4. no error
  5. python 3.8.10, streamlit 1.35.0

Hi @Erwan

Have you try using 2 versions of st.text_area in a conditional. In a recent app that I built, I was able to assign values from a session state variable to a st.text_input widget:

    if 'email' not in st.session_state:
        with st.form('EmailForm'):
          st.session_state.email = st.text_input("Email", "").lower()
          submitted = st.form_submit_button("Submit")
          if submitted:
            check(st.session_state.email)
    else:
        with st.form('EmailForm'):
          st.session_state.email = st.text_input("Email", value=st.session_state.email).lower()
          submitted = st.form_submit_button("Submit")
          if submitted:
            check(st.session_state.email)

You’ll notice the first instance value parameter was not used while in the second instance the session state variable value was assigned to the value parameter.

Hope this helps!

Thank you for the tip @dataprofessor, but it didn’t help in my case: the session state variable is always defined and can be printed with st.text, but for some reason the st.text_area sometimes does not render the value parameter.