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 in MVI.

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 on MVI.

Plotly Dash application as a standalone service

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

>>> mvi init 
Active host: http://your-host
project_name [my_project]: plotly_dashboard

The first thing we have to do is to add va-mvi to the requirements.txt file so that it looks like this:

va-mvi
dash

The next step is to take our application source code and put it into service.py. We also make a few minor tweaks to the application code according to below.

Lets add an import of mvi at the top:

import mvi

When creating the app-object we also need to tell Dash that it will be running under some custom root_path (aka base_path) like so:

app = dash.Dash(
    __name__,
    requests_pathname_prefix=mvi.utilities.get_service_root_path(),
    )

And finally, 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 mvi
import dash
import dash_html_components as html


app = dash.Dash(
    __name__,
    requests_pathname_prefix=mvi.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:

>>> mvi 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

MVI services created using the SDK use port 8000, which is the default port for mvi 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 MVI SDK service app:

import mvi
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=mvi.utilities.get_service_root_path() + "dashboard/",
    )

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

# We mount the Dash app server under the mvi.service.app on the subpath `/dashboard`
mvi.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__':
    mvi.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):

>>> mvi 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/