dcc.Interval for multipage apps

I would like to pull in updated data every-time a user refreshes a page, However I have so many pages. Do I have to change all the pages individually or is there a way to just add one dcc.interval to main app.py file? :slight_smile:

Hey Chris @chriddyp, I know you’ve written a bit on dcc.interval integration, I was wondering if you have come across anything like this before as I can’t find anything on it in the documentation etc? Thank you!

Hello @SHRees,

For the pages and creating dynamically loaded content, you should check this out:

The key is to make your pages layout a function, this will cause it to be loaded dynamically every time a user reloads the page.

Or, are you referring to a singular data store that gets used in all pages that you would like to refresh when the user refreshes the app?

2 Likes

Hi there,

Thank so much for your reply. I have read this documentation, my page layout in the app.py file is already in a function form but it does not seem to be reloading the latest data with every refresh of the browser?


dash_app = Dash(__name__, server=app, use_pages=True, external_stylesheets=[dbc.themes.LUX])

# use this in your production environment since you will otherwise run into problems
# https://flask-dance.readthedocs.io/en/v0.9.0/proxies.html#proxies-and-https
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)

for view_func in app.view_functions:
    if not view_func.startswith("azure"):
        app.view_functions[view_func] = login_required(app.view_functions[view_func])


def serve_layout():
    return DashApp.serve_layout(get_name(), get_roles())

dash_app.layout = serve_layout

if __name__ == '__main__':
    dash_app.run_server(port=8151, debug=True)

For a function to reload the data, the place where the data is updated must be updated in the layout function.

So, perhaps something like this:

dash_app = Dash(__name__, server=app, use_pages=True, external_stylesheets=[dbc.themes.LUX])

# use this in your production environment since you will otherwise run into problems
# https://flask-dance.readthedocs.io/en/v0.9.0/proxies.html#proxies-and-https
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)

def reloadData():
    for view_func in app.view_functions:
        if not view_func.startswith("azure"):
            app.view_functions[view_func] = login_required(app.view_functions[view_func])


def serve_layout():
    reloadData()
    return DashApp.serve_layout(get_name(), get_roles())

dash_app.layout = serve_layout

if __name__ == '__main__':
    dash_app.run_server(port=8151, debug=True)
1 Like

Thank you for having a look! All pages pull in different ticker values from a large central SQL database. An extremely simplified version of a page would looks something like this:

#get data from SQL
#this changes for every single page depending which table and column is required from the SQL database
minute_data = utils.load_sql_data("SELECT * FROM [dbo].[frequent_testing]")
#figure
fig = go.Figure()
chart_creator(minute_data, fig, 'Live updating', "Number", "Time")
#layout
def layout():
         
         return  dbc.Col(dcc.Graph(figure=fig), style=FIT_SIDEBAR),

so once app.py is run, it obviously runs the page and thus loads the latest data for each page, but not when refreshing. I can add a dcc.interval callback to the page which works, but this is not feasible to add to every single page at this point (as there are so many and they get quite complicated). Along your lines would it work to put the “load_sql_data” function in the app.py file?


def load_sql_data(query):
    """
    very simple function for accessing sql data 
    - gets data
    - drops duplicates
    - example query (string): SELECT TOP(1000) [date] 
                   ,[ukcon_total_activity]
                  ,[ukcon_housing_activity]
                  ,[ukcon_commercial_activity]
                  ,[ukcon_civil_engineering_activity]
                  ,[ukcon_new_orders] 
          
                    FROM [dbo].[pmi_workspace]
    Parameters
    ----------
    query : str
        your sqlquary.

    Returns
    -------
    dataframe with dropped duplicates sorted by date

    """
    server = 'azuresynapse.net,1667' 
    database = 'gold_curated' 
    username = str(os.getenv("####"))
    password = str(os.getenv("####"))
     
    connection_string = 'DRIVER=####)
    
    engine = create_engine(connection_url)
    
    df = pd.read_sql_query(sql=text(query), con=engine.connect())
    
    return df

Nope.

You’d put your data query inside each pages layout function and return the data inside of it.

Can you give just one page’s layout?

1 Like

Ofcourse, thank you :grinning:

