Search code examples
pythonplotlyplotly-dash

Plotly Dash: Why is my figure failing to show with a multi dropdown selection?


I am building a simple python dashboard using dash and plotly. I am also new to python (as is probably evident!) and I'm happy for any/all corrections. I would like to plot a time series of data from a pre-determined CSV file. I have added a dropdown selection box with which I would like to allow multiple different columns to be plotted.

Sample data:

"TOA5","HE605_RV50_GAF","CR6","7225","CR6.Std.07","CPU:BiSP5_GAF_v2d.CR6","51755","SensorStats"
"TIMESTAMP","RECORD","BattV_Min","BattV_Avg","PTemp_C_Avg","SensorRel_Min(1)","SensorRel_Min(2)","SensorRel_Min(3)","SensorRel_Min(4)","SensorRel_Min(5)","SensorRel_Max(1)","SensorRel_Max(2)","SensorRel_Max(3)","SensorRel_Max(4)","SensorRel_Max(5)"
"TS","RN","Volts","Volts","Deg C","","","","","","","","","",""
"","","Min","Avg","Avg","Min","Min","Min","Min","Min","Max","Max","Max","Max","Max"
"2019-09-30 11:15:00",0,12.68219,12.74209,"NAN","NAN","NAN","NAN","NAN","NAN","NAN","NAN","NAN","NAN","NAN"
"2019-09-30 11:30:00",1,12.68466,12.73777,31.26331,-2.498894,-2.38887,-8.497528,-2.963989,-20.42339,41.51585,28.41309,88.98283,27.27819,17.98986
"2019-09-30 11:45:00",2,12.69364,12.74584,31.43891,-3.490456,-2.856804,-8.770081,-3.879868,-22.69171,42.27676,30.53723,89.47752,34.25191,23.92586
"2019-09-30 12:00:00",3,12.69078,12.74522,31.38461,-3.290047,-2.973389,-8.69928,-3.295074,-21.88254,42.72508,29.91062,83.36012,27.9931,22.6571
"2019-09-30 12:15:00",4,12.6914,12.74376,31.2449,-2.899231,-2.392128,-10.01413,-2.996033,-23.22171,42.97162,29.20943,106.1204,35.93995,41.74426

My python(3.7) code for this is:

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

import pandas as pd
import plotly.graph_objects as go

# Load external stylesheets
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

# Load external datasets
df = pd.read_csv('../SampleData/test_data.dat', skiprows=3, na_values='NAN')
df.columns=["TIMESTAMP","RECORD","BattV_Min","BattV_Avg","PTemp_C_Avg","SensorRel_Min(1)","SensorRel_Min(2)","SensorRel_Min(3)","SensorRel_Min(4)","SensorRel_Min(5)","SensorRel_Max(1)","SensorRel_Max(2)","SensorRel_Max(3)","SensorRel_Max(4)","SensorRel_Max(5)"]

# define dropdown options
opts=[{'label': k, 'value': k} for k in list(df.columns.values)[1:]]


# create plotly figures
fig2=go.Figure()

# Create a Dash layout
app.layout = html.Div(children=[
    html.H1(children='Testing dashboard v01'),

    html.Div(children='''
        Select variable to plot below.
    '''),

    html.Div(children='''
        Select variables to add to plot below.
    '''),

    dcc.Dropdown(
        id='multiVariableDropdown',
        options=opts,
        value='RECORD',
        multi=True
    ),

    dcc.Graph(
        id='plot2'
    )  
])

# Add callback functions
## For plot 2
@app.callback(Output('plot2', 'figure'),
             [Input('multiVariableDropdown', 'value')])
def update_graph(selectedVariable2):
    trace_finalPlot2 = go.Scatter(
                            x=df['TIMESTAMP'], 
                            y=df[selectedVariable2], 
                            name=str(selectedVariable2))
    fig2 = go.Figure(data=trace_finalPlot2)
    return fig2


if __name__ == '__main__':
    app.run_server(debug=True)

The initial rendering of the plot looks good, as this is what appear after running python3 app.py:

Initial plot

But once I add another column to be plotted from the multi-selection dropdown, the original data disappears and it only plots a single point:

After adding another column of data

Unfortunately, it's not returning any error data so I'm having trouble debugging. Any tips/hints appreciated.


Solution

  • The issue is that the dropdown returns a list of multiple variables (as you set multi=True), while your callback is designed to plot only one variable.

    In order to plot multiple variables, you need to iterate through the selected list of variables (i.e. through selectedVariable2 in your code) and add the respective traces to the figure.

    You should also make sure that the dropdown is initialized with a list rather than a string (i.e. you should replace value="RECORD" with value=["RECORD"].

    I included an example below.

    import pandas as pd
    import dash
    import dash_core_components as dcc
    import dash_html_components as html
    from dash.dependencies import Input, Output
    import plotly.graph_objects as go
    
    # Load external stylesheets
    external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
    app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
    
    # Create a sample dataset
    df = pd.DataFrame({"TIMESTAMP": ["2019-09-30 11:15:00", "2019-09-30 11:30:00", "2019-09-30 11:45:00", "2019-09-30 12:00:00", "2019-09-30 12:15:00"],
                       "RECORD": [0, 1, 2, 3, 4],
                       "SensorRel_Min(2)": [12.68219, 12.68466, 12.69364, 12.69078, 12.6914],
                       "SensorRel_Min(3)": [14.74209, 13.73777, 10.74584, 9.74522, 16.74376]})
    
    # Define dropdown options
    opts = [{'label': k, 'value': k} for k in list(df.columns.values)[1:]]
    
    # Create a Dash layout
    app.layout = html.Div(children=[
    
        html.H1(children='Testing dashboard v01'),
    
        html.Div(children='''
            Select variable to plot below.
        '''),
    
        html.Div(children='''
            Select variables to add to plot below.
        '''),
    
        dcc.Dropdown(
            id='multiVariableDropdown',
            options=opts,
            value=['RECORD'],
            multi=True
        ),
    
        dcc.Graph(
            id='plot2'
        )
    
    ])
    
    # Add callback functions
    ## For plot 2
    @app.callback(Output('plot2', 'figure'),
                 [Input('multiVariableDropdown', 'value')])
    def update_graph(selectedVariable2):
    
        traces = []
    
        for var in selectedVariable2:
    
            traces.append(go.Scatter(x=df['TIMESTAMP'],
                                     y=df[var],
                                     name=var))
    
        fig2 = go.Figure(data=traces)
    
        return fig2
    
    if __name__ == '__main__':
        app.run_server(debug=True)
    

    enter image description here