Reputation: 107
I'm trying to build a dashboard using plotly/Dash that allows the user to upload a CSV file and then plot the results. I have borrowed from the examples in the dash documentation and tried to piece together an example that plots the graph but I get an error message which I've attached below.
My code is attached:
import base64
import datetime
import io
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 plotly.graph_objs as go
import pandas as pd
graph_name = 'Time series plot'
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
colors = {
"graphBackground": "#212529",
"background": "#000000",
"text": "#ffffff"
}
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
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'
},
# Allow multiple files to be uploaded
multiple=True
),
html.Div(id='output-data-upload'),
dcc.Graph(id='new-hydrograph')
])
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.'
])
if df.shape[1] == 4:
df = df.iloc[2:]
df.columns = ['Datetime', 'Depth (in)', 'Velocity (feet/sec)', 'Flow (MGD)']
else:
df.columns = ['Datetime', 'Rain (in)']
return df
@app.callback(Output('output-data-upload', 'children'),
[Input('upload-data', 'contents')],
[State('upload-data', 'filename')])
def update_output(list_of_contents, list_of_names):
if list_of_contents is not None:
children = [
parse_contents(c, n) for c, n in
zip(list_of_contents, list_of_names)]
return children
@app.callback(Output('new-hydrograph', 'figure'),
[Input('upload-data', 'contents'),
Input('upload-data', 'filename')])
def plot_graph(contents, filename):
df = parse_contents(contents, filename)
trace1 = go.Scatter(
x = df.date,
y = df['Depth (in)'],
mode = 'lines',
)
return {
'data': [trace1],
'layout': go.Layout(
title = graph_name,
plot_bgcolor = colors["graphBackground"],
paper_bgcolor = colors["graphBackground"])
}
if __name__ == '__main__':
app.run_server(debug=True)
The error message I get is:
Traceback (most recent call last):
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1997, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1985, in wsgi_app
response = self.handle_exception(e)
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1540, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\_compat.py", line 33, in reraise
raise value
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1982, in wsgi_app
response = self.full_dispatch_request()
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\_compat.py", line 33, in reraise
raise value
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1612, in full_dispatch_request
rv = self.dispatch_request()
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
sk\app.py", line 1598, in dispatch_request
return self.view_functions[rule.endpoint](**req.view
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
h-0.39.0-py3.6.egg\dash\dash.py", line 1073, in dispatch
response.set_data(self.callback_map[output]['callbac
File "C:\Users\hvkumar\AppData\Local\Continuum\Anacond
h-0.39.0-py3.6.egg\dash\dash.py", line 969, in add_conte
output_value = func(*args, **kwargs)
File "C:\Users\hvkumar\Documents\Atlanta\pressure_data
- Copy\app_1.py", line 93, in plot_graph
df = parse_contents(contents, filename)
File "C:\Users\hvkumar\Documents\Atlanta\pressure_data
- Copy\app_1.py", line 50, in parse_contents
content_type, content_string = contents.split(',')
AttributeError: 'list' object has no attribute 'split'
Here's an example CSV
PRC-01 "Average=15min" "QualityFlag=FALSE" "QualityValue=FALSE"
DateTime "MP1\DFINAL" "MP1\VFINAL" "MP1\QFINAL"
M/d/yyyy h:mm:ss tt "inches" "feet/sec" "MGD"
1/1/2015 0:00 14.9748 3.69 7.976
1/1/2015 0:15 15.0504 3.64 7.934
1/1/2015 0:30 14.7672 3.79 8.047
1/1/2015 0:45 14.9844 3.68 7.97
1/1/2015 1:00 14.8416 3.52 7.53
1/1/2015 1:15 14.7108 3.55 7.497
Upvotes: 0
Views: 649
Reputation: 6776
Your code had several problems:
multiple=True
in the upload field. This causes the callback function to receive lists instead of strings in the contents, filename
variables. Setting to False
will solve that error, and allow you to select only a single file for upload, as I assume you intend.delimiter='\t'
in your pd.read_csv
call.contents, filename
are both None
. I suggest checking this at the start of the callback function, before attempting to parse the input.df['Datetime']
, according to the columns you define in parse_contents
.Points 3 and 4 are taken care of in the revised function below. Don't forget to take care of points 1 and 2.
@app.callback(Output('new-hydrograph', 'figure'),
[Input('upload-data', 'contents'),
Input('upload-data', 'filename')])
def plot_graph(contents, filename):
fig = {
'layout': go.Layout(
title=graph_name,
plot_bgcolor=colors["graphBackground"],
paper_bgcolor=colors["graphBackground"])
}
if contents:
df = parse_contents(contents, filename)
trace1 = go.Scatter(
x=df['Datetime'],
y=df['Depth (in)'],
mode='lines',
)
fig['data'] = [trace1]
return fig
Upvotes: 1