import dash
from dash import Dash, dcc, html, Input, Output, callback
import dash_bootstrap_components as dbc
import datetime
import plotly.graph_objects as go
import pandas as pd
import urllib.request
import json
import plotly.io as pio
pio.renderers.default = "browser"
from itertools import cycle
import pages.Utilities as utils
from style import *



#
from .sidebar_fx import fx_sidebar

dash.register_page(__name__, name = "Sterling")

####################################################################
#Commentary and caveats added here
####################################################################
#To be updated by data owners
TEXT ='''
              ### Source:
           

              ### Further information
              * ERI = exchange rate index
              * Consectetur adipiscing elit


              ### Caveats
              * Fabricati diem, punc
              '''

#############################################################

columns = utils.load_sql_data("SELECT [date],[GBPUSD_BGN_Curncy], [GBPEUR_Curncy], [USDEUR_Curncy] FROM [dbo].[bloomberg_daily_v3]").dropna()


pound_dollar = columns[['date','GBPUSD_BGN_Curncy']].set_index('date')
pound_euro = columns[['date','GBPEUR_Curncy']].set_index('date')
dollar_euro = columns[['date','USDEUR_Curncy']].set_index('date')


def chart_creator(df, fig, title, xtitle, ytitle):
    PALETTE = cycle(PALETTE_FOUR_COLOURS)
    for ticker in df.columns:
        fig.add_trace(
            go.Scatter(
                name=f"{ticker}",
                x=df.index,
                y=df[ticker],
                mode="lines",
                marker_color=next(PALETTE),
            )
        )
        fig.update_layout(
            template="plotly_white",
            showlegend=True,
            legend=dict(title_font_family="Courier New", font=dict(size=7)),
            title=title,
            title_font_color="#C00000",
            xaxis_title=xtitle,
            yaxis_title=ytitle
        )

pound_dollar_fig = go.Figure()
chart_creator(pound_dollar, pound_dollar_fig, "GBPUSD", "Date", "£/$" )
pound_euro_fig = go.Figure()
chart_creator(pound_euro, pound_euro_fig, "GBPEUR", "Date", "€/£" )
dollar_euro_fig = go.Figure()
chart_creator(dollar_euro, dollar_euro_fig, "USDEUR", "Date", "€/$" )

#pound_dollar_fig.show()
# pound_euro_fig.show()
# dollar_euro_fig.show()


arrow = go.Figure(
    go.Indicator(
        mode="delta",
        value=90,
        delta={"reference": 100, "relative": True},
    )
)

arrow2 = go.Figure(
    go.Indicator(
        mode="delta",
        value=120,
        delta={"reference": 100, "relative": True},
    )
)

arrow.update_layout(
    margin=dict(l=0, r=0, t=0, b=0),
)

arrow2.update_layout(
    margin=dict(l=0, r=0, t=0, b=0),
    paper_bgcolor='rgba(0,0,0,0)',
    plot_bgcolor='rgba(0,0,0,0)'
)

arrow3 = go.Figure(
    go.Indicator(
        mode="delta",
        value=85,
        delta={"reference": 100, "relative": True},
    )
)

arrow3.update_layout(
    margin=dict(l=0, r=0, t=0, b=0),
    paper_bgcolor='rgba(0,0,0,0)',
    plot_bgcolor='rgba(0,0,0,0)'
)

cards = [
    dbc.Card(
        [
            html.H2("Inidcator", className="card-title"),
           #html.H2(f"{2*100:.2f}%", className="card-title"),
            dcc.Graph(figure=arrow, style={"height": 50, "width": 100}),
            html.P("Key statistics 1 description", className="card-text"),
        ],
        body=True,
        color="light",
        ),
    dbc.Card(
        [
            html.H2("Inidcator", className="card-title"),
            #html.H2(f"{5*100:.2f}%", className="card-title"),
            dcc.Graph(figure=arrow2, style={"height": 50, "width": 100}),
            html.P("Key statistics 2", className="card-text"),
        ],
        body=True,
        color="dark",
        inverse=True,
    ),
    dbc.Card(
        [
            html.H2("Inidcator", className="card-title"),
            # html.H2(f"{5*100:.2f}%", className="card-title"),
            dcc.Graph(figure=arrow3, style={"height": 50, "width": 100}),
            html.P("Key statistics 2", className="card-text"),
        ],
        body=True,
        color="primary",
        inverse=True,
    ),
]

