this is more likely the first time to use Dash board together with plotly and dont have clear understanding how the code works and where the issues come from. It will be appreciated if you give some suggestion. I am trying to import two csv files by using uploading buttons and dropdownbar should show all variable name and once i select multiple variable names from dopdown bar then they should be plotted in the x-y plot.
The code works to import two different csv files and showing variables in dropdownbar, but plotting doesnt work. I think the code is not able to transfer value correct to plotly functions. Can you review the code and where the source of problems are ? Thanks.
import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import plotly.graph_objs as go
from dash.dependencies import Input, Output, State
import base64
import io
import plotly.express as px
import dash_table
external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]
# Initialize the app
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
# Define the layout
app.layout = html.Div([
html.H1('CSV File Comparison Dashboard'),
html.Div([
html.H2('File A'),
dcc.Upload(
id='upload-data-A',
children=html.Div([
'Drag and Drop or ',
html.A('Select Files')
]),
style={
'width': '50%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
multiple=False
),
html.Div(id='file-name_A'),
dcc.Dropdown(
id='variable-dropdown-A',
options=[],
value=[],
multi=True
),
dcc.Graph(
id='graph-A'
)
], style={'width': '49%', 'display': 'inline-block', 'vertical-align': 'top'}),
html.Div([
html.H2('File B'),
dcc.Upload(
id='upload-data-B',
children=html.Div([
'Drag and Drop or ',
html.A('Select Files')
]),
style={
'width': '50%',
'height': '60px',
'lineHeight': '60px',
'borderWidth': '1px',
'borderStyle': 'dashed',
'borderRadius': '5px',
'textAlign': 'center',
'margin': '10px'
},
multiple=False
),
html.Div(id='file-name_B'),
dcc.Dropdown(
id='variable-dropdown-B',
options=[],
value=[],
multi=True
),
dcc.Graph(
id='graph-B'
)
], style={'width': '49%', 'display': 'inline-block', 'vertical-align': 'top'})
])
# Define the callback for updating the variable dropdown menus
@app.callback([Output('variable-dropdown-A', 'options'), Output('variable-dropdown-A', 'value')],
[Input('upload-data-A', 'contents')],
prevent_initial_call=True)
def update_dropdowns_A(list_of_contents_A):
# Initialize empty options for each dropdown
options_A = []
# Check if a csv file has been uploaded for file A
if list_of_contents_A:
# Read the csv file
content_type, content_string = list_of_contents_A.split(',')
decoded = base64.b64decode(content_string)
df_A = pd.read_csv(io.StringIO(decoded.decode('utf-8')))
# Add the column names to the options for file A
options_A = [{"label": col, "value": col} for col in df_A.columns]
return options_A, df_A.columns[0]
else:
# Return the options for both dropdowns
return [], None
@app.callback([Output('variable-dropdown-B', 'options'), Output('variable-dropdown-B', 'value')],
[Input('upload-data-B', 'contents')],
prevent_initial_call=True)
def update_dropdowns_B(list_of_contents_B):
# Initialize empty options for each dropdown
options_B = []
# Check if a csv file has been uploaded for file B
if list_of_contents_B:
# Read the csv file
content_type, content_string = list_of_contents_B.split(',')
decoded = base64.b64decode(content_string)
df_B = pd.read_csv(io.StringIO(decoded.decode('utf-8')))
# Add the column names to the options for file A
options_B = [{"label": col, "value": col} for col in df_B.columns]
return options_B, df_B.columns[0]
else:
# Return the options for both dropdowns
return [], None
# Define the callback for updating the graphs
@app.callback([Output('graph-A', 'figure'), Output('graph-B', 'figure')],
[Input('variable-dropdown-A', 'value'), Input('variable-dropdown-B', 'value')],
[State('upload-data-A', 'contents'), State('upload-data-B', 'contents')],
prevent_initial_call=True)
def update_graphs(variables_A, variables_B, contents_A, contents_B):
if not variables_A or not variables_B:
return {}, {}
# # Initialize empty dataframes for each file
df_A = pd.DataFrame()
df_B = pd.DataFrame()
# # Check if a csv file has been uploaded for file A
# if contents_A is not None:
# # Read the csv file
# content_type, content_string = contents_A.split(',')
# decoded = base64.b64decode(content_string)
# df_A = pd.read_csv(io.StringIO(decoded.decode('utf-8')))
# # Check if a csv file has been uploaded for file B
# if contents_B is not None:
# # Read the csv file
# content_type, content_string = contents_B.split(',')
# decoded = base64.b64decode(content_string)
# df_B = pd.read_csv(io.StringIO(decoded.decode('utf-8')))
# Initialize empty figures for each graph
fig_A = go.Figure()
fig_B = go.Figure()
# Check if any variables have been selected for file A
for var in variables_A:
fig_A.add_trace(go.Scatter(
x=df_A['time'],
y=df_A[var],
mode='lines',
name=var
))
fig_A.update_layout(title='Time Series Plot',
xaxis_title='Time',
yaxis_title='Value')
# Check if any variables have been selected for file B
for var in variables_B:
fig_B.add_trace(go.Scatter(
x=df_B['time'],
y=df_B[var],
mode='lines',
name=var
))
fig_B.update_layout(title='Time Series Plot',
xaxis_title='Time',
yaxis_title='Value')
# Return the figures for both graphs
return fig_A, fig_B
# Update file name
@app.callback(Output('file-name_A', 'children'),
[Input('upload-data-A', 'filename')])
def update_file_name(filename):
if filename is not None:
return html.P(f'File loaded: {filename}')
else:
return html.P('No file loaded')
@app.callback(Output('file-name_B', 'children'),
[Input('upload-data-B', 'filename')])
def update_file_name(filename):
if filename is not None:
return html.P(f'File loaded: {filename}')
else:
return html.P('No file loaded')
# Run the app
if __name__ == '__main__':
app.run_server(debug=True, port = 8000)
Explanation on the issue and furtuer comments on what to do in case if i need to extend the number of plots using subplot functions.