I'm following a tutorial here to build a plotly dashboard. I've spent the whole day looking for solution or trying to solve it on my own but no luck. Ideally it should upload a xy, xyy,xyyy... type of data and generate a line plot.
However, after uploading the data I get this error,
This is the sampple data I'm trying to run it on,
Below is my code which is just a copy from above link,
import base64
import datetime
import io
import plotly.graph_objs as go
import cufflinks as cf
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 pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server
colors = {
"graphBackground": "#F5F5F5",
"background": "#ffffff",
"text": "#000000"
}
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
),
dcc.Graph(id='Mygraph'),
html.Div(id='output-data-upload')
])
def parse_data(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 or TXT 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))
elif 'txt' or 'tsv' in filename:
# Assume that the user upl, delimiter = r'\s+'oaded an excel file
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')), delimiter = r'\s+')
except Exception as e:
print(e)
return html.Div([
'There was an error processing this file.'
])
return df
#app.callback(Output('Mygraph', 'figure'),
[
Input('upload-data', 'contents'),
Input('upload-data', 'filename')
])
def update_graph(contents, filename):
fig = {
'layout': go.Layout(
plot_bgcolor=colors["graphBackground"],
paper_bgcolor=colors["graphBackground"])
}
if contents:
contents = contents[0]
filename = filename[0]
df = parse_data(contents, filename)
df = df.set_index(df.columns[0])
fig['data'] = df.iplot(asFigure=True, kind='scatter', mode='lines+markers',
size=1)
return fig
#app.callback(Output('output-data-upload', 'children'),
[
Input('upload-data', 'contents'),
Input('upload-data', 'filename')
])
def update_table(contents, filename):
table = html.Div()
if contents:
contents = contents[0]
filename = filename[0]
df = parse_data(contents, filename)
table = html.Div([
html.H5(filename),
dash_table.DataTable(
data=df.to_dict('rows'),
columns=[{'name': i, 'id': i} for i in df.columns]
),
html.Hr(),
html.Div('Raw Content'),
html.Pre(contents[0:200] + '...', style={
'whiteSpace': 'pre-wrap',
'wordBreak': 'break-all'
})
])
return table
if __name__ == '__main__':
app.run_server(debug=True)
Since this graph is a cufflinks graph, the graph is displayed by setting it as fig as it is, rather than assigning it as plotly data.
Instead of this.
fig['data'] = df.iplot(asFigure=True, kind='scatter', mode='lines+markers', size=1)
Correct code
fig = df.iplot(asFigure=True, kind='scatter', mode='lines+markers', size=1)
Related
I am using a pdf to extract some data and convert it into pandas dataframe.
I'm using below code from dash tutorial to display the data on dash app. What I want to do next is be able to upload the pdf instead of predefining it in the code. I could find similar examples for csv but with pdf it doesn't work in the same way.
pdfFileObj = open('test.pdf', 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)
#some operations on pdf to produce df1 and df2 using PyPDF2
app = Dash(__name__)
app.layout = html.Div([
html.H4('Some title'),
html.P(id='table_out'),
dash_table.DataTable(
id='table',
columns=[{"name": i, "id": i}
for i in df1.columns],
data=df1.to_dict('records'),
style_cell=dict(textAlign='left'),
style_header=dict(backgroundColor="paleturquoise"),
style_data=dict(backgroundColor="lavender")
),
html.H4("Some title"),
html.P(id='table_out1'),
dash_table.DataTable(
id='table1',
columns=[{"name": i, "id": i}
for i in df2.columns],
data=df2.to_dict('records'),
style_cell=dict(textAlign='left'),
style_header=dict(backgroundColor="paleturquoise"),
style_data=dict(backgroundColor="lavender")
)
])
#app.callback(
Output('table_out', 'children'),
Input('table', 'active_cell'))
#app.callback(
Output('table_out1', 'children'),
Input('table1', 'active_cell'))
def update_graphs(active_cell):
if active_cell:
cell_data = df1.iloc[active_cell['row']][active_cell['column_id']]
cell_data2 = df2.iloc[active_cell['row']][active_cell['column_id']]
return cell_data, cell_data2
#return f"Data: \"{cell_data}\" from table cell: {active_cell}"
return "Click the table"
app.run_server(debug=True)
I've had success with the below code, which uses the tabula package to parse contents of a pdf into Pandas dataframe and display that in the app.
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output, State
import dash_table
import pandas as pd
import base64
import io
import tabula
app = dash.Dash()
# Callback to parse contents of a pdf
#app.callback(Output('pdf-viewer', 'data'),
Output('pdf-viewer', 'columns'),
Input('pdf-upload', 'contents'),
State('pdf-upload', 'filename'),
prevent_initial_call=True
)
def pdf_output(contents, filename):
if contents is not None:
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
#My pdf only has one page and one table with two columns
df = tabula.read_pdf(io.BytesIO(decoded), pages=1, pandas_options={'header': None})[0]
df.columns = ['Parameter', 'Value']
return df.to_dict('records'), [{"name": i, "id": i, 'editable':True} for i in df.columns]
#Upload component:
pdf_load = dcc.Upload(id='pdf-upload',
children=html.Div(['Drag and Drop or ', html.A('Select PDF files')]),
style={'width': '90%', 'height': '60px', 'lineHeight': '60px',
'borderWidth': '1px', 'borderStyle': 'dashed',
'borderRadius': '5px', 'textAlign': 'center', 'margin': '10px'},
)
#Table to view output from pdf:
pdf_table = dash_table.DataTable(id='pdf-viewer',
page_action='none',
fixed_rows={'headers': True},
style_table={'height': 500, 'overflowY': 'auto'},
style_header={'overflowY': 'auto'}
)
#Place into the app
app.layout = html.Div([html.H4('Some title'),
pdf_load,
html.Br(),
pdf_table
])
if __name__ == '__main__':
app.run_server(debug = False)
Output (no formatting applied) should look something like this:
Example dash
I am using the following code (from Plotly Dash documentation)to display a data table after uploading an csv/xlsx file into the Dash app.
import base64
import datetime
import io
from jupyter_dash import JupyterDash
import dash
from dash.dependencies import Input, Output, State
from dash import dcc, html, dash_table
import pandas as pd
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = JupyterDash(__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'),
])
def parse_contents(contents, filename, date):
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([
html.H5(filename),
html.H6(datetime.datetime.fromtimestamp(date)),
dash_table.DataTable(
df.to_dict('records'),
[{'name': i, 'id': i} for i in df.columns],
page_size =15
),
html.Hr(), # horizontal line
# For debugging, display the raw contents provided by the web browser
html.Div('Raw Content'),
html.Pre(contents[0:200] + '...', style={
'whiteSpace': 'pre-wrap',
'wordBreak': 'break-all'
})
])
#app.callback(Output('output-data-upload', 'children'),
Input('upload-data', 'contents'),
State('upload-data', 'filename'),
State('upload-data', 'last_modified'))
def update_output(list_of_contents, list_of_names, list_of_dates):
if list_of_contents is not None:
children = [
parse_contents(c, n, d) for c, n, d in
zip(list_of_contents, list_of_names, list_of_dates)]
return children
app.run_server(mode='external')
Strangely, for files with size (1mb - 2mb) I am being able to display the file but for a file of size 14mb (approx) I am not being able to do the same and it is just looking like this -
I have tried using the max_size property setting it to -1(infinite size) as well but it doesn't solve the problem. Is there any way to do the same using dash_uploader?
I'm new to the Plotly Dash framework and have attempted to build a simple dashboard that:
Allows the user to upload a CSV file to analyze graphically.
Creates a Pandas data frame based on the file uploaded in step #1.
2a. Renders nothing if the CSV file (and resulting data frame) has not been selected.
Renders a basic bar plot (or scatter plot, heat map, etc.) based on the data contained in the aforementioned data frame.
The data in my CSV file looks similar to the following:
df = pd.DataFrame({'Make':['Ford', 'Ford', 'Ford', 'BMW', 'BMW', 'BMW', Mercedes', 'Mercedes', 'Mercedes'],
'Score':['88.6', '76.6', '100', '79.1', '86.8', '96.4', '97.3', '98.7', '98.5'],
'Dimension':['Speed', 'MPG', 'Styling', 'Speed', 'MPG', 'Styling', 'Speed', 'MPG', 'Styling'],
'Month':['Apr-19', 'Apr-19', 'Apr-19', 'Apr-19', 'Apr-19', 'Apr-19', 'Apr-19', 'Apr-19', 'Apr-19']})
My code is as follows:
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 plotly.graph_objects as go
import dash_table
import pandas as pd
app = dash.Dash()
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'),
])
def parse_contents(contents, filename, date):
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([
html.H5(filename),
html.H6(datetime.datetime.fromtimestamp(date)),
dash_table.DataTable(
data=df.to_dict('records'),
columns=[{'name': i, 'id': i} for i in df.columns]
),
html.Hr(), # horizontal line
#### How to get the x and y values DYNAMICALLY from the data frame to pass into the Bar() function? ####
dcc.Graph(
figure = go.Figure(data=[
go.Bar(name=df.columns.values[0], x=pd.unique(df['Make']), y=[88.6, 76.6, 100], text=[88.6, 76.6, 100], textposition='auto'),
go.Bar(name=df.columns.values[1], x=pd.unique(df['Make']), y=[92.5, 93.6, 93.4], text=[92.5, 93.6, 93.4], textposition='auto'),
go.Bar(name=df.columns.values[2], x=pd.unique(df['Make']), y=[99.1, 99.2, 95.9], text=[99.1, 99.2, 95.9], textposition='auto'),
])
),
html.Hr(),
# For debugging, display the raw contents provided by the web browser
html.Div('Raw Content'),
html.Pre(contents[0:200] + '...', style={
'whiteSpace': 'pre-wrap',
'wordBreak': 'break-all'
})
])
#app.callback(Output('output-data-upload', 'children'),
[Input('upload-data', 'contents')],
[State('upload-data', 'filename'),
State('upload-data', 'last_modified')])
def update_output(list_of_contents, list_of_names, list_of_dates):
if list_of_contents is not None:
children = [
parse_contents(c, n, d) for c, n, d in
zip(list_of_contents, list_of_names, list_of_dates)]
return children
if __name__ == '__main__':
app.run_server(debug=True)
I'm able to upload and view the contents of the CSV file.
However, the go.Bar() function has its x and y values 'hard-coded' in. They're not necessarily DYNAMIC (i.e. if the number of x variables changes, etc.).
How do I get Dash to build the bar plot based on the data in the CSV file that's uploaded using the parse_contents(contents, filename, date) function?
I tried to follow along in Using dash upload component to upload csv file and generate a graph, but was unable to implement that example successfully.
Thanks in advance for helping a newbie get this toy example working!
Here is the answer:
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 plotly.express as px
import plotly.graph_objects as go
import dash_table
import pandas as pd
app = dash.Dash()
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'),
])
def parse_contents(contents, filename, date):
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([
dcc.Graph(
figure = go.Figure(data=[
go.Bar(name=df.columns.values[0], x=pd.unique(df['Make']), y=df['Score'], text=df['Score'], textposition='auto'),
])
),
])
#app.callback(Output('output-data-upload', 'children'),
[Input('upload-data', 'contents')],
[State('upload-data', 'filename'),
State('upload-data', 'last_modified')])
def update_output(list_of_contents, list_of_names, list_of_dates):
if list_of_contents is not None:
children = [
parse_contents(c, n, d) for c, n, d in
zip(list_of_contents, list_of_names, list_of_dates)]
return children
if __name__ == '__main__':
app.run_server(debug=True)
I am trying to render a graph using columns of an uploaded csv. The first callback is running but when I add the second callback the browser page says "Error loading dependencies". None of the consoles are generating any error. Can someone point out the flaw in my code or simply suggest a way to generate a graph using dropdown?
I have tried returning just the "options" to the dropdown, instead of the whole dropdown to the div. But it hasn't worked for me either. I have tried running on other browsers as well
import dash
import dash_table
import pandas as pd
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State
import numpy as np
import plotly
import plotly.graph_objs as go
import base64
import io
app = dash.Dash(__name__)
app.scripts.config.serve_locally = True
app.config['suppress_callback_exceptions'] = True
app.layout = html.Div([html.Div([
html.H5("Upload Files"),
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'
},
multiple=False)
]),
html.Div(id = 'output-table'),
html.Div(id = 'x-value', style = {'width' : '48%' , 'display' : 'inline-block'}),
html.Div(id = 'y-value', style = {'width' : '48%' , 'display' : 'inline-block'}),
html.Div(dcc.Graph(id = "first_graph",
config={
'displaylogo': False,
}))
] , style = {"padding" : 10})
def parse_contents(contents, filename):
content_type, content_string = contents.split(',')
decoded = base64.b64decode(content_string)
try:
if 'csv' in filename:
df = pd.read_csv(
io.StringIO(decoded.decode('utf-8')))
elif 'xls' in filename:
df = pd.read_excel(io.BytesIO(decoded))
except Exception as e:
print(e)
return None
return df
#app.callback([Output('output-table', 'children'),
Output('x-value', 'children'),
Output('y-value', 'children')],
[Input('upload-data', 'contents'),
Input('upload-data', 'filename')])
def update_columns(contents, filename):
if contents is not None:
df = parse_contents(contents, filename)
if df is not None:
head = df.head()
return html.Div([
html.Div(id='datatable-output'),
dash_table.DataTable(
id='datatable',
columns =[{"name": i, "id": i} for i in df.columns],
data = head.to_dict("rows")
)
]), [dcc.Dropdown(
id = 'xaxis',
options = [{'label':i , 'value':i} for i in df.columns],
#value ='my_x',
placeholder = 'Select X-axis value'
)] , [dcc.Dropdown(
id = 'yaxis',
options = [{'label':i , 'value':i} for i in df.columns],
#value = 'my_y',
placeholder = 'Select Y-axis value'
)]
else:
return 'Cannot load the file','',''
else:
return '', '', ''
#app.callback(Output('first_graph', 'figure'),
[Input('xaxis' , 'value'),
Input('yaxis' , 'value'),
Input('upload-data', 'contents'),
Input('upload-data', 'filename')])
def update_graph(my_x , my_y,contents,filename):
if contents is not None:
df = parse_contents(contents, filename)
if df is not None:
if (my_x is not None) and (my_y is not None):
return {'data': [go.Scatter( x = df[my_x],
y = df[my_y],
mode = " lines + markers",
marker = dict(size = 15,
color = "rgb(54,321,123)",
symbol = "circle",
line = dict(width = 2)
)
)],
'layout': go.Layout(title = 'Dashboard',
xaxis = {'title' : my_x},
yaxis = {'title' : my_y},
hovermode = "closest"
)
}
else:
return {}
else:
return {}
I am attempting to create something simple with Dash by looking at the uploads tutorial but with the exection of graphing the data versus creating a table.
Would anyone have any tips with the error I am running into with parsing the data?
File "C:\Users\benb\Desktop\dash\hwsLineUpload.py", line 105, in update_graph
df = parse_contents(contents, filename)
File "C:\Users\benb\Desktop\dash\hwsLineUpload.py", line 52, in parse_contents
content_type, content_string = contents.split(',')
ValueError: not enough values to unpack (expected 2, got 1)
This is the complete script, I know I have something wrong in the def parse_contents(contents, filename): function.. Any tips help, not a lot of wisdom here.
import base64
import datetime
import io
import cufflinks as cf
import plotly.graph_objs as go
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
import pandas as pd
import numpy as np
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
colors = {
"graphBackground": "#F5F5F5",
"background": "#ffffff",
"text": "#000000"
}
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'
},
# Not multiple files to be uploaded
multiple=False
),
dcc.Graph(id='myGraph')
])
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')))
if df.empty:
df = df.fillna(method = 'ffill').fillna(method = 'bfill')
if df.isnull().values.any():
df = df.fillna(method = 'ffill').fillna(method = 'bfill')
elif 'xls' in filename:
# Assume that the user uploaded an excel file
df = pd.read_excel(io.BytesIO(decoded))
if df.empty:
df = df.fillna(method = 'ffill').fillna(method = 'bfill')
if df.isnull().values.any():
df = df.fillna(method = 'ffill').fillna(method = 'bfill')
except Exception as e:
print(e)
return html.Div([
'There was an error processing this file.'
])
return df
#app.callback(Output('myGraph', 'figure'),
[
Input('upload-data', 'contents'),
Input('upload-data', 'filename')
])
def update_graph(contents, filename):
fig = {
'layout': go.Layout(
plot_bgcolor=colors["graphBackground"],
paper_bgcolor=colors["graphBackground"])
}
if contents:
contents = contents[0]
filename = filename[0]
df = parse_contents(contents, filename)
df = df.set_index(df.columns[0])
fig['data'] = df.iplot(asFigure=True, kind='scatter', mode='lines+markers', size=1)
return fig
if __name__ == '__main__':
app.run_server(debug=True)
The file I am testing this with a csv file I have in this git repo, boilerData.csv
Parse_contents use a delimiter which is here by default , the coma
When splitting the content itself it can't be assigned to 2 variables because there is only one value to assign. Try again with content_string = parse_contents(x,y)