Mahdi Jafari
Mahdi Jafari

Reputation: 415

Dash Plotly: How to filter Data Frame by date with DatePickerRange?

I use Dash Plotly for data visualization. I already have the data frame and chart which displays the correct data. Now I want to filter data and update the chart when the user filters data using the date picker.

Here is my code:

df = pd.read_csv('Sample_Data2.csv')
df["date_x"] = pd.to_datetime(df["date_x"]).dt.date

dfp = (
        df.groupby([df["date_x"], df["Categories of event"]])
        .size()
        .unstack("Categories of event", 0)
        .assign(Events=lambda d: d.sum(axis=1))
    )

graph = px.line(dfp, markers=True).update_layout(
    xaxis={'dtick': 'D'},
)

Graph layout:

html.Div(className='graph', children=[
            dcc.Graph(
                id='graph',
                figure=graph,
                responsive=True,
                animate=True,
            )
        ]),

Datepicker component:

html.Div(children=[
            dcc.DatePickerRange(
                id='date_filter',
                start_date=df['date_x'].min(),
                end_date=df['date_x'].max(),
                min_date_allowed=df['date_x'].min(),
                max_date_allowed=df['date_x'].max(),
            ),
        ]),

Callback:

@app.callback(
    Output('graph', 'figure'),
    Input('date_filter', 'start_date'),
    Input('date_filter', 'end_date'),
    prevent_initial_call=True,
)
def update_graph(start_date, end_date):
    min_date = df['date_x'].min()
    min_date = start_date

    max_date = df['date_x'].max()
    max_date = end_date
    df_date = pd.date_range(min_date, max_date, freq='D')
    
    dfp = (
        df.groupby([df_date, df["Categories of event"]])
        .size()
        .unstack("Categories of event", 0)
        .assign(Events=lambda d: d.sum(axis=1))
    )


    graph = px.line(dfp, markers=True).update_layout(
        xaxis={'dtick': 'D'},
    )

    return graph

The data frame grabs the date_x column and displays the chart, but I couldn't do it with a date picker that generates min_date and max_date.

update:

Forgot to provide data:

id  date_x  Agency  Relevance_x Human_Validation    Event   Categories of event start date  end date    Duration    Issue   Local-National  Location_Category   Location_Province   Oganizer_type   CivilSocietySector  MainPoliticalSector CS_Location_Category    CS_Location_Province    size_of_participants    Arena_type  Arena_Province
45803   1/1/2018 7:19   ILNA    Yes 1   Protest Violent protests    12/29/2017  12/29/2017  1   Economic    National    Town    Khuzestan   Unknown None    Neutral National    NONE    unknown Streets Khuzestan
45817   1/1/2018 7:46   ILNA    Yes 1   Protest Confrontational protests (illegal and non violent)          1   Labour  Local   City    Azerbaijan, East    Workers Labour  Neutral Province Center Azerbaijan, East    medium group <50    Working places  Azerbaijan, East
45531   1/1/2018 18:17  ILNA    Yes 1   Protest Violent protests            1   Economic    National    City    Isfahan Unknown None    Neutral National    NONE    unknown Streets Isfahan
45529   1/1/2018 18:23  ILNA    Yes 1   Protest Violent protests            1   Economic    National    Province Center Markazi Unknown None    Neutral National    NONE    unknown Streets Markazi
45448   1/2/2018 6:36   ILNA    Yes 1   Protest Violent protests            1   Economic    National    Province Center Kurdistan   Unknown None    Neutral National    NONE    unknown Streets Kurdistan
45299   1/2/2018 10:05  ILNA    Yes 1   Protest Confrontational protests (illegal and non violent)          1   Economic    National    Capital Tehran  Unknown Student Movement    Neutral Capital Tehran  unknown University campuses Tehran
45029   1/3/2018 6:43   ILNA    Yes 1   Protest Violent protests            1   Economic    National    Town    Kermanshah  Unknown None    Neutral National    NONE    unknown Streets Kermanshah
44950   1/3/2018 8:49   ILNA    Yes 1   Protest Demonstrative protests (legal and nonviolent)           1   Political   National    Province Center Bushehr GONGO   Progovernment   Conservative    National    Bushehr unknown Streets Bushehr
44935   1/3/2018 9:22   ILNA    Yes 1   Protest Demonstrative protests (legal and nonviolent)           1   Political   National    Province Center Khuzestan   GONGO   Progovernment   Conservative    National    Khuzestan   unknown Streets Khuzestan
44935   1/3/2018 9:22   ILNA    Yes 1   Protest Demonstrative protests (legal and nonviolent)           1   Political   National    City    Khuzestan   GONGO   Progovernment   Conservative    National    Khuzestan   unknown Streets Khuzestan
44935   1/5/2018 9:22   ILNA    Yes 1   Protest Demonstrative protests (legal and nonviolent)           1   Political   National    City    Khuzestan   GONGO   Progovernment   Conservative    National    Khuzestan   unknown Streets Khuzestan

Upvotes: 0

Views: 3896

Answers (1)

Rob Raymond
Rob Raymond

Reputation: 31236

  • you have not provided sample data so I have synthesized some
  • in callback it's as simple as filtering the dataframe with start_date and end_date
import pandas as pd
import numpy as np
import dash
import plotly.express as px
from dash.dependencies import Input, Output, State
from jupyter_dash import JupyterDash

# generate some sample data...
df = pd.DataFrame(
    {
        "date_x": pd.date_range("1-jan-2021", periods=200),
        "y": np.linspace(30, 50, 200) * np.random.uniform(0.95, 1.05, 200),
    }
)

app = JupyterDash(__name__)
app.layout = dash.html.Div(
    [
        dash.dcc.DatePickerRange(
            id="date_filter",
            start_date=df["date_x"].min(),
            end_date=df["date_x"].max(),
            min_date_allowed=df["date_x"].min(),
            max_date_allowed=df["date_x"].max(),
        ),
        dash.dcc.Graph(id="graph"),
    ]
)


@app.callback(
    Output("graph", "figure"),
    Input("date_filter", "start_date"),
    Input("date_filter", "end_date"),
)
def updateGraph(start_date, end_date):
    if not start_date or not end_date:
        raise dash.exceptions.PreventUpdate
    else:
        return px.line(
            df.loc[
                df["date_x"].between(
                    pd.to_datetime(start_date), pd.to_datetime(end_date)
                )
            ],
            x="date_x",
            y="y",
        )


# Run app and display result inline in the notebook
app.run_server(mode="inline")

Upvotes: 3

Related Questions