✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
🧬 Learn how to build RNA-Seq data apps with Python & Dash. Register for the May 20 Webinar!

Bug with dynamic slider range

Hi,

I have been trying to make a slider with a dynamic range that is modified via a date picker dropdown in conjunction with intermediate filtered data. There is a very strange glitch that happens when I do it.

I use a date picker dropdown to select the date range, which then filters through a dataset to make a filtered intermediate data set which is stored in an html div. The updated div is then used as an input to a callback to modify the max range of the slider.

When the page initiates, I can move the slider along the full range (0-98)
When I change the upper end of the date, the slider then has a lower max value.
However, when I change the lower end of the date, the section of the slider up till the new start date becomes inactive (whereas the starting point should still be 0.

Please see this video as an example:

I show how it can go to through the full range. I show how when the upper end of the date is changed, it works as expected, and then I show how when the bottom range of the date is changed, it bugs out.

ezgif-5-9388e33d75b9

I made a very simplified example code, and also hosted the page to show the issue:

http://sliderbug.us-west-2.elasticbeanstalk.com

and here is the code:

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

app = dash.Dash()
application = app.server

# list of 100 consecutive dates by day
idx_range = [i for i in range(100)]
full_range_dates = pd.DataFrame(pd.date_range(datetime(2017, 5, 1), periods=100, freq='D'), index=idx_range, columns=['date'])

data = {'idx':idx_range, 'date':full_range_dates}

app.layout = html.Div([

    # Div holder for filtered data
    html.Div(id='intermediate-data', style={'display': 'none'}),

    # dateRange picker
    html.Div([
        html.H3('Date Range:', style={'display': 'inline-block', 'marginRight': '10px'}),

        dcc.DatePickerRange(
            id='date-picker',
            min_date_allowed=datetime(2017, 5, 1),
            max_date_allowed=datetime(2017, 8, 10),
            start_date=datetime(2017, 5, 1),
            end_date=datetime(2017, 8, 10)
        )
    ], style={'display': 'inline-block'}),

    # slider
    dcc.Slider(
        id='slider',
        min=0,
        max=100,
        step=1,
        updatemode='drag',
        value=50,
    ),

    # Chosen slider value
    html.H4(id='output-slider-value', style={'fontSize': 24, 'display': 'inline-block', 'margin-top': '25px'})

],style={'width': '80%', 'margin-left': 'auto',
              'margin-right': 'auto','textAlign': 'center'})


# functions

@app.callback(Output('intermediate-data', 'children'),
              [Input('date-picker', 'start_date'),
               Input('date-picker', 'end_date')])
def filter_data(startdate, enddate):
    filtered_dates = full_range_dates[(full_range_dates['date'] > startdate) & (full_range_dates['date'] < enddate)]
    return filtered_dates.to_json(orient='split')


# Show Value selected by slider
@app.callback(Output('output-slider-value', 'children'),
              [Input('intermediate-data', 'children'),
               Input('slider', 'value')])
def SliderText(df, idx):
    filtered_dates = pd.read_json(df, orient='split')
    date = (filtered_dates['date'].loc[idx+1]).strftime('%Y-%m-%d %H:%M')
    return '{} which is idx {}'.format(date, idx)


# change slider range based on size of filtered data array

@app.callback(Output('slider', 'max'),
              [Input('intermediate-data', 'children')])
def update_slider(df):
    filtered_dates = pd.read_json(df, orient='split')  # , date_format='iso'
    maxval = filtered_dates.shape[0] - 1
    return maxval


if __name__ == '__main__':
    application.run(debug=True, port=8080)

Am I doing some sort of no no? Is there a better way to go about this? The ability to use a dynamic range slider is a very useful tool for users filtering through long datasets.

By the way, I also experienced this issue when passing back the range slider through a callback into a placeholder div and setting app.config.supress_callback_exceptions = True

Thanks in advance,
Troy