Following guidelines to structure a multipage dash app here: https://dash.plotly.com/urls
Trying to replicate and adjust following the example in the link, adding one layer on top for execution.
My project directory is as such:
-- wsgi.py
|-- multipageapp
|-- app.py
|-- index.py
|-- Procfile
|-- apps
|-- __init__.py
|-- app1.py
|-- app2.py
It works fine if I go in the multipageapp folder and execute the index.py
file from there. However, I am getting the following error when executing the wsgi.py
file, I am not sure what I am doing wrong, it seems like it match what's in the example:
Traceback (most recent call last):
File "C:\Program Files\Anaconda3_4\lib\site-packages\flask\app.py", line 2464, in __call__
return self.wsgi_app(environ, start_response)
File "C:\Program Files\Anaconda3_4\lib\site-packages\flask\app.py", line 2450, in wsgi_app
response = self.handle_exception(e)
File "C:\Program Files\Anaconda3_4\lib\site-packages\flask\app.py", line 1867, in handle_exception
reraise(exc_type, exc_value, tb)
File "C:\Program Files\Anaconda3_4\lib\site-packages\flask\_compat.py", line 39, in reraise
raise value
File "C:\Program Files\Anaconda3_4\lib\site-packages\flask\app.py", line 2447, in wsgi_app
response = self.full_dispatch_request()
File "C:\Program Files\Anaconda3_4\lib\site-packages\flask\app.py", line 1945, in full_dispatch_request
self.try_trigger_before_first_request_functions()
File "C:\Program Files\Anaconda3_4\lib\site-packages\flask\app.py", line 1993, in try_trigger_before_first_request_functions
func()
File "C:\Program Files\Anaconda3_4\lib\site-packages\dash\dash.py", line 1048, in _setup_server
_validate.validate_layout(self.layout, self._layout_value())
File "C:\Program Files\Anaconda3_4\lib\site-packages\dash\_validate.py", line 334, in validate_layout
"""
dash.exceptions.NoLayoutException: The layout was `None` at the time that
`run_server` was called.
Make sure to set the `layout` attribute of your application
before running the server.
This is the content of wsgi.py
from multipageapp.app import server
if __name__ == "__main__":
server.run(debug=True)
This is the content of Procfile
web: gunicorn index:app.server
This is the content of app.py
import dash
app = dash.Dash(__name__, suppress_callback_exceptions=True)
server = app.server
This is the content of index.py
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from app import app
from apps import app1, app2
app.layout = html.Div([
dcc.Location(id='url', refresh=False),
html.Div(id='page-content')
])
@app.callback(Output('page-content', 'children'),
[Input('url', 'pathname')])
def display_page(pathname):
if pathname == '/apps/app1':
return app1.layout
elif pathname == '/apps/app2':
return app2.layout
else:
return '404'
if __name__ == '__main__':
app.run_server(debug=True)
This is the content of app1.py
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from app import app
layout = html.Div([
html.H3('App 1'),
dcc.Dropdown(
id='app-1-dropdown',
options=[
{'label': 'App 1 - {}'.format(i), 'value': i} for i in [
'NYC', 'MTL', 'LA'
]
]
),
html.Div(id='app-1-display-value'),
dcc.Link('Go to App 2', href='/apps/app2')
])
@app.callback(
Output('app-1-display-value', 'children'),
[Input('app-1-dropdown', 'value')])
def display_value(value):
return 'You have selected "{}"'.format(value)
This is the content of app2.py
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
from app import app
layout = html.Div([
html.H3('App 2'),
dcc.Dropdown(
id='app-2-dropdown',
options=[
{'label': 'App 2 - {}'.format(i), 'value': i} for i in [
'NYC', 'MTL', 'LA'
]
]
),
html.Div(id='app-2-display-value'),
dcc.Link('Go to App 1', href='/apps/app1')
])
@app.callback(
Output('app-2-display-value', 'children'),
[Input('app-2-dropdown', 'value')])
def display_value_two(value):
return 'You have selected "{}"'.format(value)
Found out a way to make it work. I simply moved the content of 'index.py' into 'wsgi.py', deleted 'index.py' and I adjusted the imports to have folder 'multipageapp' inside