Kenneth Lott
Kenneth Lott

Reputation: 59

Show multiple dropdown values at once in Plotly

So I am aware the "multi=True" will allow users to select more than one value from the dropdown box. However, I keep getting an error every time and I believe its due to the number of Y axises on my graph.

The code is below, and the goal is to select more than one things on the graph at once. Right now, my code is set to select to different y values set to the same x axis via two separate graphs (fig1 and fig2).Before, I had one graph with both y axis on it, but could not get the call back to address each one individually.

Any ideas on how to make this happen? Thanks in advance!

###THIS WILL LET ME DROP DOWN BUT TO SEPERATE GRAPHS AND WONT ALLOW ME TO HAVE BOTH DISPLAYED AT THE SAME TIME

import pandas as pd

fig1 = px.line(full_data, x = "Date", y = "Volume")
fig2 = px.line(full_data, x = "Date", y = "Price")

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


# you need to include __name__ in your Dash constructor if
# you plan to use a custom CSS or JavaScript in your Dash apps
app = JupyterDash(__name__)

#---------------------------------------------------------------
app.layout = html.Div([
    html.Div([
        html.Label(['Full Chart']),
        dcc.Dropdown(
            id='my_dropdown',
            options=[
                     {'label': 'Price', 'value': 'Price'},
                     {'label': 'Volume', 'value': 'Volume'},
                     {'label': 'Positive Tweets', 'value': 'Positive Tweets'},
                     {'label': 'Negative Tweets', 'value': 'Negative Tweets'},
                     {'label': 'Neutral Tweets', 'value': 'Neutral Tweets'},
                     {'label': 'Total Number of Tweets', 'value': 'Total Number of Tweets'}
            ],
            value='Price',
            multi=True,
            clearable=False,
            style={"width": "50%"}
        ),
    ]),

    html.Div([
        dcc.Graph(id='the_graph')
    ]),

])

#---------------------------------------------------------------
@app.callback(
    Output(component_id='the_graph', component_property='figure'),
    [Input(component_id='my_dropdown', component_property='value')]
)

def update_graph(my_dropdown):
    if my_dropdown == 'Price':
        return fig1
    if my_dropdown == 'Volume':
        return fig2
etc for rest of the data...

<!-- begin snippet: js hide: false console: true babel: false -->

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

Upvotes: 0

Views: 4168

Answers (2)

Kenneth Lott
Kenneth Lott

Reputation: 59

final code and function, allowed me to use the drop down menu and added the additional y axis as well so multiple values can show properly at once. Thanks to Waleed Malik for the initial code!

import pandas as pd
​
import dash
from dash import dcc
from dash import  html
from dash.dependencies import Input, Output
import plotly.express as px
​
​
# you need to include __name__ in your Dash constructor if
# you plan to use a custom CSS or JavaScript in your Dash apps
app = JupyterDash(__name__)
​
app.layout = html.Div([
    html.Div([
        html.Label(['Full Chart']),
        dcc.Dropdown(
            id='my_dropdown',
            options=[
                     {'label': 'Price', 'value': 'Price'},
                     {'label': 'Volume', 'value': 'Volume'},
                     {'label': 'Positive Tweets', 'value': 'Positive Tweets'},
                     {'label': 'Negative Tweets', 'value': 'Negative Tweets'},
                     {'label': 'Neutral Tweets', 'value': 'Neutral Tweets'},
                     {'label': 'Total Number of Tweets', 'value': 'Total Number of Tweets'}
            ],
            value=['Price'],
            multi=True,
            clearable=False,
            style={"width": "50%"}
        ),
    ]),
​
    html.Div([
        dcc.Graph(id='the_graph')
    ]),
​
])
#---------------------------------------------------------------
​
#---------------------------------------------------------------
@app.callback(
    Output(component_id='the_graph', component_property='figure'),
    [Input(component_id='my_dropdown', component_property='value')]
)
​
def update_graph(my_dropdown):
​
    fig = make_subplots(specs=[[{"secondary_y": True}]])
     
​
    for label in my_dropdown:
        if label == "Volume":
            fig.add_trace(go.Bar(
            x = full_data["Date"],
            y = full_data["Volume"],
            #mode = "lines",
            name = label),
                secondary_y = True
        )
            
        else:
            fig.add_trace(go.Scatter(
            x = full_data["Date"],
            y = full_data[label],
            mode = 'lines',
            name = label,
        ))
    
        
    return fig
​
if __name__ == '__main__':
    app.run_server(debug=True, port = 9001)

enter image description here

Upvotes: 0

Waleed Malik
Waleed Malik

Reputation: 366

First of all, in case of multi-dropdown menu, the value attribute inside the dropdown component should be a list and not a string (as you'll be selecting a list of options).
In order to customize each trace separately, you have to use graph_objects instead of Plotly express. The following code will update the figure with a new trace every time you'll select an option from the dropdown menu.

import pandas as pd
import numpy as np

# fig1 = px.line(full_data, x = "Date", y = "Volume")
# fig2 = px.line(full_data, x = "Date", y = "Price")

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


# you need to include __name__ in your Dash constructor if
# you plan to use a custom CSS or JavaScript in your Dash apps
app = dash.Dash(__name__)


# Creating random DataFrame
columns = ['Price', 'Volume', 'Positive Tweets', 'Negative Tweets', 'Neutral Tweets', 'Total Number of Tweets']
np.random.seed(2019)
N = 10
rng = pd.date_range('2019-01-01', freq='MS', periods=N)
df = pd.DataFrame(np.random.rand(N, 6), columns=columns, index=rng)

#---------------------------------------------------------------
app.layout = html.Div([
    html.Div([
        html.Label(['Full Chart']),
        dcc.Dropdown(
            id='my_dropdown',
            options=[
                     {'label': 'Price', 'value': 'Price'},
                     {'label': 'Volume', 'value': 'Volume'},
                     {'label': 'Positive Tweets', 'value': 'Positive Tweets'},
                     {'label': 'Negative Tweets', 'value': 'Negative Tweets'},
                     {'label': 'Neutral Tweets', 'value': 'Neutral Tweets'},
                     {'label': 'Total Number of Tweets', 'value': 'Total Number of Tweets'}
            ],
            value=['Price'],
            multi=True,
            clearable=False,
            style={"width": "50%"}
        ),
    ]),

    html.Div([
        dcc.Graph(id='the_graph')
    ]),

])

#---------------------------------------------------------------
@app.callback(
    Output(component_id='the_graph', component_property='figure'),
    [Input(component_id='my_dropdown', component_property='value')]
)

def update_graph(my_dropdown):

    fig = go.Figure()

    for label in my_dropdown:
        fig.add_trace(go.Scatter(
            x = df.index,
            y = df[label],
            mode = 'lines',
            name = label
        ))
    return fig

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

The output of the code: Click Here

Upvotes: 2

Related Questions