background

Plotly Dash is a Python Web application framework that allows you to quickly build beautiful, responsive, interactive data visualization pages. Unfortunately, an app that only presents data isn’t always very useful. If we need a full Web application, we’ll have to find a way to take advantage of its back end, Flask.

The problem

Even though Dash borrowed Flask’s shell, this Flask runs inside a Sandbox and has a lot less functionality than regular flasks. The following features are either available or need to be upgraded to the Dash Enterprise version.

  • Database integration
  • certification
  • Multi-page, multi-route support
  • Custom style

, etc.

design

To overcome all of these problems, instead of using the Flask that comes with Dash, we can create a basic Flask application and put our Dash application on top of it.

The principle of

  • Flexible – Ability to create any type of application with Dash and Flask.
  • Fully functional – Both Dash and Flask must be fully functional, with no functional limitations.
  • Customizable – The ability to customize the style of the application.
  • Simplicity – It’s easy and quick to create a Dash application.

The solution

To sum up, there are two ways we can achieve our goals.

  • Child application: Create a basic Flask application, initialize the Dash application with this Flask as the parent server, and register the Dash application as a child application with a custom route.
  • iframe: Create a basic Flask application and place the Dash application in oneiframeIn Flask to load theseiframe.

Which is better

While this may seem the simplest approach compared to putting Dash applications in iframe, it introduces other problems due to the completely isolated nature of iframe:

  • Difficult to customize: iframeCannot be changed by CSS/JSiframeApplication within.
  • Don’t agree: iframeSince it has a different routing system than the main Frame, click on oneiframeInternal links do not trigger a jump to the main frame.
  • Unable to extend: iframeThe solution does not support multi-page Dash applications.

For these reasons, we believe that using sub-applications is a more flexible and universal solution.

The code structure

The basic Flask code structure is as follows:

├─ app │ ├─ Dash_apps - All Dash apps are in this directory │ │ ├─ custom_dash_app.py │ │ ├── experiment_detail_dash_app.py │ │ ├─ Experiment_list_dash_app. Py │ │ └ ─ ─ just set py │ ├ ─ ─ just set py │ ├ ─ ─ the static │ │ └ ─ ─ styles. The CSS - Custom CSS styles │ ├── Templates │ │ ├── ├ _ ├── ├.html - │ │ ├── ├.html - Homepage │ │ ├── ├.html -- Home page Layout │ ├── downloads.py -- Flask Route and Home page Navigation Menu Definition ├─ config.py ├── poetry ├── exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercises, exercisesCopy the code

See Github for the full demo implementation.

Implementation details

To implement the sub-application, we need to implement several key functions.

  • Create the blueprint for the underlying application
  • Register blueprint for the base application in Flask
  • Associate Dash with the base application and define routing and layout

Create blueprint for the base application:

Blueprint is the component Flask uses to implement modular applications.

app/views.py

from flask import Blueprint, render_template

base_app = Blueprint("base_app", __name__)

@base_app.route("/")
def index() :
    """Landing page."""
    return render_template("index.html", top_menu_items=get_top_menu_items("/"))
Copy the code

Register blueprint for the base application in Flask

In Flask, this is called application Factory mode and creates a create_app function that returns an Application object. Flask calls this function to process the request.

app/__init__.py

from flask import Flask

from app.views import base_app

def create_app(test_config=None) :
    """Create and configure Flask app"""

    app = Flask(__name__)

    app.register_blueprint(base_app)

    return app
Copy the code

Associate Dash with the base application and define routing and layout

Create a Dash application that uses the base application.

app/dash_apps/__init__.py

def customize_index_string(app, url) :
    """Custom app's index string"""
    app.index_string = env.get_template("dash_layout.html").render(
        top_menu_items=get_top_menu_items(url)
    )


def add_route(app, url) :
    """Add route to the app"""
    app.server.add_url_rule(url, endpoint=url, view_func=app.index)
    app.routes.append(url)


def create_dash_app(server, url_rule, url_base_pathname) :
    """Create a Dash app with customized index layout :param server: base Flask app :param url_rule: url rule as endpoint in base Flask app :param url_base_pathname: url base pathname used as dash internal route prefix """
    app = dash.Dash(name=__name__, server=server, url_base_pathname=url_base_pathname)

    customize_index_string(app, url_rule)
    add_route(app, url_rule)

    return app
Copy the code

app/dash_apps/custom_dash_app.py

from app.dash_apps import create_dash_app

# endpoint of this page
URL_RULE = "/custom-app"
# dash internal route prefix, must be start and end with "/"
URL_BASE_PATHNAME = "/dash/custom-app/"


def create_dash(server) :
    """Create a Dash view"""
    app = create_dash_app(server, URL_RULE, URL_BASE_PATHNAME)

    # dash app definitions goes here.return app.server
Copy the code

How do YOU add more Dash apps to your base app

Adding Dash to the base application takes a total of two steps.

Step 1: Create the Dash application

1-1: Create a.py file in the app/dash_apps directory.

1-2: Create the Dash application using the following code structure.

from app.dash_apps import create_dash_app

# endpoint of this page
URL_RULE = "/custom-app"
# dash internal route prefix, must be start and end with "/"
URL_BASE_PATHNAME = "/dash/custom-app/"


def create_dash(server) :
    """Create a Dash view"""
    app = create_dash_app(server, URL_RULE, URL_BASE_PATHNAME)

    # dash app definitions goes here, same as what you would do in normal Dash application.return app.server
Copy the code

Step 2: Add home page navigation menu for Dash app in app/views.py (optional)

top_menus = [
    {"path": "/"."title": "Home"},
    {"path": "/experiments"."title": "Experiments"},
    {"path": "/custom-app"."title": "Custom App"},... ]Copy the code

How to run

Run the following script to start the application. If FLASK_ENV=development is set, the application will run in development mode.

#! /bin/bash

source .venv/bin/activate

if [[ "${FLASK_ENV}"= ="development"]].thenFlask run --host=0.0.0.0 --port 8050else
    gunicorn wsgi:app \
        --bind0.0.0.0:8050 \ --log-level debug \ --workers 2 \ -- Threads 4fi
Copy the code