Dash
Dash is a productive Python framework for building web applications. Written on top of Flask, Plotly.js, and React.js, Dash is ideal for building data visualization apps with highly custom user interfaces in pure Python. It’s particularly suited for anyone who works with data in Python.
Deploying
Dash apps can be deployed with the rsconnect-python
package.
rsconnect deploy dash -n myServer MyApiPath/
Example apps
An example Dash app is available on GitHub.
To deploy the example with rsconnect-python
:
git clone https://github.com/sol-eng/python-examples
rsconnect deploy dash \
-n <saved server name> \
--entrypoint app:app \
python-examples/dash-app/
There are also a number of Dash example apps available from Plotly. Some of them require Python 2; those examples cannot be deployed to Posit Connect, which requires Python 3.7 or higher. Please ensure that you run examples locally before deploying to Connect.
git clone https://github.com/plotly/dash-sample-apps
rsconnect deploy dash \
-n <saved server name> \
--entrypoint app:app \
<app name>/ dash-sample-apps/apps/
When deploying a Dash app, ensure that you specify the correct entrypoint
for the specific app you are deploying. The example applications in this section have their source code in a file named app.py
, and within that file, the Dash application object is named app
. So the entrypoint specified here is app:app
. If the main source file or application object is named differently, you will need to specify a different entrypoint so that Posit Connect can locate the application object to serve. See the documentation on entrypoints for more information.
Do not pass the url_base_pathname
parameter to the Dash
application constructor in your code. Posit Connect will set the base path to the correct location for the deployed application.
Multi-page apps
Using Dash Pages
The Dash documentation includes an example of an app that consists of multiple pages and an index page for navigation. Multi-page apps use Dash Pages, a feature introduced in Dash version 2.5 (released on June 7, 2022). The recommended approach for deploying multi-page Dash apps on Connect is to use Dash Pages.
For example, your project could have the following structure:
- app.py
- pages
|-- analytics.py
|-- home.py |-- archive.py
from dash import Dash, html, dcc
import dash
= Dash(__name__, use_pages=True)
app
= html.Div([
app.layout 'Multi-page app with Dash Pages'),
html.H1(
html.Div(
[
html.Div(
dcc.Link(f"{page['name']} - {page['path']}",
=page["relative_path"]
href
)
)for page in dash.page_registry.values()
]
),
dash.page_container
])
if __name__ == '__main__':
=True) app.run_server(debug
import dash
from dash import html, dcc, callback, Input, Output
__name__)
dash.register_page(
= html.Div(children=[
layout ='This is our Analytics page'),
html.H1(children
html.Div(["Select a city: ",
'New York City', 'Montreal','San Francisco'],
dcc.RadioItems(['Montreal',
id='analytics-input')
]),
html.Br(),id='analytics-output'),
html.Div(
])
@callback(
='analytics-output', component_property='children'),
Output(component_id='analytics-input', component_property='value')
Input(component_id
)def update_city_selected(input_value):
return f'You selected: {input_value}'
import dash
from dash import html, dcc
__name__, path='/')
dash.register_page(
= html.Div(children=[
layout ='This is our Home page'),
html.H1(children
='''
html.Div(children This is our Home page content.
'''),
])
import dash
from dash import html, dcc
__name__)
dash.register_page(
= html.Div(children=[
layout ='This is our Archive page'),
html.H1(children
='''
html.Div(children This is our Archive page content.
'''),
])
Without Dash Pages
If you are using a version of Dash that is less than version 2.5, you will not be able to use the Dash Pages feature. Instead, you can use the dcc.Location
feature as described in this example. To deploy a multi-page app on Posit Connect, you must use Dash’s get_relative_path
and strip_relative_path
functions to implement the navigation.
For example, your project could have the following structure:
- app.py
- pages
|-- __init__.py
|-- index.py
|-- page1.py |-- page2.py
from dash import Dash, dcc, html, Input, Output, callback
from pages import page1, page2, index
= Dash(__name__, suppress_callback_exceptions=True)
app = app.server
server
= html.Div([
app.layout id='url', refresh=False),
dcc.Location(id='page-content'),
html.Div(
html.Div(['Go to Home', href=app.get_relative_path("/")),
dcc.Link(
html.Br(),'Go to Page 1', href=app.get_relative_path('/page1')),
dcc.Link(
html.Br(),'Go to Page 2', href=app.get_relative_path('/page2'))
dcc.Link(
])
])
@callback(Output('page-content', 'children'), Input('url', 'pathname'))
def display_page(pathname):
= app.strip_relative_path(pathname)
pathname if pathname == '':
return index.layout
elif pathname == 'page1':
return page1.layout
elif pathname == 'page2':
return page2.layout
else:
return '404'
if __name__ == '__main__':
=True) app.run_server(debug
# an empty file
from dash import html
= html.Div([
layout 'Home page!'),
html.H3( ])
from dash import dcc, html, Input, Output, callback
= html.Div([
layout 'Page 1'),
html.H3(
dcc.Dropdown(f'Page 1 - {i}': f'{i}' for i in ['New York City', 'Montreal', 'Los Angeles']},
{id='page-1-dropdown'
),id='page-1-display-value'),
html.Div(
])
@callback(
'page-1-display-value', 'children'),
Output('page-1-dropdown', 'value'))
Input(def display_value(value):
return f'You have selected {value}'
from dash import dcc, html, Input, Output, callback
= html.Div([
layout 'Page 2'),
html.H3(
dcc.Dropdown(f'Page 2 - {i}': f'{i}' for i in ['London', 'Berlin', 'Paris']},
{id='page-2-dropdown'
),id='page-2-display-value'),
html.Div(
])
@callback(
'page-2-display-value', 'children'),
Output('page-2-dropdown', 'value'))
Input(def display_value(value):
return f'You have selected {value}'
Content URL paths for multi-page Dash apps do not update based on a set vanity URL. For example, setting your application vanity URL to /multi-page-dash/
will make the index page available at that location, but /multi-page-dash/page-2
will not be accessible. page-2
will only be accessible via the base content URL, .../content/{GUID}/page-2
.
User meta-data
Dash apps can access the username and the names of the groups of the current logged in user by parsing the RStudio-Connect-Credentials
request header.
Your Dash app should access the RStudio-Connect-Credentials
header value via the flask.request
object’s headers
property. This value is populated from the HTTP_RSTUDIO_CONNECT_CREDENTIALS
environment variable present in the underlying WSGI environ.
This simple Dash app shows how to access and use the user credentials from the RStudio-Connect-Credentials
header:
# -*- coding: utf-8 -*-
import json
import dash
import dash_core_components as dcc
import dash_html_components as html
import flask
from dash.dependencies import Input, Output
= dash.Dash(__name__)
app
= html.Div([
app.layout
dcc.Dropdown(id="salutation",
=[
options"label": "Hello", "value": "Hello"},
{"label": "Greetings", "value": "Greetings"},
{"label": "Aloha", "value": "Aloha"},
{
],=False,
searchable=False,
clearable="Hello"
value
),id="greeting")
html.P(
])
def get_credentials(req):
"""
Returns a dict containing "user" and "groups" information populated by
the incoming request header "RStudio-Connect-Credentials".
"""
= req.headers.get("RStudio-Connect-Credentials")
credential_header if not credential_header:
return {}
return json.loads(credential_header)
@app.callback(
="greeting", component_property="children"),
Output(component_id"salutation", "value")]
[Input(
)def greeting(salutation):
= get_credentials(flask.request)
user_metadata = user_metadata.get("user")
username return "%s, %s." % (salutation, username or "stranger")
if __name__ == "__main__":
=True) app.run_server(debug
User and Group uniqueness
Most environments have unique usernames where each user
identifies a single user and groups
the name of the groups the user is a member of.
However, in large organizations with hundreds of users and groups, this may not be true. See the Admin Guide sections Credentials for Content for more information.