Learn how to use Dash Bio for next-gen sequencing & quality control. 🧬Register for the Oct 27 webinar.

Page refresh not updating page layout

Hello all,

I am struggling with the idea of updating my dataTables with new rows on page refresh. I also have a dropdown to filter rows of interest according to a column value. I learned how to do that here: https://dash.plotly.com/live-updates. However, the datatables don’t update after wrapping layoutrendering in a function.

I have explored other routes like dcc.Interval with dcc.Store in order to update dataTables, but all hit a dead end since multiple same Outputs aren’t allowed in callbacks (table1 and table2). So I figured a layout refresh would be the most efficient way to go. Live datatable updates aren’t needed in my case, so a page refresh and retriggering get_data would be perfect. Any ideas that I may be missing?

def get_data():
    conn_indicator = psycopg2.connect(
        # creds
    )

    # Stats Tab
    sql1 = "some query"
    metadata_df = pd.read_sql(sql1, con=conn_indicator)

    sql2 = "some query"
    df = pd.read_sql(sql2, con=conn_indicator)

    return metadata_df, df

# Initial load
metadata_df, strat_perf_df, strat_trade_df, positions_df, positions_perf_df = get_data()

def serve_layout():
    metadata_df, df = get_data()
    return html.Div(
        [
            dcc.Tabs(
                [
                    dcc.Tab(
                        label="Stats",
                        children=[
                            html.H5("Metadata Table"),
                            dash_table.DataTable(
                                id="table1",
                                columns=[{"name": i, "id": i} for i in metadata_df.columns],
                                data=metadata_df.to_dict("records"),
                            ),
                            html.H5("Df Stats"),
                            dash_table.DataTable(
                                id="table2",
                                columns=[{"name": i, "id": i} for i in df.columns],
                                data=df.to_dict("records"),
                            ),
                        ],
                    ),
                    dcc.Tab(
                        label="Breakdown",
                        children=[
                            html.P("Breakdown Tab"),
                        ],
                    ),
                ]
            ),
            html.P("Select the Run ID"),
            dcc.Dropdown(
                id="run-id-dropdown", options=[{"label": i, "value": i} for i in df["run_id"].tolist()]
            ),
        ]
    )


layout = serve_layout()


# Updates the datatables under the Stats tab through Run ID
@app.callback(
    [Output("table1", "data"), Output("table2", "data")],
    [Input("run-id-dropdown", "value")],
)
def update_stats(value):

    if dash.callback_context.triggered[0]["prop_id"] == ".":
        return dash.no_update
    table1_df = metadata_df.loc[metadata_df["run_id"] == value]
    table2_df = df.loc[df["run_id"] == value]

    return table1_df.to_dict("records"), table2_df.to_dict("records")

Hey @johnwhite10 welcome to the Dash community :slightly_smiling_face:

I’m not sure if this is causing the problem, but try changing:

layout = serve_layout()

to

layout = serve_layout

This is from the Live Updates | Dash for Python Documentation | Plotly page you mentioned in your post:

Thank you :slight_smile: I have tried that already but I am met with this error:

Callback error updating page-content.children
dash.exceptions.InvalidCallbackReturnValue: The callback for `<Output `page-content.children`>`
returned a value having type `function`
which is not JSON serializable.


The value in question is either the only value returned,
or is in the top level of the returned list,

and has string representation
`<function serve_layout at 0x7fdedc48db90>`

In general, Dash properties can only be
dash components, strings, dictionaries, numbers, None,
or lists of those.

hmm, maybe

app.layout = serve_layout

Hm, the app.layout doesn’t work since this is a child page rendered from:

@app.callback(Output("page-content", "children"), [Input("url", "pathname")])
def display_page(pathname):
    if pathname == "/page1":
        return page1.layout
    elif pathname == "/page2":
        return page2.layout
    else:
        return index_page

Error:

AttributeError: module 'apps.page1' has no attribute 'layout'
dash.exceptions.InvalidCallbackReturnValue: The callback for `<Output `page-content.children`>`
returned a value having type `function`
which is not JSON serializable.


The value in question is either the only value returned,
or is in the top level of the returned list,

and has string representation
`<function serve_layout at 0x7f383e019c20>`

In general, Dash properties can only be
dash components, strings, dictionaries, numbers, None,
or lists of those.

Solved! Ended up using dash_extensions: https://github.com/thedirtyfew/dash-extensions and https://pypi.org/project/dash-extensions/

It seems like their DashProxy instance has built in updates on page reload!