Black Lives Matter. Please consider donating to Black Girls Code today.
Dash HoloViews is now available! Check out the docs.

Help with Range Slider as second Input

Hi,

I am trying to add a range slider to my plot. The plot was fully functional before trying to add a range slider for the years, but after trying to add it, the data is not broadcasting. I would ideally also like to have the range slider at the bottom of the graph (as opposed to above the graph) but I realize this is a second question and will ask it separately if needed. I have written the following code so far:

import os
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_ui as dui
import plotly.graph_objs as go
import pandas as pd

# Read in the data
gaining_ground = pd.read_csv('https://github.com/thedatasleuth/New-York-Congressional-Districts/blob/master/gaining_ground2.csv?raw=True', index_col=0)
gaining_ground = gaining_ground.sort_values(['Year', 'DISTRICT'])

# Get a list of drop down menu items
districts = gaining_ground['DISTRICT'].unique()

# Create the app
app = dash.Dash()
server = app.server

# Populate the layout with HTML and graph components
app.layout = html.Div([
    
    html.H2(children="Gaining Ground: Percentage of Active Voters",
           style={'textAlign': 'center',
#                  'color': layout_colors['text'],
#                  'backgroundColor': layout_colors['background']
                 }),
    html.Div(
        [
            dcc.Dropdown(
                id="DISTRICT",
                options=[{
                    'label': i,
                    'value': i
                } for i in districts],
                value='All Districts'),
            
            dcc.RangeSlider(
                id='range-slider',
                marks={
                    2014: '2014',
                    2015: '2015',
                    2016: '2016',
                    2017: '2017',
                    2018: '2018'
                },
                min=2014,
                max=2018,
                value=[2014, 2018])
            
        ],
        style={'width': '25%',
               'display': 'inline-block'}),
    dcc.Graph(id='graph')
])

@app.callback(
    dash.dependencies.Output('graph', 'figure'),
    [dash.dependencies.Input('DISTRICT', 'value'),
   dash.dependencies.Input('range-slider', 'value')
    ])
def update_graph(Districts):
    if Districts == 'All Districts':
        gaining_ground_plot = gaining_ground.copy()
    else:
        gaining_ground_plot = gaining_ground[gaining_ground['DISTRICT'] == Districts]

    trace1 = go.Scatter(x=gaining_ground_plot['Year'], y=gaining_ground_plot[('DEM')], name='DEM')
                       
    trace2 = go.Scatter(x=gaining_ground_plot['Year'], y=gaining_ground_plot[('REP')], name='REP')
                       
    trace3 = go.Scatter(x=gaining_ground_plot['Year'], y=gaining_ground_plot[('CON')], name='CON')
                       
    trace4 = go.Scatter(x=gaining_ground_plot['Year'], y=gaining_ground_plot[('WOR')], name='WOR')
                     
    trace5 = go.Scatter(x=gaining_ground_plot['Year'], y=gaining_ground_plot[('IND')], name='IND')
                      
    trace6 = go.Scatter(x=gaining_ground_plot['Year'], y=gaining_ground_plot[('GRE')], name='GRE')
                     
    trace7 = go.Scatter(x=gaining_ground_plot['Year'], y=gaining_ground_plot[('WEP')], name='WEP')
                     
    trace8 = go.Scatter(x=gaining_ground_plot['Year'], y=gaining_ground_plot[('REF')], name='REF')
                     
    trace9 = go.Scatter(x=gaining_ground_plot['Year'], y=gaining_ground_plot[('OTH')], name='OTH')
                      
    trace10 = go.Scatter(x=gaining_ground_plot['Year'], y=gaining_ground_plot[('BLANK')], name='BLANK')
                        


    return {
        'data': [trace1, trace2, trace3, trace4, trace5, 
                     trace6, trace7, trace8, trace9, trace10],
        'layout':
        go.Layout(
            title='District {}'.format(Districts))
    }

if __name__ == '__main__':
    app.run_server(port=8050, host='127.0.0.1')

Hi @thedatasleuth

It looks like you have added the rangeslider to the layout and as an input but haven’t referenced it inside your callback. For example,

def update_graph(Districts):

should become:

def update_graph(Districts, dates):

dates will return something like [2014,2018]

Then inside your callback you can filter your dataframe. Something like:

gaining_ground_copy = gaining_ground[(gaining_ground['Year'] > dates[0]) & (gaining_ground['Year'] <= dates[1])]

You can see more examples of rangesliders here https://dash.plot.ly/dash-core-components/rangeslider. To answer the second part, simply move dcc.RangeSlider(...) under dcc.Graph(...) in the layout.

Hi,

Thank you so much for your help and interest - I’m still pretty new to Dash and Python in general so I appreciate the help. One last thing, (hopefully) - I added the dates and the above code to my function like this:

def update_graph(Districts, dates):
    if Districts == 'All Districts':
        gaining_ground_plot = gaining_ground[(gaining_ground['Year'] >= dates[0]) & 
                                     (gaining_ground['Year'] <= dates[1])]
    else:
        gaining_ground_plot = gaining_ground[gaining_ground['DISTRICT'] == Districts]

And now the callback is updating the initial ‘All Districts’ graph, but fails to update when I specify a district using the drop down menu. I realize this is because there is no specification for the date range in the ‘else’ statement, but I’m not sure how to combine the filtering of the Districts with the filtering of the Years. I tried adding the same dates code snippet right after filtering for Districts, but that did not work.
Any further insight would be greatly appreciated.

Also I was able to move the slider below the graph now :slight_smile: