Hi,
ok, here we go…Sorry, but I wasn’t able to strip it down further.
The below example reads a csv-file with date and various columns as in
t;X;Y
8.3.2020;5;1
9.3.2020;5;2
10.3.2020;6;5
11.3.2020;13;12
12.3.2020;20;26
13.3.2020;29;37
The columns (apart from date) are passed to the dash_table.DataTable as rows.
I want to be able to select the rows which are then visualized in the dash_core_components.Graph
Displaying the graph works fine all the time.
Now on 1st load of the program the DataTable is not showing the correct values when I load the csv.
If I then stop the and restart the dash-server (Strg-C and re-run in the same ipython session) everything works fine as intended.
Any help appreciated!!
Greetings! Stay safe everyone!
# -*- coding: utf-8 -*-
import dash
from dash.dependencies import Input, Output, State
import dash_core_components as dcc
import dash_html_components as html
import dash_table
import base64
import pandas as pd
import io
# import json
df_init = pd.DataFrame(['leer'], columns=['channels'])
app = dash.Dash(__name__)
# app.config['suppress_callback_exceptions'] = True
app.layout = html.Div([
# html.Div(id='waitfor'),
dcc.Upload(
id='upload',
children=html.Div([
'Drag and Drop or ',
html.A('Select a File')
]),
style={
'width': '100%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
}
),
html.Hr(),
dcc.Graph(id='graph'),
html.Hr(),
html.Div([
dash_table.DataTable(id='table',
#columns=[{"name": i, "id": i} for i in df_init.columns],
columns=[{"name": 'channels', "id": 'channels'}],
data=[],
# data=df_init.to_dict('records'),
row_selectable="multi")]),
html.Div(id='error'),
# Hidden div inside the app that stores data
html.Div(id='datastore_table', style={'display': 'none'}),
html.Div(id='datastore_graph', style={'display': 'none'})
])
def extract_data(data):
# extract filename + dataframe from string data
pos = data.find('\n')
filename = data[:pos]
data = data[pos+1:]
df = pd.read_json(data, orient='split')
return filename, df
@app.callback([Output('datastore_table', 'children'),
Output('datastore_graph', 'children'),
Output('error', 'children')],
[Input('upload', 'contents'),
Input('upload', 'filename')])
def data_changed(contents, filename):
if contents is None:
return dash.no_update, dash.no_update, dash.no_update
df = parse_data(contents, filename)
if isinstance(df, pd.DataFrame):
error = '' # clear error msg
else:
error = df # html.Div with error msg
data_table = df_init.to_json(date_format='iso', orient='split')
# print('error: ', data_table)
dff = pd.DataFrame()
data_graph = filename + '\n' + dff.to_json(date_format='iso', orient='split')
return data_table, data_graph, error
df2 = pd.DataFrame(df.columns[1:], columns=['channels'])
data_table = df2.to_json(date_format='iso', orient='split')
# print('data_changed: data_table: %s' % data_table)
data_graph = filename + '\n' + df.to_json(date_format='iso', orient='split')
return data_table, data_graph, error
def parse_data(contents, filename):
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
try:
if 'csv' in filename or 'txt' in filename:
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')),
delimiter=';', decimal=',')
# convert excel time to datetime
# df[df.columns[0]] = pd.TimedeltaIndex(df[df.columns[0]], unit='d') + dt.datetime(1899, 12, 30)
elif 'xls' in filename:
df = pd.read_excel(decoded)
# convert excel time to datetime
# df[df.columns[0]] = pd.TimedeltaIndex(df[df.columns[0]], unit='d') + dt.datetime(1899, 12, 30)
else:
# df = pd.DataFrame()
# return df
return html.Div([
html.Hr(),
html.Div('There was an error processing file %s: ' % filename),
html.Div('unknown file type')])
except Exception as e:
print("Exception parse_data: ", e)
return html.Div([
html.Div('There was an error processing file %s' % filename),
html.Hr(),
html.Div(e)
])
return df
@app.callback([Output('table', 'data'),
Output('table', 'selected_rows')],
[Input('datastore_table', 'children')],
[State('table', 'selected_rows')])
def update_table(data, selected_rows):
if data:
# print('update_table: data: %s' % data)
df = pd.read_json(data, orient='split')
else:
df = df_init
dff = df.to_dict('records') # df.to_dict('rows')
if selected_rows is None:
rows = [] # dash.no_update
else:
# print('update_table, sel:%s, rows:%s' % (selected_rows,rows))
col = len(df.columns)
rows = []
for i in selected_rows:
if i <= col:
rows.append(i)
print('update_table, data: %s, rows:%s' % (dff, rows))
return dff, rows
@app.callback(Output('graph', 'figure'),
[Input('datastore_graph', 'children'),
Input('table', 'selected_rows')])
def update_graph(data, selected_rows):
filter_rows = False
ctx = dash.callback_context
if ctx.triggered:
"""ctx_msg = json.dumps({
'states': ctx.states,
'triggered': ctx.triggered,
'inputs': ctx.inputs
}, indent=2)
# print('ctx_msg: ', ctx_msg)
"""
for trig in ctx.triggered:
id = trig['prop_id'].split('.')[1]
if id == 'selected_rows' and selected_rows is not None:
# print("id selected rows: %s" % selected_rows)
filter_rows = True
break
if data:
filename, df = extract_data(data)
if filter_rows: # update graph
if selected_rows == []:
df = pd.DataFrame()
else: # select column 0 (time) & selected
sel = [0]
# print('col: ', df.columns)
col = len(df.columns) - 1
# print('len col:', col + 1)
for i in selected_rows:
if i < col:
sel.extend([i+1])
# print('update graph sel: ', sel)
df = df.iloc[:, sel]
else: # called by datastore graph
pass # print('update graph: datastore graph changed')
if not isinstance(df, pd.DataFrame):
df = pd.DataFrame()
filename = 'Error: ' + filename
data = [dict(
x=df[df.columns[0]],
y=df[df.columns[i+1]],
name=col,
) for i, col in enumerate(df.columns[1:])]
# print('update_graph: ', data)
return {'data': data,
'layout': dict(
title=filename,
showlegend=True,
legend=dict(
x=0,
y=1.0
),
margin=dict(l=40, r=0, t=40, b=30)
)
}
else:
return dash.no_update
if __name__ == '__main__':
app.run_server(debug=True)