✊🏿 Black Lives Matter. Please consider donating to Black Girls Code today.
⚡️ Concerned about the grid? Kyle Baranko teaches how to predicting peak loads using XGBoost. Register for the August webinar!

Dynamic layout with multi page app

Hello everybody,

I’m trying to build a multipage app, where each app can have a dynamic layout, but multipage apps (per https://dash.plotly.com/urls) don’t seem to be compatible with the approach suggested to use dynamic layout (the Updates on page load section of the docs at https://dash.plotly.com/live-updates).

Does anybody have any good suggestions for how to combine the two approaches so that I can have a multipage app whose individual page layouts are dynamic?

The top layer app layout looks like this (in index.py):

app.layout = html.Div([
    html.Div(
        [
            dcc.Location(id='url', refresh=False),
        ],
        id="toc"
    ),
    html.Div(id='page-content'),
])

my callback (in index.py) looks like:

app.callback(Output('page-content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/apps/cumulative_pnl':
        return cumulative_pnl.layout
    elif pathname == '/apps/cumulative_pnl_bookmarks':
        return cumulative_pnl_bookmarks.layout
    else:
        return toc_layout

Inside of my cumulative_pnl.py module, I have a function called return_layout that returns the layout that I want to use (simplified here) and then I assign it to layout (cumulate_pnl.layout)

return_layout():
     return html.Div(
                     [
                                 dcc.Input(
                                    id='start_date',
                                    placeholder='YYYY/MM/DD',
                                    type='text',
                                    value=datetime.date.today().strftime('%Y/%m/%d'),
                                    debounce=True,
                                ),
                                'end_date',
                                dcc.Input(
                                    id='end_date',
                                    placeholder='YYYY/MM/DD',
                                    type='text',
                                    value=datetime.date.today().strftime('%Y/%m/%d'),
                                    debounce=True,
                                ),
                    ],
             )

layout = return_layout

but I get the following exception:

Exception on /_dash-update-component [POST]
Traceback (most recent call last):
  File "/home/mhale/.virtualenvs/dash_release/lib/python2.7/site-packages/flask/app.py", line 2446, in wsgi_app
    response = self.full_dispatch_request()
  File "/home/mhale/.virtualenvs/dash_release/lib/python2.7/site-packages/flask/app.py", line 1951, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/home/mhale/.virtualenvs/dash_release/lib/python2.7/site-packages/flask/app.py", line 1820, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/home/mhale/.virtualenvs/dash_release/lib/python2.7/site-packages/flask/app.py", line 1949, in full_dispatch_request
    rv = self.dispatch_request()
  File "/home/mhale/.virtualenvs/dash_release/lib/python2.7/site-packages/flask/app.py", line 1935, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/home/mhale/.virtualenvs/dash_release/lib/python2.7/site-packages/dash/dash.py", line 1032, in dispatch
    response.set_data(func(*args, outputs_list=outputs_list))
  File "/home/mhale/.virtualenvs/dash_release/lib/python2.7/site-packages/dash/dash.py", line 1002, in add_context
    _validate.fail_callback_output(output_value, output)
  File "/home/mhale/.virtualenvs/dash_release/lib/python2.7/site-packages/dash/_validate.py", line 251, in fail_callback_output
    _validate_value(val, index=i)
  File "/home/mhale/.virtualenvs/dash_release/lib/python2.7/site-packages/dash/_validate.py", line 246, in _validate_value
    toplevel=True,
  File "/home/mhale/.virtualenvs/dash_release/lib/python2.7/site-packages/dash/_validate.py", line 200, in _raise_invalid
    bad_val=bad_val,
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 return_layout at 0x7f64c3396c08>`

In general, Dash properties can only be
dash components, strings, dictionaries, numbers, None,
or lists of those.
10.4.150.20 - - [21/Jul/2020 15:13:10] "POST /_dash-update-component HTTP/1.1" 500 -

I’ll note that if in

app.callback(Output('page-content', 'children'),
              [Input('url', 'pathname')])
def display_page(pathname):
    if pathname == '/apps/cumulative_pnl':
        return cumulative_pnl.layout
    elif pathname == '/apps/cumulative_pnl_bookmarks':
        return cumulative_pnl_bookmarks.layout
    else:
        return toc_layout

For the pathname == ‘/apps/cumulative_pnl’ conditional, I return cumulative_pnl.return_layout() instead, it seems to work ok, even though the docs say to use the function object itself rather than call the function?

I have concerns that I’m doing something wrong here since the documentation seems to warn against calling the function vs defining layout as the function object itself

1 Like