cards2 = [
    dbc.Card(
        [
            html.H2(f"{2*100}%", className="card-title"),
            html.P("Key statistics 4", className="card-text"),
        ],
        body=True,
        color="light",
        #style={"width": "14rem"}
    ),
    dbc.Card(
        [
            html.H2(f"{5*100}%", className="card-title"),
            html.P("Key statistics 5", className="card-text"),
        ],
        body=True,
        color="dark",
        inverse=True,
       # style={"width": "14rem"}


    ),
    dbc.Card(
        [
            html.H2("Filler", className="card-title"),
            html.P("Key statistics 6", className="card-text"),
        ],
        body=True,
        color="primary",
        inverse=True,
        #style={"width": "14rem"}
    ),
]

cards3 = [
    dbc.Card(
        [
            html.H2("Summary", className="card-title"),
            html.P("Summary paragraph...", className="card-text"),
        ],
        body=True,
        color="light",
        className="w-100")]


def layout():

    return html.Div(
        [
            dbc.Row(
                [

                    html.Div(
                        [
                            html.Div(

                                style=filterdiv_borderstyling,
                            ),

                            dbc.Col([fx_sidebar()], xs=4, sm=4, md=2, lg=2, xl=2),
                            html.H1('Sterling at time: ' + str(datetime.datetime.now()), style=FIT_SIDEBAR),
                           # html.Hr(style=FIT_SIDEBAR),
                            dcc.Interval('graph-update', interval=45000, n_intervals=0),
                            dbc.Col(cards3, style=FIT_SIDEBAR),
                            dbc.Row([dbc.Col(card) for card in cards], style=FIT_SIDEBAR),
                           #dbc.Col([dbc.Row(card) for card in cards2], style=FIT_SIDEBAR),
                            html.Br(),
                            dcc.Tabs(id="Sterling-tabs-example-graph", value='tab-1-example-graph', children=[
                                dcc.Tab(label='GBPUSD', value='tab-1-example-graph'),
                                dcc.Tab(label='GBPEUR', value='tab-2-example-graph'),
                                dcc.Tab(label='USDEUR', value='tab-3-example-graph')
                                #dcc.Tab(label='RPI', value='tab-3-example-graph'),
                            ], style=FIT_SIDEBAR),
                            html.Div(id='Sterling-tabs-content-example-graph', style=FIT_SIDEBAR),

                            dcc.Markdown(TEXT, style=FIT_SIDEBAR), #adds caveats, further info etc
                        ],
                        style={
                            "background-color": corporate_colors["light-grey"],
                            "box-shadow": "2px 5px 5px 1px rgba(255, 101, 131, .5)",
                        },
                    ),


                ]
            )
        ], style=CONTENT_STYLE
    )

@callback(Output('Sterling-tabs-content-example-graph', 'children'),
              Input('Sterling-tabs-example-graph', 'value'))
def render_content(tab):
    if tab == 'tab-1-example-graph':
        return html.Div([
            html.H3('Sterling'),
                dbc.Row([
                    #dbc.Col([dbc.Row(card) for card in cards2], width=2),
                    dbc.Col(dcc.Graph(figure=pound_dollar_fig))
                    ], style={'margin-left' : '1px'})
        ])
    elif tab == 'tab-2-example-graph':
        return html.Div([
            html.H3('Sterling'),
            dcc.Graph(
                id='graph-2-tabs-dcc',
                figure=pound_euro_fig
            )
        ])
    elif tab == 'tab-3-example-graph':
        return html.Div([
            html.H3('Dollar'),
            dcc.Graph(
                figure=dollar_euro_fig
            )
        ])


Instead of changing each page is there not a way to automatically rerun the app.py file as it does when you first launch the the app, so it reruns every page thus reruns the data importing so the visualisations will be up-to-date?

You really dont want to try to reload all of the data on every page upon reload, the only way to do that would be to have one data source in a dcc.Store, and all your layouts have callbacks to query it from there.

