Plotly Dash is a framework that allows the creation of interactive dashboards, facilitating the presentation of a wide variety of data and information in an easy to digest and aesthetically pleasing format.
Typically, examples and guidance on how to create a Dash app have all the code within a single python file. Although this is a nice concise way to start, even simple dashboards can become overwhelming to manage when all the code is in a single file.
This article presents a sensible, and fully functional, multi-file project structure, containing all the essentials to get started.
Managing and expanding the project, even if the project is quite extensive, should become much easier to deal with.
Introduction
Many online examples …
Plotly Dash is a framework that allows the creation of interactive dashboards, facilitating the presentation of a wide variety of data and information in an easy to digest and aesthetically pleasing format.
Typically, examples and guidance on how to create a Dash app have all the code within a single python file. Although this is a nice concise way to start, even simple dashboards can become overwhelming to manage when all the code is in a single file.
This article presents a sensible, and fully functional, multi-file project structure, containing all the essentials to get started.
Managing and expanding the project, even if the project is quite extensive, should become much easier to deal with.
Introduction
Many online examples for Dash dashboards are presented in a single file, and although this is fine for small simple dashboards, it becomes impossible to manage as a project increases in size, and potentially onto multiple pages.
It therefore becomes necessary to start breaking up the single file to create a logical project structure to make project management easier.
However, guidance on how to approach a structured multi-page app, specifically with Dash, are few and far between. There also appears to be no standard “official” way to structure a Dash app.
Furthermore, any examples of multi-page apps tend to present a bear-bones structure that typically doesn’t include any example graphing (i.e. they are not fully functional). This leaves some guesswork with regard to actually getting the app to run and work reliably with the data you want to present.
This article provides a fully functional base that the user can run, and experiment with, straight away. It also provides a useful reference point to begin developing a project from.
Disclaimer: I am in no way affiliated with Plotly. Furthermore, both the shared GitHub code base, and all the features and examples in this article, can be used without the need for any paid features or paid subscriptions.
Aim
With the above in mind, this article is primarily concerned with four items in relation to creating a Dash dashboard:
- Multi-page
- Logical project structure (i.e. not all in one file, and with a multi-folder structure)
- Fully functional including data (API) and graphing (Plotly)
- Git ready
Detailed Features
The exact output (dark mode) showing the features of the project structure – Image by Author – Data from GAPMINDER.ORG, CC-BY LICENSE
A summary
In addition to the main aims detailed in the previous section, the following features have been included to provide a usable, aesthetically pleasing, and functional base:
- A sidebar which lists the available pages, and highlights which page is active as the page changes
- A header with website name, logo and dark/light theme switch
- Mobile ready responsive layout with collapsible sidebar
- Dark/light theme switching, including dark light theming of the Plotly graphs
- Two different API integrations, one local (Plotly Gapminder), and one remote with logic for API keys (NinjasAPI)
- Git ready, with logic to keep API keys out of the code, and auto DEBUG/production mode (python-dotenv)
- A simple example of bespoke styling using style.css
- Utilises DASH Mantine Components for general styling, providing a consistent theme The following sub-sections will explain some of the features included in the framework in a little more detail.
If you are looking for the code please skip towards the end of the article where you will find a link to the GitHub repository with the code and details on how to get started.
Styling with DASH Mantine Components
The exact output (light mode) showing the features of the project structure – Image by Author – Data from GAPMINDER.ORG, CC-BY LICENSE
It is possible to style a Dash dashboard without the aid of a front end framework. However, in general I suspect the priority will be to present data quickly and effectively, so it makes little sense to make life harder than it needs to be.
As such, the framework presented in this article utilises Dash Mantine components for styling, which is a widely used and modern styling API designed specifically for use with Dash dashboards:
Build feature-rich, accessible Dash apps faster than ever! Dash Mantine Components includes over 100 customizable components based on the React Mantine library, with consistent styling, theming, and full support for light and dark mode.
In particular, the layout selected for this project structure builds on the following official layout example:
AppShell with Theme Switch Component – GitHub
Although the overall look of the official layout is very similar to the one this article uses (as you would expect…), there is no functionality built into the official layout, and all the code is in a single python file.
Dark light graph switching
The base theme detailed in the previous section already includes the code to switch between light and dark themes.
However, once components are added that are not specifically “Mantine” components (e.g. plotly graphs), then the theme switch will not work for those “other” components without specific integration.
The framework included in this article includes example plotly graphs, and the associated code to switch the graphs between the dark and light theme.
The dark/light switch is implemented to work without the need to reload the data displayed in the graphs, and hence will not overload any data APIs on switching.
Multi-page
One of the more complicated items included in the framework is the fact that it includes more than one page.
The implementation uses the most recent method of achieving this through Dash Pages, which was introduced in Dash 2.5.
Although the implementation of Dash Pages is relatively straight forward, it becomes more complicated when the project is structured into multiple files and folders, as there are very few examples available.
Hopefully, this framework will provide guidance on what a working example looks like.
Git and Development Ready
Photo by Yancy Min on Unsplash
As this framework is intended to be a starting point for your own project, it is assumed that some development will take place, and that ongoing development may include the need to use Git.
The following subsections detail some features of this framework that help to make this process easier.
Environmental variables
The framework utilises python-dotenv to handle environmental variables (see the “Basic Usage” section later in the article for implementation details).
What this essentially means is that certain variables can be kept local to the project, but out of the main code-base. For example:
- variables that change between production and development environments
- variables that should not appear in public repositories (i.e. GitHub) This allows API keys to be kept secret, and seamless pushing to production through GitHub (should you wish to do this).
Git Ignore
A .gitignore
file is included primarily to stop virtual environments, and the all important .env
file, from being pushed to GitHub by accident.
It also includes some generic Python based exclusions that may be helpful.
Production Server Ready
To aid in the deployment of the Dash app to production, a wsgi.py
file is included, which should be useful when the time comes to push the project live.
The .env
file mentioned in the previous section can also be used to activate (or deactivate) DEBUG
mode seamlessly between produciton and development environments. (see the “Basic Usage” section later in the article for implementation details)
API Integration
Image by zeeve platform from Pixabay
There are two data APIs integrated into the codebase.
Gapminder (the default)
The first is the Gapminder API that is included as a library within Plotly.
This makes the API locally available, and fast, which is great for rapid development and testing.
API Ninjas
There is also code included as an example of how to integrate an external API.
In this particular case, the included external API is API Ninjas. This should essentially allow for more realistic remote API testing should you need this (i.e. accounting/testing for bad or lost connections, or API errors).
API Ninjas is a commercial API, and as such has subscription costs beyond certain usage levels. However, their free tier is one of the most generous I have found, which makes it great for development testing.
To use the API Ninjas API you will need to get your own API key (A free limited use API Key can be acquired from their website). The API key then needs to be included in the .env
file. Finally, set the EXTERNAL_API
flag in utils/consts.py
to True
.
Disclaimer:* I am in no way affiliated with API Ninjas, feel free to use an external API of your choice (or none at all)!*
CSS Styling
Specific styling can be included within the project in a CSS file. This file is located in assets/styles.css
and includes the following code:
.main-title {
color: var(--mantine-color-gray-6);
}
[data-mantine-color-scheme="dark"] .main-title {
color: var(--mantine-color-gray-3);
}
The example just changes the main title to a gray colour, but also accounts for colour change when switching between the dark and light theme.
If you are familiar with CSS, extensive style changes can be made from this file if required.
More details on how to deal with external resources like CSS or Javascript are in the Dash docs.
Important coding notes
The second page of the framework app – Image by Author
Dash is very flexible in terms of the methods allowed to build a dashboard/app, which keeps things simple and easy to use.
However, in the process of building this framework it has become clear that some unwritten rules need to be followed when things become more complicated.
it is essential to produce app elements with functions rather than assigning them to a variable.
In particular, when dealing with a multi-page Dash app, with file and folder structure, it is essential to produce app elements with functions rather than assigning them to a variable.
As an example, take the definition of the Archive page utilised in this project structure.
This is the Archive page defined with a function:
import dash
from dash import html
dash.register_page(__name__)
def layout(**kwargs) -> html.Div:
return html.Div(
[
html.H1("This is our Archive page"),
html.Div("This is our Archive page content."),
]
)
…and this is the same page defined using a variable:
import dash
from dash import html
dash.register_page(__name__)
layout = html.Div(
[
html.H1("This is our Archive page"),
html.Div("This is our Archive page content."),
]
)
In theory they are both valid, and should both work, as can be seen from the official documentation.
In general, assigning to a variable will work sometimes. However, there are certain circumstances where passing variables between separate files/folders will fail. Whereas, using functions will always work.
Unfortunately, I cannot recall an example, but I have experienced this first hand, which is why this framework religiously uses functions if elements are required to be passed between files/folders in the code.
Regardless, using functions is arguably a much more transparent and accountable way of coding, and in the long run makes much more sense.
Variable Typing
You may note that variable typing has been included on all functions.
As the codebase is written in Python this is not strictly necessary. The hope is that it will help with transparency when people are reading the codebase and trying to get their head around how the different pieces fit together.
If you find it confusing, or not helpful, then it can always be removed without any ill effects.
For example, changing this:
def get_graph(index: str) -> dmc.Skeleton:
to this:
def get_graph(index):
Is perfectly OK.
The Repository
The GitHub page where you can access the DASH project structure discussed in this article – Image by Author A fully working example Dash app, using the structure covered in this article, is available on my GitHub repository here:
The repository can be cloned and run directly to see how things work, or used as a starting point for your own project.
Basic Usage
Photo by Eder Pozo Pérez on Unsplash
To run the code in the repository take the following steps.
Create your virtual environment and install packages
Create your virtual environment and activate it. You can do this however you choose. For example:
cd project-folder
python -m venv venv
source venv/bin/activate
Then install the required packages:
pip install --upgrade pip
pip install -r requirements.txt
Create a “.env” file
The project uses python-dotenv
to keep things like API Keys out of the project code by using a local file to store sensitive data. As such, you won’t find this file included in the repository. You will need to create your own.
In the root of the project folder create a file with the name: .env
.
As an example of what to include in the file, the following is what could be used in a local development environment:
DEBUG = True
NINJAS_API_KEY = "s0L889BwIkT2ThjHDROVGH==fkluRlLyGgfUUPgh"
Note: You would have to get a legitimate API Key from NinjasAPI if you wanted to use that particular API, but as Gapminder local API is the default this is not necessary to run the app. Apart from including a working API key to use the NinjasAPI, you will also have to set the EXTERNAL_API
flag in utils/consts.py
to True
.
Within a live / development environment you should change the DEBUG
value to False
.
Utilising this method has the advantage of being able to use Git to update code between the development and production environments, without having to change the DEBUG
value in the .env
file every time.
This is due to the .env
not being included in the Git repository, and therefore being exclusive to the machine/server it is created on.
Run the Project
To run the project just execute the following line from within the project directory:
python main.py
You will then be told the local IP address that you can open in a browser to access the project front end.
Conclusion
Hopefully this article, and the associated Github repository provide a good starting point to begin your journey into using Plotly Dash to create your own dashboards, or even just get some idea of how to move to the next stage.
If you have any comments, or improvements, with regard to the code, please feel free to either comment on this article, or open an issue / pull request on the associated GitHub repository.
References
Plotly DASH DASH Mantine Components GAPMINDER.ORG, CC-BY LICENSE