Dash app update in django

Our Aim

We’re creating a time series plot in a Django app using dash/plotly. The data being plotted is read from a pandas dataframe which is first pre-processed written to a file, and then sent to the next page via POST request for the interactive dashboard. On updating the dataframe the new plot should be plotted on the dashboard.

Problem

Even though the data is changed the dashboard doesn’t updates. It still shows the plot for the previous dataframe saved in the file. Until or unless the django server is restarted it doesn’t updates. dcc.interval() doesn’t do the trick, it also requires the server to be restarted even though you can see the dash app reply in the console log plus it removes the zoom in capability for a graph since, it refreshes the plot. The Django version in use is 2.2.9

Anyone who ever came across this? How can this be done?

Edit

In the code below at start we manipulate the dataframe to our adjusted needs, then the dashboad itself has multiple html.div() which in turn each have their own dcc.graph() component which don’t seem to update when the dataframes are updated.
Here’s our code for the dash app:

import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output,State
import plotly.graph_objs as go
from django_plotly_dash import DjangoDash
import pandas as pd
import dash_table 
from datetime import datetime



app = DjangoDash('chalao')
selected_df=pd.read_pickle(r'static/selected_df.pkl')
actual_df=pd.read_pickle(r'static/actual_prediction.pkl')
datatable_df=actual_df
datatable_df.reset_index(inplace=True)
datatable_df['START_DATETIME'] = datatable_df['START_DATETIME'].astype(str)
datatable_df['Transaction'] = datatable_df['Transaction'].round(decimals=-3)
datatable_df['Prediction'] = datatable_df['Prediction'] + 500
datatable_df['Prediction'] = datatable_df['Prediction'].round(decimals=-3)
datatable_df['START_DATETIME'] = datatable_df['START_DATETIME'].map(lambda x: x.lstrip('T00:00:00'))
app.layout = html.Div([
    html.H1('Stock Ticker Dashboard'),
    html.H1('Transaction Dashboard'),
    html.Div([
        html.H3('Select start and end dates:'),
        dcc.DatePickerRange(
            id='my_date_picker2',
            min_date_allowed=selected_df.index.min(),
            max_date_allowed=selected_df.index.max(),
            start_date=selected_df.index.min(),
            end_date=selected_df.index.max()
        )
    ], style={'display':'inline-block'}),
 dcc.Graph(
        id='my_graph2',
        figure={
            'data': [
                {'x': selected_df.index, 'y': selected_df.Transaction,'name':'Transaction'},
            ],
            'layout': go.Layout(title='Actual Transaction Graph')
        }
    ),
    html.Div([
        html.H3('Select start and end dates:'),
        dcc.DatePickerRange(
            id='my_date_picker',
            min_date_allowed=actual_df.index.min(),
            max_date_allowed=actual_df.index.max(),
            start_date=actual_df.index.min(),
            end_date=actual_df.index.max()
        )
    ], style={'display':'inline-block'}),
    dcc.Graph(
        id='my_graph',
        figure={
            'data': [
                {'x': actual_df.index, 'y': actual_df.Transaction,'name':'Transaction'},
                {'x': actual_df.index, 'y': actual_df.Prediction,'name':'Prediction'}
            ],
            'layout': go.Layout(title='Predicted Graph')
        }
    ),

    dash_table.DataTable(
    id='table',
    
    columns=[{"name": i, "id": i} for i in datatable_df.columns],
    data=datatable_df.to_dict('records'),
    sort_action='native',
    filter_action='native',
    export_format='csv',


    style_cell={'textAlign': 'center', 'font-size' : '16px','width': '10px',
        'overflow': 'hidden'
},


    style_data_conditional=[
        {
            'if': {'row_index': 'odd'},
            'backgroundColor': 'rgb(248, 248, 248)'
        }
    ],
    style_header={
        'backgroundColor': 'rgb(230, 230, 230)',
        'fontWeight': 'bold',
        'font-size' : '20px'
    }
    
)

])   
def update_graph(start_date, end_date):
    start = datetime.strptime(start_date[:10], '%Y-%m-%d')
    end = datetime.strptime(end_date[:10], '%Y-%m-%d')
    updated_df=actual_df
    updated_df=updated_df[start:end]
    fig = {
        'data': [
                {'x': updated_df.index, 'y': updated_df.Transaction,'name':'Transaction'},
                {'x': updated_df.index, 'y': updated_df.Prediction,'name':'Prediction'}
            ],
        'layout': {'title': 'Prediction Graph'}
    }
    return fig

@app.callback(
    Output('my_graph2', 'figure'),
    [Input('my_date_picker2', 'start_date'),
    Input('my_date_picker2', 'end_date')]
)    

def update_graph2(start_date, end_date):
    start = datetime.strptime(start_date[:10], '%Y-%m-%d')
    end = datetime.strptime(end_date[:10], '%Y-%m-%d')
    updated_df=selected_df
    updated_df=updated_df[start:end]
    fig = {
        'data': [
                {'x': updated_df.index, 'y': updated_df.Transaction,'name':'Transaction'}
            ],
        'layout': {'title': 'Actual Transaction Graph'}
    }
    return fig

and below is the call to the dash app in our Django html template:

 <div class="container-fluid">
    {% load plotly_dash %}
    <h1>Home Page</h1>
    <div class="{% plotly_class name='chalao' %}" style="height: 100%; width: 100%;">
        {% plotly_app name='chalao' ratio=0.45 %}
    </div>
    <br>
    {{ plot1 | safe }}
</div>

Any guidance and or suggestion is appreciated, thanks.

The data flow is a slightly unclear without seeing the actual code. Is the file written to disk? If yes, have you inspected it to check that the data are updated?

I’m sorry I didn’t attach the code here at first, I though it would make the quesiton look a bit messy , I’ll edit it.

Yes, the file is written to disk, and the file is updated, but we even tried executing a new dataframe on the run to change the graph.

Your code shown above that reads the file and sets up the dataframe is only executed when the file is loaded. You need to make it run whenever you want to update the content of the file, which probably means something along the lines of triggering its execution in a Django view or as part of a Dash callback. It is not clear if you’re already doing this somewhere. Even then, your charts will only update when a callback is triggered from the server, which from the code you’ve posted is only when either of the selected dates is changed. If you want a push notification when something on the server has changed you need something like this Pipe component or to poll with an Interval component.

You should also think about how you are persisting the content of this dataframe between callbacks and other requests. Global variables are rarely, if ever, a good idea. You have all of the power of Django at your disposal, along with its ORM, which permits several approaches to structuring your data flow.

:astonished: Wow, great insights. I’ll surely look into all that. We’ll refactor our code and get back to this if something still doesn’t work.

Yes exactly, but changing the dates still presents us with the old dataframe.

Thank you for your time and judgement. We’ll be switching our work sprint, this is on hold for a week, will get back to this soon.

Coming back to this. @delsim can you please highlight as to how to achieve this using dpd.Pipe.
Although changing the dates should run the @app.callback and refresh the graph,but it doesn’t seem to.

In your code as shown, the pickle files containing the data for the dataframe are read only when the file containing the code is first imported into each process. Later changes to the contents of the pickled files will not be picked up.

You need to replace your global variable with something that is more properly shared between different requests; given your use of Django the obvious route would be to use the ORM. You then need to arrange for updates to the data to be pushed to the server, and then for your app to refresh its display as desired. If you want to use a Pipe component for this latter step then I suggest you take a look at the documentation linked above, along with the example code in the django-plotly-dash repo.

1 Like