Using Plotly Dash to build a dashboard

In this tutorial we will see how to create a service that serves a dashboard using Plotly Dash.We will not go into detail into how to use Plotly Dash itself, but rather how to deploy a Plotly Dash application with Daeploy.

Example Plotly Dash application

We will use a hello-world Plotly Dash application in this tutorial that simply prints Hello World. The code for this application looks like this:

import dash
import dash_html_components as html

app = dash.Dash(__name__)

app.layout = html.Div(
    children=[
        html.H1(children="Hello World"),
    ]
)

if __name__ == "__main__":
    app.run_server(debug=True)

In order to run this application, our requirements.txt will look like:

dash

That is all you need to run this Plotly Dash application locally. Lets now have a look at making this example deployable and runnable with Daeploy.

Plotly Dash application as a standalone service

Let’s get som fresh boiler-plate directories/files using the functionality provided by the Daeploy CLI:

>>> daeploy init 
project_name [my_project]: plotly_dashboard

To run the same dashboard on Daeploy only a few changes have to be made. First, when creating the app-object we must tell Dash that it will be running under some custom root_path (aka base_path):

import daeploy

app = dash.Dash(
    __name__,
    requests_pathname_prefix=daeploy.utilities.get_service_root_path() + "/",
)

And when starting the server, we need to make sure that the Plotly Dash application accepts connections from others than localhost:

if __name__ == "__main__":
    app.run_server("0.0.0.0")

The final application code should now look like this:

import dash
import dash_html_components as html
import daeploy

app = dash.Dash(
    __name__,
    requests_pathname_prefix=daeploy.utilities.get_service_root_path() + "/",
)

app.layout = html.Div(
    children=[
        html.H1(children="Hello World"),
    ]
)

if __name__ == "__main__":
    app.run_server("0.0.0.0")

We can now deploy the Plotly Dash app, like we would any other service, with one important difference. Plotly Dash, by default, use port 8050 to communicate so we have to explicitly set the port when deploying:

>>> daeploy deploy plotly_dashboard 1.0.0 ./plotly_dashboard --port 8050 
Active host: http://your-host
Deploying service...
Service deployed successfully
MAIN    NAME              VERSION    STATUS    RUNNING
------  ----------------  ---------  --------  -----------------------------------
*       plotly_dashboard  1.0.0      running   Running (since 2021-01-13 07:14:55)

Note

Daeploy services created using the SDK use port 8000, which is the default port for daeploy deploy. But when deploying other apps it might be necessary to change it to not get a Bad Gateway.

Open http://your-host/services/plotly_dashboard/ and you should see your app there

Plotly Dash application as part of a SDK-based application

It is also possible to add a Plotly Dash application as a (sub-)part of an SDK-based service. This is done by mounting the Plotly Dash server on the SDK app. In the example below, we mount the Plotly Dash app at the subpath /dashboard/ under the Daeploy SDK service app:

import daeploy
import dash
import dash_html_components as html

# We need a WSGIMiddleware to be the middleman between the asynchronous SDK app
# (based on FastAPI) and the synchronous Dash app (based on Flask). `starlette`
# is a dependency of FastAPI so it doesnt need to be added to the
# `requirements.txt`
from starlette.middleware.wsgi import WSGIMiddleware

# Creating Dash app object that can be used as usual to build you Dash application.
# We make sure to give it the correct path where it will be mounted
app = dash.Dash(
    __name__,
    requests_pathname_prefix=daeploy.utilities.get_service_root_path() + "/dashboard/",
)

app.layout = html.Div(
    children=[
        html.H1(children="Hello World"),
    ]
)

# We mount the Dash app server under daeploy.service.app on the subpath `/dashboard`
daeploy.service.app.mount("/dashboard", WSGIMiddleware(app.server))

# And finally we start the service as we would with any other SDK-based service.
if __name__ == "__main__":
    daeploy.service.run()

Assuming we deploy our service as such (note that we no longer need to specify a custom port number since we are using the SDK to actually run the application):

>>> daeploy deploy plotly_dashboard 1.0.0 ./plotly_dashboard 
Active host: http://your-host
Deploying service...
Service deployed successfully
MAIN    NAME              VERSION    STATUS    RUNNING
------  ----------------  ---------  --------  -----------------------------------
*       plotly_dashboard  1.0.0      running   Running (since 2021-01-13 07:14:55)

Your dashboard would then be available at http://your-host/services/plotly_dashboard/dashboard/