Is there functionality, plan to add one, or a hack to enable multiple dashboards in the same server? Right now I’m getting this in Spyre, trying to replicate in Dash
I think that the way Dash handles multiple “pages” gets you to the multiple dashboard outcome.
See this discussion:
With latest (master) version of dash, you can build a multi-app project!
Structure
dash-project/
app1/
app.py
datamodel.py
app2/
app.py
datamodel.py
mycomponents/
...
server.py
run.py
app1/app.py:
import dash
import app1.datamodel
..
from server import server
app = dash.Dash(name='app1', sharing=True,
server=server, url_base_pathname='/app1')
from flask import Flask
server = Flask(__name__)
from server import server as application
import app1.app
import app2.app
Serve using uwsgi:
uwsgi --http 0.0.0.0:5000 --processes 4 --wsgi-file run.py
(updated to work with uwsgi, so you get proper multi-process management)
I would like to run multiple instances of the same app side by side on the same computer. I am able to pass the port number to app.run_server() so each instance uses a different port. However, when I run two instances, I get this error:
WARNING in flask_seasurf [D:\Users\212448403\AppData\Local\Continuum\Anaconda32_new\lib\site-package
s\flask_seasurf.py:282]:
Forbidden (CSRF token missing or incorrect.): /_dash-update-component
What is going wrong? Some authentication issue?
Did you put ‘csrf_protect=False’ in your app?
Like this
app = dash.Dash(‘My app’, server=server, url_base_pathname=’/’, csrf_protect=False)
That worked! Thanks!
Note that you can also create a multi-page Dash app using links and the new dash_core_components.Location component. I just wrote a tutorial on this here: https://plot.ly/dash/urls. This is what the multi-page Dash user guide (https://plot.ly/dash, github.com/plotly/dash-docs) uses.
This would be better than setting the csrf_protect flag to False, probably.
I was really looking forward to this, awesome!
so for these multiple dashboards we don’t need to break up the code say what the person did above ie i mean your tutorial both pages are in the same module script can it be separated into say two module scripts and imported into a third script ?
ie can we design the code the following way:
have page 1 dropdown in one .py script called drop.py
have page 2 radio in a second ,py script called radio.py
have a run script that can run both ie run.py runs both dashboards
this way its cleaner code and not overlapping
i attempted to split the example into two separate .py scripts and call it but I failed to do so hence I am asking the question the idea Vlad posted doesn’t work for me when I attempted to split the urls example posted in the docs
@Vlad This is great - thanks for sharing it. I’m assuming your app var in app2/app.py is something like this:
import dash
import app2.datamodel
from server import server
app = dash.Dash(name='app2', sharing=True,
server=server, url_base_pathname='/app2')
i’m getting AssertionError: View function mapping is overwriting an existing endpoint function: serve_layout even though both my apps use unique names. Any pointers?
Thanks a lot
Will
yeah, you need to use version in github, (not available in pip install dash yet).
pip install -e git+git://github.com/plotly/dash#egg=dash
At the moment, I am trying to make a setup using UWSGI emperor mode:
http://uwsgi-docs.readthedocs.io/en/latest/Emperor.html
Stay tuned…
Oh, man. That’s a lot of hours I’ve wasted. Thanks! Will look forward to it reaching pip at some point …
Still struggling to get your version above working @Vlad. I’m wondering if my desired setup will even be possible:
url.com/apps/app1
url.com/apps/app2
url.com/apps/category/app3
url.com/apps/category/app4
We have an existing Flask app running (url.com/flask). I think it’s using uwsgi and nginx. So perhaps we could use that as the ‘runner’, with a basic template pointing to url.com/flask/app1 etc.
I can’t be the only one needing this though! Thoughts welcome
Will
@will - Does the approach outlined in https://plot.ly/dash/urls work for you? This is what I use on the Dash docs (https://plot.ly/dash, https://github.com/plotly/dash-docs).
In your case, this would look something like:
import dash
import dash_core_components as dcc
import dash_html_components as html
import app1
import app2
import app3
import app4
print(dcc.__version__) # 0.6.0 or above is required
app = dash.Dash()
app.layout = html.Div([
# represents the URL bar, doesn't render anything
dcc.Location(id='url', refresh=False),
# content will be rendered in this element
html.Div(id='page-content')
])
@app.callback(dash.dependencies.Output('page-content', 'children'),
[dash.dependencies.Input('url', 'pathname')])
def display_page(pathname):
if pathname == '/apps/app1':
return html.Div('This is app 1')
elif pathname == '/apps/app2':
return html.Div('This is app 2')
elif pathname == '/apps/category/app3':
return html.Div('This is app 3')
elif pathname == '/apps/category/app4':
return html.Div('This is app 4')
Or, if you want to put these apps in separate files and import them, it would look something like:
- app.py
- index.py
- apps
|-- __init__.py
|-- app1.py
|-- app2.py
app.py
import dash
app = dash.Dash()
server = app.server
app.config.supress_callback_exceptions = True
app.css.append_css({
"external_url": "https://codepen.io/chriddyp/pen/bWLwgP.css"
})
index.py
from dash.dependencies import Input, Output
import dash_core_components as dcc
import dash_html_components as html
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)
__init__.py
# empty file
app1.py
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
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)
app2.py
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
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(value):
return 'You have selected "{}"'.format(value)
Awesome, @chriddyp. I’ve actually tried something similar yesterday but yours is neater - and works well for simple apps. But for one of my more complicated one (multiple figures, callbacks; about 20 radios/dropdowns) I get the same wsgi issue:
Error on request:
Traceback (most recent call last):
File "/usr/local/lib/python2.7/site-packages/werkzeug/serving.py", line 209, in run_wsgi
execute(self.server.app)
File "/usr/local/lib/python2.7/site-packages/werkzeug/serving.py", line 200, in execute
write(data)
File "/usr/local/lib/python2.7/site-packages/werkzeug/serving.py", line 168, in write
self.send_header(key, value)
File "/usr/local/Cellar/python/2.7.13/Frameworks/Python.framework/Versions/2.7/lib/python2.7/BaseHTTPServer.py", line 412, in send_header
self.wfile.write("%s: %s\r\n" % (keyword, value))
IOError: [Errno 32] Broken pipe
127.0.0.1 - - [21/Aug/2017 20:59:08] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:08] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:08] "GET /favicon.ico HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:08] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200 -
127.0.0.1 - - [21/Aug/2017 20:59:09] "POST /_dash-update-component HTTP/1.1" 200
The 200 response is repeated 6-10 times per second. I tried adding threaded=True to app.run_server() without luck; there must be something fundamentally wrong in my app. I’d share it here but it’s too sensitive unfortunately. I may pm you though, in case this is a common issue which may affect others (doubt it!)
Think your approach is on the right lines though. Will just have to start the app afresh
For more complex, production-level apps, I recommend running the app behind gunicorn instead of the flask dev server. Like threading=True, this will run the app in a way that can process many requests in parallel. Unlike threading=True, it’s more robust and performant.
So:
$ gunicorn app:server
install gunicorn with pip install gunicorn. In this case, app refers to app.py and server refers to the variable server instead app.py. This is adapted from the instructions in deployment: Deploy Your Dash App | Dash for Python Documentation | Plotly
Thanks Chris. I did try with Gunicorn yesterday, but no joy. I’m going to forget about using this particular app inside a multi-page multi-URL app; it’s clearly too heavy / unwieldy / poorly written. Plan is to fire uwsgi once to handle the simpler apps, and again for this more complicated one.
Ideally, I believe we want to make it work with something like this:
http://uwsgi-docs.readthedocs.io/en/latest/Emperor.html
Combined with lazy start and timeout process termination - this seams to be a perfect setup, where each app is running in a separate python process, therefore avoiding potential memory issues, with one heavy app blocking everything else.
So far - I had only some luck with this setup (caused by some url path issues).
