'Dash DatePickerRange with Graph

I am trying to connect a graph to a DatePickerRange. However, i keep running into a problem, when trying to connect the graph and date picker. I have the following code:

import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from datetime import datetime
import plotly.graph_objs as go
import plotly.express as px

controls = dbc.FormGroup(
    [
        html.P('Pick Date', style={
            'textAlign': 'center'
        }),
        dcc.DatePickerRange(
            id = "date-picker",
            start_date = datetime(2021,1,1),
            end_date = datetime.today(),
            display_format='MMMM Y, DD'
        ),

        html.Br(),
        dbc.Button(
            id='submit_button',
            n_clicks=0,
            children='Submit',
            color='primary',
            block=True
        ),
    ]
)

content_second_row = dbc.Row(
    [

        dbc.Col(
            dcc.Graph(id='graph_2'), md=4
        )
    ]
)

@app.callback(
    Output('graph_2', 'figure'),
    [Input('date-picker', 'start_date'),
    Input('date-picker', 'end_date')],
    [State('submit_button', 'n_clicks')])
def update_graph_2(n_clicks, start_date, end_date):
    fig = {
        'data': [{
            'x':  dfEconomic[(dfEconomic['Date']>start_date)&(dfEconomic['Date']<end_date)],
            'y': dfEconomic["Amount [DKK]"],
            'type': 'bar'
        }]
    }

    return fig

I have tried to convert the date values to dateframes, by the use of following code:


for i in range(len(dfEconomic["Date"])):
    if isinstance(dfEconomic["Date"][i], str) == True:
        dfEconomic["Date"] =  datetime.strptime(dfEconomic["Date"][i], "%Y-%m-%d")

But it has not helped the situation. I get the following error message:

TypeError: invalid type comparison

Can anyone help me understand what needs to be changed?

The dataframe looks the following



Solution 1:[1]

This might be useful for those who faces this issue while using dash DatePickerRange with a callback function associated with it.

The dash callback function reads the start and end date of the DatePickerRange component as string. So, you will get an error when slicing the pandas dataframe by comparing the date values in a column with the start and end data values in the DatePickerRange.

Follow these steps to ensure that the date type matches and your callback function works as expected:

  1. Ensure that the datatype of the column you are trying to filter is of the type datetime.date. You can do so by adding this code - dfEconomic['Date'] = pd.to_datetime(dfEconomic['Date']).dt.date

  2. Then convert the data type of the start_date and end_date coming from DatePickerRange in the callback function -

start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d').date() 
end_date = datetime.datetime.strptime(opp_end_date, '%Y-%m-%d').date()

So, the updated callback function should look like this:

import datetime

@app.callback(
    Output('graph_2', 'figure'),
    [Input('date-picker', 'start_date'),
    Input('date-picker', 'end_date')],
    [State('submit_button', 'n_clicks')])
def update_graph_2(n_clicks, start_date, end_date):
    dfEconomic['Date'] = pd.to_datetime(dfEconomic['Date']).dt.date
    start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d').date() 
    end_date = datetime.datetime.strptime(opp_end_date, '%Y-%m-%d').date()
    fig = {
        'data': [{
            'x':  dfEconomic[(dfEconomic['Date']>start_date)&(dfEconomic['Date']<end_date)],
            'y': dfEconomic["Amount [DKK]"],
            'type': 'bar'
        }]
    }

    return fig

Feel free to adjust the format of your datetime object as per the requirement.

Solution 2:[2]

  • simulated dataframe and constructed a dash layout to make your code runnable
  • three core issues
    1. the order of the parameters to callback were wrong. n_clicks is last parameter
    2. used pd.to_datetime() to convert string values to datetime64[ns]. Created a list that can then used as *args to between()
    3. need to filter x and y so used a local variable df
import dash
import dash_bootstrap_components as dbc
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State
from datetime import datetime
import plotly.graph_objs as go
import plotly.express as px
import pandas as pd
import numpy as np
from jupyter_dash import JupyterDash

app = JupyterDash(__name__)

dfEconomic = pd.DataFrame({"Date": pd.date_range("1-jan-2021", "today")}).assign(
    **{"Amount [DKK]": lambda d: np.random.uniform(10, 200, len(d))}
)

controls = dbc.FormGroup(
    [
        html.P("Pick Date", style={"textAlign": "center"}),
        dcc.DatePickerRange(
            id="date-picker",
            start_date=datetime(2021, 1, 1),
            end_date=datetime.today(),
            display_format="MMMM Y, DD",
        ),
        html.Br(),
        dbc.Button(
            id="submit_button",
            n_clicks=0,
            children="Submit",
            color="primary",
            block=True,
        ),
    ]
)

content_second_row = dbc.Row([dbc.Col(dcc.Graph(id="graph_2"), md=4)])

app.layout = html.Div([controls, content_second_row])


@app.callback(
    Output("graph_2", "figure"),
    [Input("date-picker", "start_date"), Input("date-picker", "end_date")],
    [State("submit_button", "n_clicks")],
)
def update_graph_2(start_date, end_date, n_clicks):
    df = dfEconomic.loc[dfEconomic["Date"].between(*pd.to_datetime([start_date, end_date]))]
    fig = {"data": [{"x": df["Date"], "y": df["Amount [DKK]"], "type": "bar"}]}

    return fig


if __name__ == "__main__":
    #     app.run_server(debug=True)
    app.run_server(mode="inline")

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Shivam Solanki
Solution 2 Rob Raymond