How to Build a Reporting Dashboard using Dash and PlotlyDavid ComfortBlockedUnblockFollowFollowingMar 11In this blog post, I will provide a step-by-step tutorial on how to build a reporting dashboard using Dash, a Python framework for building analytical web applications.
Rather than go over the basics of building a Dash app, I provide a detailed guide to building a multi-page dashboard with data tables and graphs.
I built the reporting dashboard as a multi-page app in order to break up the dashboard into different pages so it less overwhelming and to present data in an organized fashion.
On each dashboard page, there are two data tables, a date range selector, a data download link, as well as a set of graphs below the two dashboards.
I ran into several technical challenges while building the dashboard and I describe in detail how I overcame these challenges.
The completed Dashboard can be viewed at https://davidcomfort-dash-app1.
com/cc-travel-report/paid-search/ and the code is provided in Github.
(The data used in the app is random data and the names for the products are “dummy” names.
)Figure 1: Dashboard built using DashFigure 2: Second Part of DashboardTable of Contents1.
What am I Trying to Achieve with a Dashboard?3.
Challenges Building the Dashboard4.
Creating a New Environment and Installing Dash5.
Getting Started with Dash6.
Building a Multi-page ApplicationBuilding the Index PageCustomizing the Page Title and FaviconOverview of the Page LayoutLocal Testing of the App7.
Building the Date Selector ElementAdding a correction to CSS so that the Date Picker is not hidden behind the data tables8.
Building the First Data TableChanging the Dates Presented in the Data Table based upon the Date SelectionCalculating Changes in the Metrics, as well as the calculating cost-per-session, conversion rate, and cost-per-acquisition.
A method to select either a condensed data table or the complete data table.
Conditionally Color-Code Different Data Table cellsConditional Formatting of Cells using Doppelganger Columns9.
Building the Download Data link10.
Building the Second Data Table11.
Updating Graphs by Selecting Rows in a Dash Data tableStep 1Step 2Step 312.
Updating the Graphs and Calculating metrics on the fly13.
Plotly Graph Tools14.
Deploying the DashboardResolving an Issue with Custom.
css File and AuthenticationDash Deployment Server15.
Resources for Dash1.
IntroductionIn January of this year, I went to my first PyData conference, PyData Miami, and sat in on a great presentation by Chelsea Douglas about Dash.
Embedded Video 1: Dash: data exploration web apps in pure Python — Chelsea DouglasIt quickly became apparent how powerful Dash was and how I easily I could build web apps and dashboards using Python.
From my perspective, there was a real need in my company to automate reporting, replace Microsoft Excel pivot tables and spreadsheets, and provide an alternative to Business Intelligence tools.
Even though various stakeholders in my company have relied upon Excel spreadsheets for regular reporting, their usage becomes unwieldy, they are prone to error, they are not platform independent, and they do not lend themselves to automation.
Therefore, I endeavored to build a multi-page web application using Dash.
This article goes into the nitty, gritty details of my efforts and how I overcame several technical challenges.
I should note that I come from a data scientist perspective and make no claims to be a software developer.
Hence, there certainly is room for improvement in my code and I would welcome the reader’s suggestions.
At the same time, I hope the reader can benefit from my efforts if they need to build complex dashboards and data tables.
What am I Trying to Achieve with a Dashboard?At my present company, a lot of periodic reporting is done either with Excel spreadsheets and pivot tables, or using business intelligence tools such as Birst or Qlikview.
Hence, I wanted to build a reporting dashboard as a proof-of-concept that could replace and enhance our reporting.
Specifically, I wanted to build a reporting web application for one of brands, which could report out on different marketing channel metrics, enable automation and provide ease of access.
The requirements for the E-commerce Marketing Dashboard included:Break out the different marketing channels into different pages so that the amount of data presented in the dashboard would not be overwhelming.
A date selector so a user can select a date range to filter the data.
A data table to present basic metrics (spend, sessions, number of transactions, and revenue) for each digital marketing channel or product type for the date range selected, as well as for the same period last year and a corresponding period prior to the date range selected.
*Another data table to present calculated metrics for the date range selected (as well as for the same period last year and prior period).
These metrics include cost-per-session (CPS), conversion rate (CVR), and CPA (cost-per-acquisition).
A link to download the data (in Excel format) that is displayed in each data table.
Graphs of the metrics on a weekly basis are to be depicted below the data tables.
An example of a corresponding prior period would be if a user selected week numbers 5 and 6 of 2019, then the corresponding prior period would be week numbers 3 and 4 of 2019.
Challenges Building the DashboardThere were multiple challenges that cropped up when I was building the dashboard app.
Some of the main challenges included:Figuring out a method to display either a condensed data table or a complete data table.
Having the ability to color code cells in the data tables, based upon the value in that cell.
Having the ability to select multiple products to include in a graphical representation of the data.
Having the ability to update the metrics in the data tables on-the-fly, depending upon the date range a user selects.
Having the ability to download the data presented in the data tables without any added formatting.
Depicting year-to-year changes in metrics on the same x-axis as a given metric.
Being able to zoom in on all graphs at the same time.
Creating a New Environment and Installing DashThere is a Dash User Guide, which provides a fairly thorough introduction to Dash and I encourage the reader to go through the user guide and build some simple Dash apps prior to tackling a full fledged dashboard.
In addition, there is a Dash Community Forum, a show-and-tell section of the forum highlighting work by the Dash community, a gallery of Dash projects, a curated list of awesome Dash resources, and an introductory essay about Dash:Dash is a Open Source Python library for creating reactive, Web-based applications.
Dash started as a public proof-of-concept on GitHub 2 years ago.
We kept this prototype online, but subsequent work on Dash occurred behind closed doors.
We used feedback from private trials at banks, labs, and data science teams to guide the product forward.
Today, we’re excited to announce the first public release of Dash that is both enterprise-ready and a first-class member of Plotly’s open-source tools.
Dash can be downloaded today from Python’s package manager with pip install dash — it’s entirely open-source and MIT licensed.
You’ll find a getting started guide here and the Dash code on GitHub here.
Dash is a user interface library for creating analytical web applications.
Those who use Python for data analysis, data exploration, visualization, modelling, instrument control, and reporting will find immediate use for Dash.
Dash makes it dead-simple to build a GUI around your data analysis code.
Prior to installing Dash, as is the usual practice, I created a new environment using conda: conda create –name dash and then activated that environment, conda activate dash.
I then simply followed the Dash installation protocol provided in the user guide:Code Block 1: Pip installing Dash and its componentsI should note that the versions for Dash and its components will change from above and you should refer to the User Guide.
Getting Started with DashThere are already quite a few tutorials for Dash, so I will focus on how to build a multi-page dashboard with data tables and graphs in this tutorial, rather than go over the basics of building a Dash app.
If you are just getting started in Dash, I would encourage the reader to go through at least the first three sections of the excellent Dash User Guide.
There is also a section on the Dash Data Table.
There are several tutorials to get you started*:Introducing Plotly Dash — A high level introduction to Dash by Chris Parmer, the author of Dash.
This essay was released as part of Dash’s official launch (June 21, 2017).
Plotly’s tutorials — Part 1: App LayoutPlotly’s tutorials — Part 2: InteractivityPlotly’s tutorials — Part 3: Interactive GraphingPlotly’s tutorials — Part 4: Callbacks With StateInteractive Web-Based Dashboards in Python — How the MVC model pertains to Dash and a walkthrough of building an app.
Using Plotly’s Dash to deliver public sector decision support dashboards — Building a complex dashboard step-by-step.
OPS CodeDay: Dash Plotly Map + Graph — How to use Jupyter notebooks in tandem with Dash to create mapping viz.
Creating Interactive Visualizations with Plotly’s Dash Framework — High level overview of how to get started with Dash.
Finding Bigfoot with Dash, Part 1 — Walkthrough of building a dashboard of Bigfoot sightings.
Part 2, Part 3.
Visualize Earthquakes with Plotly Dash — Environmental scan of alternatives to Dash followed with a tutorial.
ARGO Labs — Plotly Dash Tutorial (Video) — Detailed introduction to creating interactive dashboards.
Data Visualization GUIs with Dash and Python (Video playlist) — Five-part series exploring Dash features.
*From the Awesome Dash Github page.
Essentially, Dash apps are composed of two parts: (1) the “layout” of the app that describes the look and feel of the app, and (2) the “callbacks” that enable the apps to be interactive.
A simple Dash App Layout is presented in the user guide and reproduced below:Code Block 2: Simple Dash App LayoutThe dashboard which I describe in this tutorial splits up the Dash app into different files and enables one to build a multi-page app.
There is an “index” page which renders different pages, or layouts, depending the URL.
Each individual layout consists of several different Dash components, including a date range picker, data tables, a download link, and several graphs.
Each of these components is related to one or more “callbacks” that enable the dashboard to be interactive.
A user can interact with one of the Dash components (e.
, change the date range) and the other components reflect this change (e.
, cause the data presented in the data tables to change).
A schematic of this approach is in the following diagram:6.
Building a Multi-page ApplicationThe structure of multi-page Dash application, based upon the Dash documentation at https://dash.
ly/urls, with slight tweaks, is presented below:Code Block 3: File Structure of a Multi-page Dash AppThe file app.
py simply has the following:Code Block 4: app.
pyNote that I am using the dash authentication module (https://dash.
This has some implications which I will go into below.
Building the Index PageThe index.
py file essentially defines the URL page structure of the app by defining a function display_page, which determines what page layout should be rendered depending upon the app URL.
Code Block 5: index.
pyThis is very similar to the index.
py page in the Dash Vanguard Report at https://github.
com/plotly/dash-vanguard-report, with a demo at (https://dash-gallery.
However, I had to include the line from app import server, in order to overcome an issue when I deployed the app on Heroku (see https://community.
ly/t/nolayoutexception-on-deployment-of-multi-page-dash-app-example-code/12463 for details).
Customizing the Page Title and FaviconIn addition, I wanted to customize the app’s HTML index template, specifically, the page title and the favicon.
In order to do so, I added the following index_string: to index.
py:Code Block 6: index_string in index.
py FileIn order to order to customize the favicon, the favicon.
ico image can be placed in the assets directory.
Overview of the Page LayoutThe callback in the index.
py file takes as input the app URL and outputs different layouts depending upon the layout:Code Block 7: Callback in index.
py FileThe layouts.
py file contains the following:Normal python import statementsStatement to read in the data CSV file into pandas data frameDefinition of the data table columns needed in the different variations of the layoutsDefinition of each page layout sectionDefinition of thenoPage layoutThe beginning of the layouts.
py file is as follows:Code Block 8: Beginning of layouts.
py FileEach page layout section contains the following elements:Call to Header() which is imported, so one can have common elements (logo, brand name, etc.
) across multiple apps.
Data Range elementHeader BarRadio Button to select condensed vs.
complete data frameFirst data tableDownload buttonSecond data tableGraphsA simplified code block for one layout section in the layouts.
py is below:Code Block 9: Section of layouts.
py to render Paid Search PageThe above code does not include conditional formatting, which I will go into below.
Local Testing of the AppFollowing the user guide, after one has created the index.
py and app.
py files, one invokes the app with$ python app.
Running on http://127.
1:8050/ (Press CTRL+C to quit)and visit http:127.
1:8050/cc-travel-report/paid-search/ in your web browser.
Building the Date Selector ElementThe date selector element provided a means to update the data presented in both data tables, as well as the downloaded data link.
I also wanted the date selector to provide feedback on the dates selected by the user.
I simply chose January 1, 2018 as the minimum date allowed (min_date_allowed); The maximum date allowed was based upon the maximum date in the CSV data file (max_date_allowed); the initial month presented in the date selected was based upon the maximum date in the CSV data file (initial_visible_month); the initial start date was the maximum date minus 6 days (start_date); and the initial end date was the maximum date.
The following code is located in the layouts.
py file and needs to be repeated for each “page” of the Dashboard app.
Code Block 10: Html Element for Date Picker in layouts.
py FileI used a callback and a function, update_output to provide feedback to the user.
Specifically, I wanted to provide text feedback on the dates selected, the number of days selected, as well as the dates in the corresponding previous period.
For instance, if a user had selected week numbers 5 and 6 of 2019 using the date range selector, then the corresponding past period would be week numbers 3 and 4 of 2019.
The update_output function below provides this functionality.
Code Block 11: Callback and Function for Date Picker in layouts.
py fileThe date picker element provides input to the callbacks for the first data table, the second data table, the download link, as well as the set of graphs below the data tables.
I will go into detail how each of these callbacks work, with their associated outputs.
Adding a correction to CSS so that the Date Picker is not hidden behind the data tablesOne issue I had to correct was that the data tables obscured the date picker element, so I had to correct the CSS accordingly.
Code Block 12: CSS for change z-index of data table in custom.
Building the First Data TableThe first data table in the dashboard presents metrics such as spend (the cost associated with a given advertising product), website sessions, bookings (transactions), and revenue.
These metrics are aggregated depending upon the dates selected in the date selected and typically present data for the current year for the date range selected, data for the previous corresponding period, data for last year, as well as percent and absolute differences between these periods.
Changing the Dates Presented in the Data Table based upon the Date SelectionThe main functionality I wanted for the first data table is making it interactive, whereby the data presented changes according in the date selected.
To start with, the data table element needs to be included in the layouts.
py file as in the (simplified) code below:Code Block 13: Data Table Component in layouts.
py FileThe different parameters for the data table include:id : identifier so that the data table can be referenced by the callbacks.
columns : the columns presented in the table; deletable gives the ability of the user to delete the column while using the app.
editable=True gives the user the ability to change the data in the table while using the app.
n_fixed_columns=2 freezes the first two columns (the checkboxes and the placement type in our case), so when a user scrolls across the complete data table, the user can still view the check boxes and the placement type.
style_table allows CSS styles to be applied to the table.
row_selectable='multi' allows the user to select multiple rows via the checkboxes.
This will enable updating of the graphs below based upon the selection.
selected_rows=0 contains the index of the rows that are selected initially (and presented in the graphs below).
style_cell allows CSS styles to be applied to the table cells.
I will add additional parameters in a subsequent step so we can have conditional style formatting.
Number formatting such as dollar signs, commas, and percent signs are added in pandas and defined as a series of formatters.
I should note that I do not specify the data parameter for the data table in the layouts.
Rather, the data parameter for the data table will come from the callback:Code Block 14: Callback for First Data Table in layouts.
py FileCalculating Changes in the Metrics, as well as the calculating cost-per-session, conversion rate, and cost-per-acquisition.
Since we need to calculate changes in the metrics, as well as CPA, CPS, and conversion rate depending upon the dates selected “on-the-fly,” I push these calculations into a separate file, functions.
I can then re-use these functions for the different Dashboard pages.
I also define formatting functions in this file:Code Block 15: Data Formatters in functions.
py fileThe functions for both the first data table and the second data table are similar so I only present one here:Code Block 16: update_first_datatable Function in functions.
pyThe flow between the data table element, the callback and the function can be portrayed as:A method to select either a condensed data table or the complete data table.
One of the features that I wanted for the data table was the ability to show a “condensed” version of the table as well as the complete data table.
Therefore, I included a radio button in the layouts.
py file to select which version of the table to present:Code Block 17: Radio Button in layouts.
pyThe callback for this functionality takes input from the radio button and outputs the columns to render in the data table:Code Block 18: Callback for Radio Button in layouts.
py FileThis callback is a little bit more complicated since I am adding columns for conditional formatting (which I will go into below).
Essentially, just as the callback below is changing the data presented in the data table based upon the dates selected using the callback statement,Output('datatable-paid-search', 'data', this callback is changing the columns presented in the data table based upon the radio button selection using the callback statement, Output('datatable-paid-search', 'columns'.
Conditionally Color-Code Different Data Table cellsOne of the features which the stakeholders wanted for the data table was the ability to have certain numbers or cells in the data table to be highlighted based upon a metric’s value; red for negative numbers for instance.
However, conditional formatting of data table cells has three main issues.
There is lack of formatting functionality in Dash Data Tables at this time.
If a number is formatted prior to inclusion in a Dash Data Table (in pandas for instance), then data table functionality such as sorting and filtering does not work properly.
There is a bug in the Dash data table code in which conditional formatting does not work properly.
I ended up formatting the numbers in the data table in pandas despite the above limitations.
I discovered that conditional formatting in Dash does not work properly for formatted numbers (numbers with commas, dollar signs, percent signs, etc.
Indeed, I found out that there is a bug with the method described in the Conditional Formatting — Highlighting Cells section of the Dash Data Table User Guide:Code Block 19: Conditional Formatting — Highlighting CellsThe cell for New York City temperature shows up as green even though the value is less than 3.
* I’ve tested this in other scenarios and it seems like the conditional formatting for numbers only uses the integer part of the condition (“3” but not “3.
The filter for Temperature used for conditional formatting somehow truncates the significant digits and only considers the integer part of a number.
I posted to the Dash community forum about this bug, and it has since been fixed in a recent version of Dash.
*This has since been corrected in the Dash Documentation.
Conditional Formatting of Cells using Doppelganger ColumnsDue to the above limitations with conditional formatting of cells, I came up with an alternative method in which I add “doppelganger” columns to both the pandas data frame and Dash data table.
These doppelganger columns had either the value of the original column, or the value of the original column multiplied by 100 (to overcome the bug when the decimal portion of a value is not considered by conditional filtering).
Then, the doppelganger columns can be added to the data table but are hidden from view with the following statements:Code Block 20: Adding Doppelganger ColumnsThen, the conditional cell formatting can be implemented using the following syntax:Code Block 21: Conditional Cell FormattingEssentially, the filter is applied on the “doppelganger” column, Revenue_YoY_percent_conditional (filtering cells in which the value is less than 0).
However, the formatting is applied on the corresponding “real” column, Revenue YoY (%).
One can imagine other usages for this method of conditional formatting; for instance, highlighting outlier values.
The complete statement for the data table is below (with conditional formatting for odd and even rows, as well highlighting cells that are above a certain threshold using the doppelganger method):Code Block 22: Data Table with Conditional FormattingI describe the method to update the graphs using the selected rows in the data table below.
Building the Download Data linkFigure 7: Download data linkOne of the features I wanted for the dashboard was the ability to download the data that was presented in the data tables.
Specifically, I wanted the downloaded data to be updated according to the dates selected (and presented in the data tables).
In addition, since the dates are not displayed, it was necessary to add the dates to the downloaded file.
Moreover, even though the data is formatted in the data tables (with $, % , and thousand comma separators, I wanted the downloaded data to be free of formatting.
There were two critical Plotly community threads which helped me to build this functionality at Allow users to dowload [sic] an Excel in a click and Allowing users to download CSV on click.
The download data functionality was implemented using the following:There is simply a placeholder for the download button in the layouts.
Code Block 23: Placeholder for Download ButtonYou will need the following modules for the download link to work properly:Code Block 24: Import Statements to Enable Download FunctionalityThe callback for the excel download is placed in the callbacks.
The callback is taking the start_date and the end_date from the date picker element and outputting a file reference to the download link.
The update_link function is updating the URL link to serve, based upon the start and end dates.
The function download_excel_1 takes the URL value and splits it up back into start_date and end_date so that I can name the filename based upon the start and end dates, as well as the current date.
Code Block 25: Callback and function for excel download data linkThe function download_excel_1 also calls another function, update_first_download, which is very similar to the update_first_download function presented above, except that the data is not formatted.
The downloaded Excel file is named according to the product name and the start and end dates selected, as well as the current date.
Columns for the start and end dates and other appropriate dates are added to the downloaded data file.
Building the Second Data TableThe second data table featured metrics such as cost-per-session, conversion rate and and cost-per-session which are calculated “on-the-fly,” depending upon the dates selected in the date range selected.
The second data table is created is a similar manner to the first data table so the details are left out of this tutorial, but the complete files are on Github.
Updating Graphs by Selecting Rows in a Dash Data tableFigure 10: Digital Marketing Metric GraphsThe graphs below the data tables display metrics aggregated by week, and include the current year’s data, last year’s data, as well as the percentage changes between the two.
The steps to update the graphs are:Set placeholder in the layouts.
Create callback for each set of graphs, for each page of the Dashboard in the callbacks.
Build a function which filters the complete list of products by the list of products selected in the Dash data table, and subsequently creates a pandas data frame based upon this selection.
The filtered data frame is then passed to another function, update_graph that (a) calculates metrics such as cost-per-session, conversion rate and cost-per session, and (b) produces the output for the graphs.
These steps are detailed below.
Step 4 is detailed in Section 12, “Updating the Graphs and Calculating metrics on the fly.
”Step 1In the layouts.
py file, there is simply a placeholder for the graphs:Code Block 26: Placeholder for GraphsStep 2There is a callback for each set of graphs on each page in the callbacks.
py file:Code Block 27: Callback for GraphsThe callback takes input from the first data table, as well as input from the date picker, and outputs to the dcc.
Graph element with the id, paid-search.
Step 3One of the challenges I had had was to figure out a way of updating the graphs depending upon the products selected in the data table.
In the code for the first data table, it was necessary to set the parameters for row_selectable to multi and selected_rows=.
The former parameter enables checkboxes next to each row in the data table, whereas the latter parameter ensures that the selected rows has an initial value.
The parameter, n_fixed_columns freezes the first two rows in the data table so that they are visible when a user enables the complete data frame, (thus exposing all of the available columns).
Here is a simplified code block for the first data table (which is in the layouts.
py file):Code Block 28: Simplified Data Table DefinitionHence, the callback for the graphs acquire the selected_rows.
In the function to update the graphs, update_paid_search, a list of products is built by filtering the original data frame by the dashboard page category (Paid Search in this case) and getting a complete list of unique placement types.
Then, a for loop filters this list by the list of products selected in the data table.
Subsequently, a filtered data frame, filtered_df is created by filtering the original data frame by the list of selected products and performing a pandas groupby and summing the spend, sessions, bookings and revenue columns.
The callback and function, update_paid_search, for the graphs is presented below:Code Block 29: Callback and Update Function for Graphs12.
Updating the Graphs and Calculating metrics on the flyThe graphs for each metric are aggregated by week and by the products that are selected in the data table (as detailed above).
The features I wanted for the graphs and for the update function included:Since the graphs can depict metrics on more than one product at a time, the update function needs to calculate the metrics on-the-fly.
The graph for each metric should include the value for this year, the value for last year, as well as the year-to-year percentage difference.
These should be overlaid on the same graph, with the values being line graphs, and the year-to-year change being bar graphs.
I wanted the zoom function to work across all of the graphs simultaneously, such that zooming in on one graph, zooms in the other graphs at the same zoom level.
The complete update_graph function (which resides in the functions.
py file is below:Code Block 30: update_graph Function in functions.
py FileIn order to “group” the graphs together, I utilized the subplot capability of Plotly detailed at https://plot.
The update_graph function has the following main elements:On-the-fly calculation of the metrics.
Each graph “trace” is defined using the graph_objs method in the Plotly library (remember to import this method viaimport plotly.
graph_objs as go).
Specifically, each graph is defined with the go.
Scatter method:Code Block 31: Trace Assignment for each Graph elementThe main graph figure and its parameters are defined when we call tools.
During app development, I found that potential sources of error are not remembering to change the number of rows when you add additional traces ( rows=6) , as well as ensuring that you have the same number of titles as the number of graphs.
Both of these might cause the app to fail.
Code Block 32: make_subplots To Set Parameters for SubplotsThe different subplot “traces” are appended to the main graph figure with the statements such as fig.
append_trace(sessions_ty, 1, 1), where sessions_ty is the trace name defined above; the first number, 1 is the graph number and the last number is the column number (which is 1 in every case since we only have one column).
I have included commented-out numbers for each trace in order to assist me in the next step.
Code Block 33: Appending Trace to the FigureIn order to overlay the year-to-year changes, I had to have several update statements, as well as adding new y-axes for each overlaid graph (the year-to-year change graphs).
The syntax required for these overlaid graphs was a little tricky.
Code Block 34: Code to Overlay Year-to-Year Change GraphsFor instance, in the first update statement, the index number 2 in the statement fig['data'] refers to the third trace, sessions_yoy (since Python is zero-indexed).
The following figure hopefully assists in visualizing the indexing of the various elements of the combined graph.
Figure 12: Schematic of the Different Axis IndexesThe y-axis name, y7, in the statement yaxis='y7' needs to be 7 since there are already 6 y-axes (one for each metric: sessions, spend, bookings, cpa, cps, and cr.
For each metric, this year’s and last year’s data shares the same left y-axis).
Hence, we need start numbering the right-side y axes at 7.
We need to assign the parameter for each of the additional y-axes using the fig['layout']['yaxis'] statements.
Specifically, the first right-side axis for the year-to-year changes in sessions overlaps with the other session traces in the first graph.
Hence, we need to assign the parameters accordingly: overlaying='y1', anchor='x1' and, of course, we need to assign it to the right side by setting side='right'.
In addition, I update the title of the set of the graphs with the following:Code Block 35: Update Title of GraphsFinally, I need to update the overall figure layout with the following statement.
I should note that there are several parameters below which are commented out since I am still experimenting with different parameters.
Code Block 36: Update Overall Figure Layout13.
Plotly Graph ToolsI should note that there are several helpful tools available in Dash to manipulate the graphs.
If you hover over the top right-side of the graph figure, you can view these tools.
Figure 13: Plotly Graph ToolsWith these tools you can:Drag to zoom in and double-click to return to the original graph.
Drag the corners of a graph to zoom along one axis.
Double-click to autoscale a single axis.
Change the hover mode to compare data or investigate a single data point.
Certainly, one of the nicest tools is the ability to download a pic of the graph:Figure 14: Downloaded image of the graphs14.
Deploying the DashboardI essentially followed the Deploying Dash Apps guide in the Dash User Guide, with a few changes.
Specifically, I deployed the Dashboard on Heroku using the following steps:Step 1: I had already created a folder for the my dashboard code in a previous step.
Code Block 37: Mkdir and cd CodeStep 2: Initialize the folder with git .
Rather than use venv, I had previously set up a conda environment for Dash.
Code Block 38: Init Git and Active Dash Conda EnvironmentAnd I had either installed the app’s dependencies using either conda or pip:Code Block 39: Pip Installation of Dash and other ModulesYou will also need a new dependency, gunicorn, for deploying the app (line 10 in the above code segment).
Step 3: Initialize folder with an app ( app.
py), a .
gitignore file, a requirements.
txt file, and a Procfile file for deployment.
We only need a minimal app.
py since we are defining our app using multiple files.
You need to create the following files in your project folder.
pyCode Block 40: app.
py file (previously created).
gitignoreCode Block 41: .
gitignore fileAnd aProcfile file:Code Block 42: Procfile fileYou also need to generate a requirements.
You can do this with:Code Block 43: Create new requirements.
txt fileStep 4: Initialize Heroku, add files to Git, and Deploy.
Prior to initializing Heroku, you need to install the Heroku Command Line Interface (CLI) either with their installer available at https://devcenter.
com/articles/heroku-cli or, on a Mac, using homebrew: brew tap heroku/brew && brew install heroku.
Code Block 44: Initialize Heroku and DeployYou should be able to view your app at https://my-dash-app.
com (changing my-dash-app to the name of your app).
Step 5: Update the code and redeploy.
When you modify any element of your app, you will need to add the changes to git and push those changes to Heroku.
Also, whenever I change the underlying CSV data file, you need to push the new data set to Heroku.
Code Block 45: Pushing changes to Heroku via GitI should note that if you have issues deploying to Heroku, try deploying a simply app first and test whether you are doing each step correctly.
For instance, I found that I needed to add the following to the index.
py file in order for the Heroku deployment to work: from app import server.
Resolving an Issue with Custom.
css File and AuthenticationIn addition, I found that when I added authentication to my app, the app could no longer access my custom.
css file, so I needed to create a css file on codepen.
io and include it in the list of external css files (I am assuming that this is a bug in Dash).
Dash Deployment ServerPlotly also offers a Dash Deployment Server…for easy app deployment in commercial IT environments, get started with support plans and workshops for mission critical projects, or contract our world-class engineering team for custom feature development or proof of concept app development.
I should note that I have no affiliation with Plotly.
Wrapping upFrom start to finish, the project took about two and half weeks.
I had not previously used Dash and had limited experience using Plotly.
Some of the methods which I employed to build the dashboard included:Building minimal parts of the dashboard first.
Basically, I do not try to tackle everything at once.
I built element at a time, and often by itself, before adding it to the entire dashboard.
To ensure that I got my python syntax correct, I used a Jupyter notebook with the original data frame and applied each change in a piecewise fashion.
I would make small incremental changes to the app and then test.
Rinse and repeat.
I developed one section first and got it working and to my liking.
Then I would copy and paste this section to the other sections and make appropriate changes.
I saved deployment for the last step.
I tested everything locally.
Some things on my wish list to update the Dashboard include:Add weeks to each graph axis, most likely using annotations.
Have the graph x-axis cross over years, rather than just depict either 2018 or 2019.
Add a “print PDF” button for the report.
I tried to implement one but haven’t been able to get it working yet.
Add a footer with metadata (data sources, date data was pulled, where it was pulled from, etc.
)Thanks for reading this far.
I know it is a little overwhelming, but I essentially broke things down into manageable pieces.
Resources for DashHere are some resources to help you further with Dash:Dash User GuideUdemy Course (I have not taken this online course so I cannot comment on it though.
Dash Community ForumAwesome Dash Resource Guide on Github.