Editable Data Tables in Streamlit

Hello!
Thank you to the dev team for making Streamlit, this is quite a brilliant, exiting and useful tool for data engineers who want to quickly and easily make front end app for data visualization.

I am wondering if there is a way to insert editable data table, such as the one in Dash.

It seems that editable datatable is a feature who does not exist in Plotly, so the plotly_chart() method won’t work.

Thanks,

6 Likes

This would indeed be an incredible feature. It would be very useful to be able to read pandas dataframes into a Streamlit table and allow that table to be point and click editable and then read the values out of that table back into a dataframe.

3 Likes

@sheridonx the way I am currently handling this problem is by displaying a Pandas dataframe and using the sliders and button presses to edit the table with whatever criteria is interesting. The only issue is you’ll need to do all of your sliding and editing in one swoop as Streamlit doesn’t appear to be able to persist when another widget is used (yet). See LINK

Hello,
to address your issue, I would consider using i/o systems to save the status after each click on button (by using pickle file for example) and reload your variables from the file at the beginning of your script.
This should work well if there will be at most one user on your app at the same time (which means there is no need to worry about multi-agent problems).

@sheridonx There is very frequently up to 5 people using the app at any given time. When I was testing for my own use that’s similar to what I was doing.

I’ve now remedied the issue by using a database… reading and writing as necessary.

Would still be best to be able to continually make changes to the dataframe and only read from the db at the beginning and write at the end.

@posey22 Absolutely.
I am also struggling to lay a streamlit project into Flask framework, like redirecting to a streamlit page by a flask view decorator…but I got totally no idea about it. Have you tried something similar?

@sheridonx So my application is mainly .NET and serves a handful of different analytics tools, my Streamlit pages being part of that. I just put a button on the pages where I list the various projects or tools you can visit. From there, I just redirect to wherever the streamlit project lives.

As for a Flask specific implementation, not sure I can help there, no experience with mixing streamlit and Flask. Maybe this will help?: LINK

Hey @sheridonx, thanks for checking out Streamlit, and for the kind words!

Editable data tables don’t currently exist in Streamlit. You can approximate them somewhat by using st.text_input and st.number_input to allow the user to enter values that you write back into your dataframe, like in this contrived example:

import streamlit as st
import numpy as np
import pandas as pd

# Randomly fill a dataframe and cache it
@st.cache(allow_output_mutation=True)
def get_dataframe():
    return pd.DataFrame(
        np.random.randn(50, 20),
        columns=('col %d' % i for i in range(20)))


df = get_dataframe()

# Create row, column, and value inputs
row = st.number_input('row', max_value=df.shape[0])
col = st.number_input('column', max_value=df.shape[1])
value = st.number_input('value')

# Change the entry at (row, col) to the given value
df.values[row][col] = value

# And display the result!
st.dataframe(df)

But I imagine you’re after a more spreadsheet-like interface, where the user just directly edits the “cell” they’re interested in.

We don’t currently have this feature on the roadmap, but have been giving it some thought in a GitHub issue. If you’re interested, please feel free to upvote the issue and/or participate in the discussion!

3 Likes

Any idea if this will be implemented to have a more spreadsheet-like interface, where the user just directly edits the “cell” they’re interested in? (as you mentioned)

thanks Tim.

1 Like

Hey @dariushazimi as you can see in our roadmap we are working on a custom components project which will solve it.

1 Like

Guess you’re looking for solutions like Ag-grid or grid studio. People love the straightforwardness and interactive features. While these powerful features may need complex configurations. Anyway, if you like to play with javascript stuff, you will figure it out.

Hi! Thanks for the solution, what if we want to change more than one value? We’d have to save the file and read it again, right? but if we use file_uploader() we don’t have the name of the file… Is there an easy way to change more than one value?
Thaaanks!

1 Like

For future references: Don’t use the solution provided by tim. It is still a workaround for a non-existent solution, but it is awful user experience since user will want to change both row and column, which will edit some unrelated parameters during the edit.

2 Likes

Take a look at https://discuss.streamlit.io/t/ag-grid-component-with-input-support

2 Likes

Great tool, but I try to keep the code within default anaconda imports since I’ll distribute it locally. I hope that developers can take your solution as a beta asap.

I think the key is to use st.session_state variable, it can be a dictionary. We can save a whole data frame into it. Then we can set default values of those text_input widgets (array) by this data frame.
We can also use Ag-Grid. It looks better if you like editable table. Remember to restore the values before you change the editable status of table.

import streamlit as st
import pandas as pd
from st_aggrid import AgGrid

if 'init' not in st.session_state: st.session_state['init']=False
if 'store' not in st.session_state: st.session_state['store']={}
if 'store_d' not in st.session_state: st.session_state['store_d']={}
if 'edit' not in st.session_state: st.session_state['edit']=True

if st.session_state.init == False:
    st.session_state.store_d = {'A':[1,2,3,4], 'B':[7,6,5,4]}
    st.session_state.init = True

@st.cache(allow_output_mutation=True)
def fetch_data():
    return pd.DataFrame(st.session_state.store_d)

def saveDefault():
    st.session_state.store_d = st.session_state.store
    return

def app():
    c1,c2=st.columns(2)
    lock=c1.button('Lock', key='lock', on_click=saveDefault)
    unlock=c2.button('Unlock', key='unlock', on_click=saveDefault)
    if lock: st.session_state.edit = False
    if unlock: st.session_state.edit = True

    df = fetch_data()
    ag = AgGrid(df, editable=st.session_state.edit, height=200)
    df2=ag['data']
    st.session_state.store=df2.to_dict()
    st.dataframe(df2)

if __name__ == '__main__':
    app()
1 Like