Reputation: 303
I would like to implement a live-update feature to the add column function based on the documentation on editable DataTable https://dash.plotly.com/datatable/editable such that a new column is added to the datatable when the CSV file is updated. I've got the callback working and I can add new columns as new CSV data is updated through live update but I've run into some problems. In my first attempt (labelled first code), I declared a global variable (which I know is bad in DASH) in an attempt to keep track of current CSV contents and the compare it to an updated CSV file to check for new data, but this version fails to load existing CVS data on initial start up and only adds new data. The second code, loads up existing CSV data into columns, but on live-update it simply adds duplicate columns. I cannot simply remake the whole datatable with a new CSV file because if there is user input in the cells, then that would be lost on update.
My question is therefore: How do I store the state of something (ie: number of lines of CSV data) without using global variables in Dash so that I have the ability to compare the existing state of a CSV file to a new state. I can't see how this is accomplished since assigned variables are reset on live-update. I've read about Hidden Div and storing data in a users browser session but I can't get it to work. Is that the direction I should be going or is there a more elegant solution?
html.Div([dash_table.DataTable(
id='editing-columns',
columns=[{
'name': 'Parameter',
'id': 'column1',
'deletable': True,
'renamable': True
}],
style_cell={
'whiteSpace': 'normal',
'height': 'auto',
'width': '20',
# 'minWidth': '50px',
'textAlign': 'left',
},
data=[
{'column1': j}
for j in table_contents
],
editable=True,
)], className="drug_input"),
#First code
@app.callback(Output('editing-columns', 'columns'),
[Input('graph-update', 'n_intervals')],
[State('editing-columns', 'columns')])
def update_columns(n, existing_columns):
check_length = []
global sierra
with open('assets' + '/' + 'record ' + str(current) + '.csv', 'r') as rf:
reader = csv.reader(rf)
for a in reader:
check_length.append(a[3])
if len(check_length) == 0:
return existing_columns
elif len(check_length) > sierra:
existing_columns.append({
'id': check_length[-1], 'name': check_length[-1],
'renamable': True, 'deletable': True
})
sierra = len(check_length)
return existing_columns
else:
return existing_columns
#Second code
@app.callback(Output('editing-columns', 'columns'),
Input('graph-update', 'n_intervals'),
State('editing-columns', 'columns'))
def update_columns(n, existing_columns):
counter = 0
with open('assets' + '/' + 'record ' + str(current) + '.csv', 'r') as rf:
reader = csv.reader(rf)
for a in reader:
counter = counter + 1
existing_columns.append({
'id': 'counter', 'name': a[3],
'renamable': True, 'deletable': True
})
return existing_columns
Upvotes: 0
Views: 1018
Reputation: 6596
I've read about Hidden Div and storing data in a users browser session but I can't get it to work. Is that the direction I should be going or is there a more elegant solution?
Yes, you should use the store component for this.
You can store everything in a dict, with one key for your original file, and another key containing the modified one with user inputs. Make sure each callback reads in the store as a State
. One should output to the table, and the other should output to the store.
Upvotes: 1