Date_editor tied to a set of text_input

Hi there,
I’m looking to have a dataframe within a data_editor “tied” to a set of text_inputs…

  1. I’d like to be able to edit the values either in the text_inputs or the data_editor and they would both update whenever a change in either was made.
  2. I’d also like to be able to add new rows via the data_editor and have that add additional text_inputs

Any help would be appreciated, I’ve gotten this far but it seems like the changes only update every other change for some reason:

import streamlit as st
from streamlit import session_state as ss
import pandas as pd

st.set_page_config(layout='wide')

print('app started')

# Load data frame
if 'df' not in ss:
    ss['df'] = pd.DataFrame({'strategy': ['strategy1', 'strategy2', 'strategy3'], 'value': ['1', '2', '3']})
    print('initializing df')

# Initialize session state for text inputs
for strategy in ss['df']['strategy']:
    key = strategy + "_input"
    if key not in ss:
        ss[key] = ss['df'][ss['df']['strategy'] == strategy]['value'].values[0]

# Function to handle changes in text_input fields
def change_value(key):
    strategy = key.split('_')[0]
    new_value = ss[key]
    ss['df'].loc[ss['df']['strategy'] == strategy, 'value'] = new_value

    print('--------------')
    print('input changed: ' + key)
    print(ss[key])
    print(ss['df'])

# Function to handle changes in the data_editor
def change_table():
    for index, row in ss['df'].iterrows():
        key = row['strategy'] + "_input"
        ss[key] = row['value']
    print('ss[df_editor]_____________')
    print(ss['df_editor'])

# Display the data_editor
edited = st.data_editor(ss['df'], num_rows='dynamic', on_change=change_table, key='df_editor',
                        column_config={
                            "strategy": st.column_config.TextColumn(
                                "strategy",
                                width="small",
                                required=True,
                            ),
                            "value": st.column_config.TextColumn(
                                "value",
                                width='large',
                                required=True,
                            ),
                        })

# Update the session state DataFrame with the edited DataFrame
ss['df'] = edited

# Synchronize text inputs with the updated DataFrame
for index, row in ss['df'].iterrows():
    key = row['strategy'] + "_input"
    if key not in ss or ss[key] != row['value']:
        ss[key] = row['value']

# Display text_input fields for each strategy
for strategy in ss['df']['strategy']:
    key = strategy + "_input"
    st.text_input(strategy, key=key, value=ss[key], on_change=lambda key=key: change_value(key))

print('--------------')
print('table changed')
print(ss['df'])

Hi all, still looking for help…

Tried a new approach, and I got the behavior I want between the data_editor and the text_inputs… but it requires me to rerun the app every time some change happens…

Anyone have any suggestions for how to achieve this but have it be a more seamless experience?

Right now it jumps back to the top and collapses the expander every time I change the value in the data_editor

(I basically just want to be able to live edit a dataframe in memory via two different components a data_editor or text_input/selector, also see the changes in the values of either component.)

Thanks in advance!

import pandas as pd
import streamlit as st
from streamlit import session_state as ss

df = pd.DataFrame(
    {
        "col1": ['strategy1', 'strategy2', 'strategy3', 'strategy4', 'strategy5'],
        "col2": [1, 2, 3, 4, 5],
    }
)

if "df" not in st.session_state:
    ss['df'] = df

print('app started')


def main():
    print('fragment ran')
    print('df')
    print(ss['df'])

    ss['df_edited'] = st.data_editor(ss['df'], num_rows='dynamic')

    print('editor')
    print(ss['df_edited'])


    if ss['df_edited'].equals(ss['df']):
        print('df - same')
    else:
        print('df - different')
        ss['df'] = ss['df_edited']
        st.rerun()

    return ss['df']



def print_inputs():
    ss['df_text'] = ss['df'].copy()
    for key in ss['df_text']['col1'].tolist():
        ss['df_text'].loc[ss['df_text']['col1'] == key, 'col2'] = st.session_state['input_'+str(key)]

    if ss['df_text'].equals(ss['df']):
        print('text - same')
    else:
        print('text - different')
        ss['df'] = ss['df_text']
        st.rerun()



def inputs():
    for key, value in zip(ss['df']['col1'].tolist(), ss['df']['col2'].tolist()):
        st.text_input(label=str(key), key='input_'+str(key), value=value)
    
    print_inputs()




main()
with st.expander('Inputs', ):
    inputs()