import dash
from dash import Dash, dcc, html, Input, Output, callback
import dash_bootstrap_components as dbc
import datetime
import plotly.graph_objects as go
import pandas as pd
import urllib.request
import json
import plotly.io as pio

pio.renderers.default = "browser"
from itertools import cycle
import pages.Utilities as utils
from style import *

#
from .sidebar_fx import fx_sidebar

dash.register_page(__name__, name="Sterling")

####################################################################
# Commentary and caveats added here
####################################################################
# To be updated by data owners
TEXT = '''
              ### Source:


              ### Further information
              * ERI = exchange rate index
              * Consectetur adipiscing elit


              ### Caveats
              * Fabricati diem, punc
              '''


#############################################################

def chart_creator(df, fig, title, xtitle, ytitle):
    PALETTE = cycle(PALETTE_FOUR_COLOURS)
    for ticker in df.columns:
        fig.add_trace(
            go.Scatter(
                name=f"{ticker}",
                x=df.index,
                y=df[ticker],
                mode="lines",
                marker_color=next(PALETTE),
            )
        )
        fig.update_layout(
            template="plotly_white",
            showlegend=True,
            legend=dict(title_font_family="Courier New", font=dict(size=7)),
            title=title,
            title_font_color="#C00000",
            xaxis_title=xtitle,
            yaxis_title=ytitle
        )

def layout():
    columns = utils.load_sql_data(
        "SELECT [date],[GBPUSD_BGN_Curncy], [GBPEUR_Curncy], [USDEUR_Curncy] FROM [dbo].[bloomberg_daily_v3]").dropna()

    pound_dollar = columns[['date', 'GBPUSD_BGN_Curncy']].set_index('date')
    pound_euro = columns[['date', 'GBPEUR_Curncy']].set_index('date')
    dollar_euro = columns[['date', 'USDEUR_Curncy']].set_index('date')

    arrow = go.Figure(
        go.Indicator(
            mode="delta",
            value=90,
            delta={"reference": 100, "relative": True},
        )
    )

    arrow2 = go.Figure(
        go.Indicator(
            mode="delta",
            value=120,
            delta={"reference": 100, "relative": True},
        )
    )

    arrow.update_layout(
        margin=dict(l=0, r=0, t=0, b=0),
    )

    arrow2.update_layout(
        margin=dict(l=0, r=0, t=0, b=0),
        paper_bgcolor='rgba(0,0,0,0)',
        plot_bgcolor='rgba(0,0,0,0)'
    )

    arrow3 = go.Figure(
        go.Indicator(
            mode="delta",
            value=85,
            delta={"reference": 100, "relative": True},
        )
    )

    arrow3.update_layout(
        margin=dict(l=0, r=0, t=0, b=0),
        paper_bgcolor='rgba(0,0,0,0)',
        plot_bgcolor='rgba(0,0,0,0)'
    )

    cards = [
        dbc.Card(
            [
                html.H2("Inidcator", className="card-title"),
                # html.H2(f"{2*100:.2f}%", className="card-title"),
                dcc.Graph(figure=arrow, style={"height": 50, "width": 100}),
                html.P("Key statistics 1 description", className="card-text"),
            ],
            body=True,
            color="light",
        ),
        dbc.Card(
            [
                html.H2("Inidcator", className="card-title"),
                # html.H2(f"{5*100:.2f}%", className="card-title"),
                dcc.Graph(figure=arrow2, style={"height": 50, "width": 100}),
                html.P("Key statistics 2", className="card-text"),
            ],
            body=True,
            color="dark",
            inverse=True,
        ),
        dbc.Card(
            [
                html.H2("Inidcator", className="card-title"),
                # html.H2(f"{5*100:.2f}%", className="card-title"),
                dcc.Graph(figure=arrow3, style={"height": 50, "width": 100}),
                html.P("Key statistics 2", className="card-text"),
            ],
            body=True,
            color="primary",
            inverse=True,
        ),
    ]

    cards2 = [
        dbc.Card(
            [
                html.H2(f"{2 * 100}%", className="card-title"),
                html.P("Key statistics 4", className="card-text"),
            ],
            body=True,
            color="light",
            # style={"width": "14rem"}
        ),
        dbc.Card(
            [
                html.H2(f"{5 * 100}%", className="card-title"),
                html.P("Key statistics 5", className="card-text"),
            ],
            body=True,
            color="dark",
            inverse=True,
            # style={"width": "14rem"}

        ),
        dbc.Card(
            [
                html.H2("Filler", className="card-title"),
                html.P("Key statistics 6", className="card-text"),
            ],
            body=True,
            color="primary",
            inverse=True,
            # style={"width": "14rem"}
        ),
    ]

    cards3 = [
        dbc.Card(
            [
                html.H2("Summary", className="card-title"),
                html.P("Summary paragraph...", className="card-text"),
            ],
            body=True,
            color="light",
            className="w-100")]
    
    return html.Div(
        [
            dcc.Store(id='data', data={'pound_dollar': pound_dollar.to_dict('records'),
                                       'pound_euro': pound_euro.to_dict('records'),
                                       'dollar_euro': dollar_euro.to_dict('records')}),
            dbc.Row(
                [

                    html.Div(
                        [
                            html.Div(

                                style=filterdiv_borderstyling,
                            ),

                            dbc.Col([fx_sidebar()], xs=4, sm=4, md=2, lg=2, xl=2),
                            html.H1('Sterling at time: ' + str(datetime.datetime.now()), style=FIT_SIDEBAR),
                            # html.Hr(style=FIT_SIDEBAR),
                            dcc.Interval('graph-update', interval=45000, n_intervals=0),
                            dbc.Col(cards3, style=FIT_SIDEBAR),
                            dbc.Row([dbc.Col(card) for card in cards], style=FIT_SIDEBAR),
                            # dbc.Col([dbc.Row(card) for card in cards2], style=FIT_SIDEBAR),
                            html.Br(),
                            dcc.Tabs(id="Sterling-tabs-example-graph", value='tab-1-example-graph', children=[
                                dcc.Tab(label='GBPUSD', value='tab-1-example-graph'),
                                dcc.Tab(label='GBPEUR', value='tab-2-example-graph'),
                                dcc.Tab(label='USDEUR', value='tab-3-example-graph')
                                # dcc.Tab(label='RPI', value='tab-3-example-graph'),
                            ], style=FIT_SIDEBAR),
                            html.Div(id='Sterling-tabs-content-example-graph', style=FIT_SIDEBAR),

                            dcc.Markdown(TEXT, style=FIT_SIDEBAR),  # adds caveats, further info etc
                        ],
                        style={
                            "background-color": corporate_colors["light-grey"],
                            "box-shadow": "2px 5px 5px 1px rgba(255, 101, 131, .5)",
                        },
                    ),

                ]
            )
        ], style=CONTENT_STYLE
    )


