# How to get on\_change callback func work with data\_editor

**URL:** <https://discuss.streamlit.io/t/how-to-get-on-change-callback-func-work-with-data-editor/86141>\
**Category:** Using Streamlit\
**Tags:** data\_editor, session-state, discussion\
**Created:** [November 21, 2024, 11:03pm UTC](https://discuss.streamlit.io/t/how-to-get-on-change-callback-func-work-with-data-editor/86141 "2024-11-21T23:03:53Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![serdar\_bay](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/serdar_bay/32/52473_2.png) [@serdar\_bay](https://discuss.streamlit.io/u/serdar_bay)\
**Post date:** [November 21, 2024, 11:03pm UTC](https://discuss.streamlit.io/t/how-to-get-on-change-callback-func-work-with-data-editor/86141/1 "2024-11-21T23:03:53Z")

</div>

Hi,  
I am trying to use on\_change callback function within data\_editor. I can’t seem to get my table updated when I edit the editable fields on the table. My expectation is as soon as I edit the data the table should update in place. Here is my code that I could not get working correctly for me. Currently, when I change data, nothing happens (i.e the prices do not get updated).

> ```
> if final_dfs:
> st.session_state.final_df = pd.concat(final_dfs, ignore_index=True)
> 
> # Add default values and extra columns
> if "Markup, %" not in st.session_state.final_df.columns:
> st.session_state.final_df["Markup, %"] = 30
> if "External margin, %" not in st.session_state.final_df.columns:
> st.session_state.final_df["External margin, %"] = 50
> if "Select" not in st.session_state.final_df.columns:
> st.session_state.final_df["Select"] = False
>     
> # Define a callback function to recalculate the prices
> def recalculate_prices():
> st.session_state.final_df = calculate_price_with_markup(st.session_state.final_df)
> st.session_state.final_df = calculate_total_price(st.session_state.final_df)
> st.session_state.final_df = calculate_final_base_margin(st.session_state.final_df)
> 
> # Rearrange the column sequence
> desired_order = [
> "part_id",
> "diameter_in",
> "Total Cost (USD)",
> "Markup, %",
> "Price with markup (USD)",
> "External margin, %",
> "Total price (USD)",
> "Final base margin, %",
> "Select"
> ]
> st.session_state.final_df = st.session_state.final_df[desired_order]
> 
> # Initial calculation of prices
> recalculate_prices()
> 
> # Define the column configuration
> column_config = {
> "part_id": st.column_config.TextColumn(
> "Part ID",
> disabled=True,
> ),
> "diameter_in": st.column_config.NumberColumn(
> "Diameter",
> disabled=True,
> ),
> "Total Cost (USD)": st.column_config.NumberColumn(
> "Total Cost (USD)",
> disabled=True,
> ),
> "Markup, %": st.column_config.NumberColumn(
> "Markup, %",
> ),
> "External margin, %": st.column_config.NumberColumn(
> "External margin, %",
> 
> ),
> "Price with markup (USD)": st.column_config.NumberColumn(
> "Price with markup (USD)",
> disabled=True,
> 
> ),
> "Total price (USD)": st.column_config.NumberColumn(
> "Total price (USD)",
> disabled=True,
> ),
> "Final base margin, %": st.column_config.NumberColumn(
> "Final base margin, %",
> disabled=True,
> ),
> 
> "Select": st.column_config.CheckboxColumn("Select"),
> }
> 
> # Display the data editor
> edited_df = st.data_editor(
> st.session_state.final_df,
> key="data_editor",
> hide_index=True,
> column_config=column_config,
> on_change=recalculate_prices,
> )
> 
> ```

---

<div class="post-metadata">

**Author:** ![Encrypt](https://sea2.discourse-cdn.com/streamlit/user_avatar/discuss.streamlit.io/encrypt/32/52088_2.png) [@Encrypt](https://discuss.streamlit.io/u/Encrypt)\
**Post date:** [November 23, 2024, 8:49am UTC](https://discuss.streamlit.io/t/how-to-get-on-change-callback-func-work-with-data-editor/86141/2 "2024-11-23T08:49:51Z")

</div>

The `on_change` callback lacks access to the most recent edited data values. Consequently, I have implemented a manual update procedure for the session state data frame after an edit, ensuring that the prices are recalculated accordingly.

```auto
import streamlit as st
import pandas as pd

# Placeholder functions for price calculations
def calculate_price_with_markup(df):
    df["Price with markup (USD)"] = df["Total Cost (USD)"] * (1 + df["Markup, %"] / 100)
    return df

def calculate_total_price(df):
    df["Total price (USD)"] = df["Price with markup (USD)"] * (1 + df["External margin, %"] / 100)
    return df

def calculate_final_base_margin(df):
    df["Final base margin, %"] = (df["Total price (USD)"] - df["Total Cost (USD)"]) / df["Total price (USD)"] * 100
    return df

# Assuming final_dfs is a list of DataFrames
final_dfs = [
    pd.DataFrame({
        "part_id": ["A1", "B1", "C1"],
        "diameter_in": [1.0, 2.5, 3.0],
        "Total Cost (USD)": [10, 20, 30],
    }),
    pd.DataFrame({
        "part_id": ["D1", "E1", "F1"],
        "diameter_in": [4.0, 5.5, 6.0],
        "Total Cost (USD)": [40, 50, 60],
    })
]

if final_dfs:

    # Define a callback function to recalculate the prices
    def recalculate_prices():
        print("Recalculating prices...")

        st.session_state.final_df = calculate_price_with_markup(st.session_state.final_df)
        st.session_state.final_df = calculate_total_price(st.session_state.final_df)
        st.session_state.final_df = calculate_final_base_margin(st.session_state.final_df)

        # Rearrange the column sequence
        desired_order = [
            "part_id",
            "diameter_in",
            "Total Cost (USD)",
            "Markup, %",
            "Price with markup (USD)",
            "External margin, %",
            "Total price (USD)",
            "Final base margin, %",
            "Select"
        ]
        st.session_state.final_df = st.session_state.final_df[desired_order]

    # Initialize the final DataFrame if not already present
    if 'final_df' not in st.session_state:
        st.session_state.final_df = pd.concat(final_dfs, ignore_index=True)

        # Add default values and extra columns
        if "Markup, %" not in st.session_state.final_df.columns:
            st.session_state.final_df["Markup, %"] = 30
        if "External margin, %" not in st.session_state.final_df.columns:
            st.session_state.final_df["External margin, %"] = 50
        if "Select" not in st.session_state.final_df.columns:
            st.session_state.final_df["Select"] = False

        recalculate_prices()

    # Define the column configuration
    column_config = {
        "part_id": st.column_config.TextColumn(
            "Part ID",
            disabled=True,
        ),
        "diameter_in": st.column_config.NumberColumn(
            "Diameter",
            disabled=True,
        ),
        "Total Cost (USD)": st.column_config.NumberColumn(
            "Total Cost (USD)",
            disabled=True,
        ),
        "Markup, %": st.column_config.NumberColumn(
            "Markup, %",
        ),
        "External margin, %": st.column_config.NumberColumn(
            "External margin, %",

        ),
        "Price with markup (USD)": st.column_config.NumberColumn(
            "Price with markup (USD)",
            disabled=True,

        ),
        "Total price (USD)": st.column_config.NumberColumn(
            "Total price (USD)",
            disabled=True,
        ),
        "Final base margin, %": st.column_config.NumberColumn(
            "Final base margin, %",
            disabled=True,
        ),

        "Select": st.column_config.CheckboxColumn("Select"),
    }

    # Display the data editor
    edited_df = st.data_editor(
        st.session_state.final_df,
        key="data_editor",
        hide_index=True,
        column_config=column_config,
    )

    # Check if the data has been edited and recalculate prices
    if not edited_df.equals(st.session_state.final_df):
        st.session_state.final_df = edited_df
        recalculate_prices()

        # Trigger a rerun to update the displayed data
        st.rerun()

```

---

<div class="post-metadata">

**Author:** ![system](https://global.discourse-cdn.com/streamlit/original/3X/c/f/cf4c2ee0d938358f82448c5fe4b9c3c91d7ce19c.svg) [@system](https://discuss.streamlit.io/u/system)\
**Post date:** [May 22, 2025, 8:50am UTC](https://discuss.streamlit.io/t/how-to-get-on-change-callback-func-work-with-data-editor/86141/3 "2025-05-22T08:50:19Z")

</div>

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