Hi there,
I just discovered dash_table, and I am having some trouble figuring out the last step in my code.
I want to be able to load a csv or excel file and display it on the top.
The rows of the displayed table can then be selected and/or removed.
I would like the selected rows to populate a second table below, these are the “accepted rows”.
and the removed rows to populate a 3 table below that, these are the “rejected rows”.
I managed to do the loading and updating the accepted table, but still having trouble with the rejected one.
Basically I can only get one row back and each time its replaced by the new removed row.
How do make it work so that I keep the all rejected rows ?
input file: comma separated csv file
#=============================================================================#
# #
# Dashboard #
# #
#=============================================================================#
# Perform imports here:
import pandas as pd
pd.options.mode.chained_assignment = None # default = 'warn'
import io
import base64
import numpy as np
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table
import dash_bootstrap_components as dbc
import dash_daq as daq
from dash.dependencies import Input, Output, ALL, State
# Launch the application:
app = dash.Dash(external_stylesheets=[dbc.themes.CERULEAN])
app.config.suppress_callback_exceptions = True
server = app.server
#=============================================================================#
# #
# Layout #
# #
#=============================================================================#
content = dbc.Container(
[
dbc.Row(
[
dbc.Col(
[
dbc.Button("Select all",id='all-button',
className="btn btn-outline-info")
], md = 2, align='center',
),
dbc.Col(
[
dcc.Upload(id='upload-data',
children=html.Div(['Drag and Drop or ',
html.A('Select Files')]),
style={
'width': '100%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
),
], md = 8, align='center',
),
dbc.Col(
[
dbc.Button("Submit",id='submit-button', className="btn btn-warning"),
], md = 2, align='center',
),
],justify='end',style={'background-color': '#fff7ed',}
),
dbc.Row(
[
dbc.Col(id='output-data-upload',align='center',style={'height': '450px'}),
],justify='center',style={'background-color': '#fff7ed',}
),
dbc.Row(
[
dbc.Col(
[
html.H4(['Accepted'],style={'color': '#000000'}),
html.Hr(style={'borderWidth': '0.3vh', 'borderColor': '#FEC700',}),
],
),
],justify='left', style={'background-color': '#edffed',},
),
dbc.Row(
[
dbc.Col(id='output-data-accepted',align='center',style={'height': '450px'}),
],justify='center',style={'background-color': '#edffed',}
),
dbc.Row(
[
dbc.Col(
[
html.H4(['Rejected'],style={'color': '#000000'}),
html.Hr(style={'borderWidth': '0.3vh', 'borderColor': '#FEC700',}),
]
),
],justify='left',style={'background-color': '#ffeded',}
),
dbc.Row(
[
dbc.Col(id='output-data-rejected',align='center',style={'height': '450px'}),
dcc.Store(id='rejected-memory'),
],justify='center',style={'background-color': '#ffeded',}
),
],
)
#=============================================================================#
# App Layout #
#=============================================================================#
app.layout = html.Div([
content,
])
#=============================================================================#
# #
# Callbacks & Functions #
# #
#=============================================================================#
#=============================================================================#
# Load Data #
#=============================================================================#
def parse_contents(contents, filename):
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
try:
if 'csv' in filename:
# Assume that the user uploaded a CSV file
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')))
elif 'xls' in filename:
# Assume that the user uploaded an excel file
df = pd.read_excel(io.BytesIO(decoded))
except Exception as e:
print(e)
return html.Div([
'There was an error processing this file.'
])
return html.Div([
dash_table.DataTable(id='input-datatable',
data=df.to_dict('records'),
columns=[{'name': i, 'id': i} for i in df.columns],
row_deletable=True,
row_selectable='multi',
selected_rows=[],
fixed_rows={'headers': True},
style_table={'overflowX': 'auto','height': 400},
style_cell={'overflow': 'hidden',
'textOverflow': 'ellipsis',
'minWidth': '180px', 'width': '180px', 'maxWidth': '180px',
},
tooltip_data=[
{
column: {'value': str(value), 'type': 'markdown'}
for column, value in row.items()
} for row in df.to_dict('records')
],
tooltip_duration=None
),
])
@app.callback(Output('output-data-upload', 'children'),
Input('upload-data', 'contents'),
State('upload-data', 'filename'))
def update_output(contents, filename):
if contents is not None:
children = [parse_contents(contents, filename)]
return children
#=============================================================================#
# Accept/Reject Rows #
#=============================================================================#
@app.callback(
[Output('input-datatable', "selected_rows"),],
[Input('all-button', 'n_clicks'),],
[State('input-datatable', "derived_virtual_data"),]
)
def select_all(n_clicks, selected_rows):
if selected_rows is None:
return [[]]
else:
return [[i for i in range(len(selected_rows))]]
@app.callback(
Output('output-data-accepted', 'children'),
Input('input-datatable', 'selected_rows'),
State('input-datatable', 'data'),
)
def update_accepted_table(selected_rows, rows):
if selected_rows is None:
selected_rows = []
if rows is None:
dff = pd.DataFrame()
else:
dff = pd.DataFrame(rows)
dff = dff.iloc[selected_rows]
table = html.Div([
dash_table.DataTable(
columns=[
{"name": i, "id": i} for i in dff.columns
],
data=dff.to_dict("rows"),
fixed_rows={'headers': True},
style_table={'overflowX': 'auto','height': 400},
style_cell={'overflow': 'hidden',
'textOverflow': 'ellipsis',
'minWidth': '180px', 'width': '180px', 'maxWidth': '180px',
},
tooltip_data=[
{
column: {'value': str(value), 'type': 'markdown'}
for column, value in row.items()
} for row in dff.to_dict('records')
],
tooltip_duration=None
),
])
return table
@app.callback(
Output('output-data-rejected', 'children'),
Input('input-datatable', 'data_previous'),
State('input-datatable', 'data'),
)
def update_rejected_table(previous_rows, current_rows):
if previous_rows is None:
dff = pd.DataFrame()
else:
df_1row = pd.DataFrame([row for row in previous_rows if row not in current_rows])
dff = df_1row
table = html.Div([
dash_table.DataTable(
columns=[
{"name": i, "id": i} for i in dff.columns
],
data=dff.to_dict("rows"),
fixed_rows={'headers': True},
style_table={'overflowX': 'auto','height': 400},
style_cell={'overflow': 'hidden',
'textOverflow': 'ellipsis',
'minWidth': '180px', 'width': '180px', 'maxWidth': '180px',
},
tooltip_data=[
{
column: {'value': str(value), 'type': 'markdown'}
for column, value in row.items()
} for row in dff.to_dict('records')
],
tooltip_duration=None
),
])
return table
#=============================================================================#
#=============================================================================#
if __name__ == '__main__':
app.run_server()