@callback(Output('Sterling-tabs-content-example-graph', 'children'),
          Input('Sterling-tabs-example-graph', 'value'),
          Input('data', 'data'))
def render_content(tab, data):
    if tab == 'tab-1-example-graph':
        pound_dollar_fig = go.Figure()
        chart_creator(pd.DataFrame(data['pound_dollar']), pound_dollar_fig, "GBPUSD", "Date", "£/$")
        return html.Div([
            html.H3('Sterling'),
            dbc.Row([
                # dbc.Col([dbc.Row(card) for card in cards2], width=2),
                dbc.Col(dcc.Graph(figure=pound_dollar_fig))
            ], style={'margin-left': '1px'})
        ])
    elif tab == 'tab-2-example-graph':
        pound_euro_fig = go.Figure()
        chart_creator(pd.DataFrame(data['pound_euro']), pound_euro_fig, "GBPEUR", "Date", "€/£")
        return html.Div([
            html.H3('Sterling'),
            dcc.Graph(
                id='graph-2-tabs-dcc',
                figure=pound_euro_fig
            )
        ])
    elif tab == 'tab-3-example-graph':
        dollar_euro_fig = go.Figure()
        chart_creator(pd.DataFrame(data['dollar_euro']), dollar_euro_fig, "USDEUR", "Date", "€/$")
        return html.Div([
            html.H3('Dollar'),
            dcc.Graph(
                figure=dollar_euro_fig
            )
        ])

Give this a try.

I cant really test it.

1 Like

Thanks so much for your help!

1 Like