Nat  Grady

Nat Grady

1670915040

How to Create a Live Dashboards with Airtable and React

Reporting and visualizing data is crucial to businesses of all sizes. Dashboards allow users to efficiently access and use this data for a range of business operations. In this article, Toptal Full-stack Engineer Dylan Golow demonstrates how he created a powerful dashboard for telemedicine using Airtable, Typeform, and React.

Whether a company is a large enterprise or a budding startup, collecting data from users and customers, and reporting on or visualizing that data is crucial to the business.

I recently worked with a telemedicine startup based in Brazil. Its mission is to provide remote care and monitoring by connecting patients to medical professionals and health coaches. The core need was to create an interface for the coaches and health professionals to easily review a patient’s information and most important metrics related to their particular situation: a dashboard.

Enter Typeform and Airtable.

Typeform

Typeform is one of the go-to data collection tools that enables responsive web experiences for users completing a survey. It also comes with several features that make surveys more intelligent, especially when combined:

  • Logic Jumps
  • Hidden Fields

Surveys can be shared via URLs that can be pre-seeded with values for the hidden fields, which can then be used to implement logic jumps and alter the behavior of the survey for the user with the link.

Airtable Uses

Airtable is a spreadsheet-database hybrid and a collaborative cloud platform. Its focus on point and click functionality means that non-technical users can configure it without coding. Airtable has a multitude of use cases in any business or project.

You can use an Airtable Base for:

  • CRM (Client Relationship Management)
  • HRIS (Human Resources Information System)
  • Project Management
  • Content Planning
  • Event Planning
  • User Feedback

There are many more potential use cases. You can explore Airtable case studies here.

If you are not familiar with Airtable, the conceptual data model breaks down like this:

  • Workspace - Composed of Bases
  • Base - Composed of Tables
  • Table - Composed of Fields (columns) and rows
  • View - A perspective on Table data with optional filters and reduced Fields
  • Field - A column of a Table with a Field Type; see here for more information on Field Types

Apart from providing a cloud-hosted database with familiar spreadsheet features, here are some of the reasons the platform is so powerful:

 

Depiction of technical and non-technical users working with Airtable.

 

For non-technical users, Airtable provides:

  • An easy to use front-end interface
  • Automations that can be created with point-and-click configuration to send emails, process rows of data, schedule appointments in calendars, and more
  • Multiple types of views that allow teams to collaborate on the same Base and tables
  • Airtable Apps that can be installed from the marketplace to supercharge a Base

For developers, Airtable provides:

  • A well-documented back-end API
  • A scripting environment that allows developers to automate actions within a Base
  • Automations that can also trigger custom developed scripts that run within the Airtable environment, extending the capabilities of automations

You can learn more on Airtable here.

Getting Started: Typeform to Airtable

Typeform surveys were already configured by the client, and the next step was to plan how that data would land in Airtable and then be turned into a dashboard. There are many questions to consider when creating dashboards on top of any database: How should we structure the data? What data will need to be processed prior to visualization? Should we sync the Base with Google Sheets and use Google Data Studio? Should we export and find another third-party tool?

Fortunately for developers, not only does Airtable provide automations and scripting to handle the data processing steps, but it has also made it possible to build custom applications and interfaces on top of an Airtable Base with Airtable Apps.

Custom Apps in Airtable

Custom Apps in Airtable have been around since the Airtable Blocks SDK was released at the beginning of 2018, and were recently renamed to Apps. The release of Blocks was huge in that it meant that creators now had the ability to develop, as Airtable puts it, “An infinitely recombinable Lego kit.”

More recently with the change to apps, the Airtable Marketplace made it possible to share apps publicly, as well.

Airtable Apps provide businesses with an infinitely recombinable Lego kit they can tailor to their needs.

In order to build a custom app in Airtable, a JavaScript developer must know how to use React, one of the most popular JavaScript libraries for building user interfaces. Airtable provides a component library of functional React components and hooks, which are a huge help for rapidly building a consistent UI and determining how you will manage state within the app and its components.

Check out Airtable’s Getting Started article for more information and Airtable on GitHub for examples of apps.

Airtable Dashboard Requirements

After reviewing the dashboard mockups with the client team, the types of data to be used were clear. We would need a series of dashboard components that would display as text on the dashboard and charts of different metrics that could be tracked over time.

Coaches and medical professionals needed to be able to build a custom dashboard for each patient, so we needed a flexible way to add and remove charts. Other static data relative to each patient would be displayed no matter the patient selected.

In this case, the dashboard sections boiled down to:

  • General Information - Patient Name, Email, Phone Number, Contact Preference, Date of Birth, Age
  • Objectives - Goals the patient has based on survey results
  • Some Stats - BMI, Height, and Weight
  • Medicine Use - Listing all prescription drugs already used by a patient
  • Family History of Conditions - Helpful in diagnosing certain conditions
  • Charts - A section where the Airtable dashboard user could add a chart and configure which metric it would visualize over time

 

Image showing an Airtable Dashboard mockup.

 

One way to approach all of the sections except for charts would be to hard-code all the columns for objectives, medicine use, and family history into the dashboard. However, that would not allow the client team to add new questions to a Typeform survey nor add a new column to an Airtable table to present that data on the dashboard without having a developer update the custom app.

A more elegant and extensible solution to this challenge was finding a way to tag columns as relevant to a particular dashboard section and retrieve those columns using the metadata that Airtable exposes when using the Table and Field models.

This was achieved using Field Descriptions as a place to tag a column from the Table as relevant to a dashboard section to be displayed to the user. Then, we could ensure only those with the Creator role (the administrators) for the Base had the ability to modify these Field Descriptions to alter what appears on the dashboard. To illustrate this solution, we will focus mostly on the items in General Information and how to present Charts.

Creating a #TAG# System

Given the dashboard sections, it made sense to make reusable tags for some sections and specific tags for certain columns. For items like patient name, email, and phone number, #NAME#, #EMAIL#, and #PHONE# were added to each Field’s description, respectively. That would allow that information to be retrieved via the Table metadata like this:

const name = table ? table.fields.filter(field => field.description?.includes("#NAME#"))

For areas of the dashboard that would need to draw from many tagged columns we would have the following tags for each dashboard section:

  • OBJ - Objectives
  • FAM - Family History
  • MED - Medicine Usage
  • CAN - Family History specific to cancer
  • CHART - Any column that should be sourced for adding charts; must be a quantity

In addition, it was important to separate the name of a column in a Table from the label it would receive on the dashboard, so anything that received a #TAG# would also have the ability to receive two #LABEL# tags in its Field Description. A Field Description would look like this:

 

Screenshot showcasing the use of tags in a field description.

 

In case the #LABEL# tags are missing, we will display the column name from the Table.

We can parse out the label set in the description with a simple function like this after retrieving the field with the previous code example:

// utils.js

export const setLabel = (field, labelTag = "#LABEL#") => {
   const labelTags = (field.description?.match(new RegExp(labelTag, "g")) || []).length;
   let label;
   if (labelTags === 2) label = field.description?.split(`${labelTag}`)[1];
   if (!label || label?.trim() === '') label = field.name;
   return {...field, label, name: field.name, description: field.description};
}

With this #TAG# system, we achieve three main things:

  • Column names (fields) in the Table can be changed as desired.
  • Labels for data in the dashboard can be distinct from column names.
  • Dashboard sections for Objectives, Medicine Usage, Family History, and Charts can be updated by the client team without touching a line of code.

Persisting State in Airtable

In React, we use state and pass it to components as props in order to re-render that component if its state changes. Normally this is tied to an API call that fuels a dashboard component, but in Airtable we already have all the data and simply need to filter what we are displaying based on which patient we are viewing. In addition, if we use state, it will not persist the data past a refresh in the dashboard itself.

So, how can we persist a value past refresh to keep a dashboard filtered? Fortunately, Airtable provides a hook for this called useGlobalConfig in which it maintains a key-value store for an app installation on a dashboard. We simply need to implement the logic of retrieving values from this key-value store when the app loads to fuel our dashboard components.

What is even more useful about using the useGlobalConfig hook is that when its values are set, the dashboard component and its child components re-render, so you can use the Global Config like you would use a state variable in a typical React implementation.

Introducing Charts

Airtable provides examples of charts with its Simple Chart App, which uses React Charts, a React wrapper on Chart.js (chart-ception).

In the Simple Chart App, we have one chart for the whole app, but in our Dashboard App, we need the ability for the user to add and remove their own charts from their own dashboard. What’s more, in discussion with the client team, it seems that certain metrics would be better viewed on the same chart (like readings for diastolic and systolic blood pressure).

With this we have the following items to tackle:

  • Persisting state for each user’s chart (or even better using Global Config)
  • Allowing multiple metrics per chart

This is where the power of the Global Config comes in handy, as we can use the key-value store to maintain the selected metrics and anything else about our list of charts. As we configure a chart in the UI, the chart component itself will be re-rendered due to updates to the Global Config. For the charting section of the dashboard, here is a gist with the components for reference, focusing on dashboard charts.js and single chart.js.

The table passed to each chart is what is used for its metadata to find the fields, whereas the records passed have already been filtered by the patient selected at the top-level dashboard component that imports dashboard_charts/index.js.

Note that the fields listed as options in the dropdown for a chart are pulled using the #CHART# tag we mentioned before, with this line in a useEffect hook:

// single_chart/index.js

…
useEffect(() => {
  (async () => {

...

    if (table) {
      const tempFieldOptions = table.fields.filter(field =>    
        field.description?.includes('#CHART#')).map(field => {
          return {
            ...setLabel(field),
            value: field.id
          }
       });
       setFieldSelectOptions([...tempFieldOptions]);
    }
  })();
}, [table, records, fields]);


...

The code above shows how the setLabel function referenced earlier is used with the #TAG# to add anything provided in the #LABEL# tags and display it for the option in the field dropdown.

Our chart component takes advantage of the multi-axis capabilities provided by Chart.js, which is shown with React Charts. We just extended it via the UI with the user’s ability to add a dataset and a chart type (line or bar).

The key to using Global Config, in this case, is to know that each key can only hold a string | boolean | number | null | GlobalConfigArray | GlobalConfigObject (see Global Config Value reference).

We have the following items to maintain per chart:

  • chartTitle which is autogenerated and can be renamed by the user
  • fields array in which each item has:
    • field as fieldId from Airtable
    • chartOption as one line | bar as the Chart.js docs indicate
    • color as the Airtable color from the colorUtils
    • hex as the hex code relating to the Airtable color

To manage this, I found it most convenient to stringify this data as an object instead of setting Global Config keys and values all the way down. See the example below (globalConfig.json in the gist), which includes Global Config values to filter records by the patient and some related variables used to support a typeahead filtering component (thanks to react-bootstrap-typeahead):

{
 "xCharts": {
   "chart-1605425876029": "{\"fields\":[{\"field\":\"fldxLfpjdmYeDOhXT\",\"chartOption\":\"line\",\"color\":\"blueBright\",\"hex\":\"#2d7ff9\"},{\"field\":\"fldqwG8iFazZD5CLH\",\"chartOption\":\"line\",\"color\":\"blueLight1\",\"hex\":\"#9cc7ff\"}],\"chartTitle\":\"Gráfico criado em 11/15/2020, 2:37:56 AM\"}",
   "chart-1605425876288": "{\"fields\":[{\"field\":\"fldGJZIdRlq3V3cKu\",\"chartOption\":\"line\",\"color\":\"blue\",\"hex\":\"#1283da\"}],\"chartTitle\":\"Gráfico criado em 11/15/2020, 2:37:56 AM\"}",
   "chart-1605425876615": "{\"fields\":[{\"field\":\"fld1AnNcfvXm8DiNs\",\"chartOption\":\"line\",\"color\":\"blueLight1\",\"hex\":\"#9cc7ff\"},{\"field\":\"fldryX5N6vUYWbdzy\",\"chartOption\":\"line\",\"color\":\"blueDark1\",\"hex\":\"#2750ae\"}],\"chartTitle\":\"Gráfico criado em 11/15/2020, 2:37:56 AM\"}",
   "chart-1605425994036": "{\"fields\":[{\"field\":\"fld9ak8Ja6DPweMdJ\",\"chartOption\":\"line\",\"color\":\"blueLight2\",\"hex\":\"#cfdfff\"},{\"field\":\"fldxVgXdZSECMVEj6\",\"chartOption\":\"line\",\"color\":\"blue\",\"hex\":\"#1283da\"}],\"chartTitle\":\"Gráfico criado em 11/15/2020, 2:39:54 AM\"}",
   "chart-1605430015978": "{\"fields\":[{\"field\":\"fldwdMJkmEGFFSqMy\",\"chartOption\":\"line\",\"color\":\"blue\",\"hex\":\"#1283da\"},{\"field\":\"fldqwG8iFazZD5CLH\",\"chartOption\":\"line\",\"color\":\"blueLight1\",\"hex\":\"#9cc7ff\"}],\"chartTitle\":\"New Chart\"}",
   "chart-1605430916029": "{\"fields\":[{\"field\":\"fldCuf3I2V027YAWL\",\"chartOption\":\"line\",\"color\":\"blueLight1\",\"hex\":\"#9cc7ff\"},{\"field\":\"fldBJjtRkWUTuUf60\",\"chartOption\":\"line\",\"color\":\"blueDark1\",\"hex\":\"#2750ae\"}],\"chartTitle\":\"Gráfico criado em 11/15/2020, 4:01:56 AM\"}",
   "chart-1605431704374": "{\"fields\":[{\"field\":\"fld7oBtl3iiHNHqoJ\",\"chartOption\":\"line\",\"color\":\"blue\",\"hex\":\"#1283da\"}],\"chartTitle\":\"Gráfico criado em 11/15/2020, 4:15:04 AM\"}"
 },
 "xPatientEmail": "elle@gmail.com",
 "xTypeaheadValue": "Elle Gold (elle@gmail.com)",
 "xSelectedValue": "[{\"label\":\"Elle Gold (elle@gmail.com)\",\"id\":\"elle@gmail.com\",\"name\":\"Elle Gold\",\"email\":\"elle@gmail.com\"}]"
}

Note: All data contained above, and the data included in the animations below, are not real patient data.

Here’s a look at the final result:

 

Animated display of Airtable dashboard UI.

 

What About the Typeahead?

In order to filter by patient, we needed a way to select a patient and then filter the records based on this patient. In this section, we review how this was achieved.

For the typeahead, react-bootstrap-typeahead was an easy choice, as the only steps left were preparing the options for the typeahead, mixing it with an Airtable input for styling and loading bootstrap, and some other styles for our menu. Dropping components from your favorite component libraries into an Airtable app is not as straightforward as in typical React web development; however, there are only a few extra steps to get everything to look the way you would expect.

Here is the final result:

 

Animated GIF showcasing the filter-by-patient functionality.

 

To render the Airtable input and keep all our styles consistent, react-bootstrap-typeahead comes with a renderInput prop. See more on how to modify the rendering of the component here.

For the bootstrap styles and to override our menu items, the following two utils were used from Airtable:

See frontend.js in the gist for an excerpt of the typeahead implementation.

This line was used to load bootstrap globally:

// frontend/index.js

loadCSSFromURLAsync('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css');

You will notice some added logic for things like handling style changes on hover or restyling links (<a></a>) to get the familiar bootstrap look and feel. This also includes the handling of setting the Global Config values for the typeahead and filtering of records so that if a user leaves their dashboard, refreshes their page, or would like to share this dashboard with others, the app persists the selected patient in the Dashboard App. This also allows the users to install multiple copies of this same app side by side in the same Airtable Dashboard with different patients selected or with different charts.

Keep in mind that a dashboard in Airtable is also available to all users of the Base, so these custom app installations on a dashboard will be filtered to the same patients and charts no matter which users are looking at the dashboard at the same time.

Let’s recap what we’ve covered for far:

  1. Airtable allows both non-technical users and technical users to collaborate in Airtable.
  2. Typeform comes with an Airtable integration that allows non-technical users to map Typeform results to Airtable.
  3. Airtable Apps provide a powerful way to supercharge its Airtable Base, whether selecting from the marketplace or building a custom app.
  4. Developers can extend Airtable rapidly in nearly any way imaginable with these apps. Our example above took only three weeks to design and implement (with enormous help from existing libraries, of course).
  5. A #TAG# system can be used to modify the dashboard without requiring code changes by developers. There are better and worse use cases for this. Be sure to limit permissions to the Creator role if using this strategy.
  6. Using Global Config allows developers to persist data within an app installation. Mix this into your state management strategy to seed data for your components.
  7. Don’t expect to drag and drop components from other libraries and projects directly into your Airtable App. Styles can be loaded using the loadCSSFromString and loadCSSFromURLAsync utils provided by Airtable.

Future-proofing

Use a more sophisticated middleware

With Typeform and Airtable, it’s easy and cost-effective to configure the mapping of questions to columns.

However, there is one big drawback: If you have a survey of more than 100 questions mapped to Airtable and you need to modify a mapping, you must delete the entire mapping and start again. This is clearly not ideal, but for a free integration, we can deal with this.

Other options would be having a Zapier (or similar) integration manage the data between Typeform and Airtable.Then you could modify the mapping of any question to any column without starting from scratch. This would have its own cost considerations to factor in as well.

Hopefully, some of the lessons learned and communicated here will help others who are looking to build solutions with Airtable.

Finally, you can check out the gist with the files discussed in this article.

Original article source at: https://www.toptal.com/

#react #dashboards 

How to Create a Live Dashboards with Airtable and React

Data Visualizations Tutorial | Web App Dashboards with Python & Dash

Learn how to use Python and Dash library to create, style, and host an interactive data analysis web application.

If not long ago the creation of analytical web applications required knowledge of several programming languages, today you can create a data visualization interface in pure Python. One popular tool for this has become Dash, which allows data scientists to display results in interactive web applications.

In this guide, we’ll cover:

  • How to create a Dash app
  • Main library components
  • How to customize the app style
  • How to make an application interactive
  • How to deploy an application to a remote server (using Heroku as an example)

What is Dash?

Dash is an open-source framework for building data visualization interfaces. After being released in 2017 as a Python library, Dash was soon extended for R and Julia.

The library was created and maintained by a Canadian company called Plotly. Perhaps you know about her from the popular graphics libraries that bear her name. Plotly opened source Dash and released it under the MIT license, so the library is free to use.

Dash is based on and integrates three frameworks:

  1. Flask provides web server functionality.
  2. React renders the web interface.
  3. Plotly.js generates charts.

You don’t have to worry about these technologies working together. You just need to write the code in Python, R, or Julia and add some CSS.

If you are used to analyzing data using Python, Dash is a useful addition to your toolbox. Here are some practical examples of the library’s capabilities:

Setting up a virtual environment

To develop your application, you need a directory to store your code and data, as well as a clean Python 3 virtual environment. To create them, follow the instructions for your operating system.

Windows. Open a command prompt and run the following commands:

mkdir avocado_analytics && cd avocado_analytics
python -m venv venv venv\Scripts\activate.bat

The first command will create a project directory and change the current working directory. The second command will create the virtual environment, and the last command will activate it. You may need to specify a file path to python.exe instead of a command python .

MacOS or Linux. The meaning of the following terminal commands is identical to those for Windows:

mkdir avocado_analytics && cd avocado_analytics
python3 -m venv venv source venv/bin/activate

Next, you need to install the following libraries into the virtual environment:

python -m pip install dash==1.13.3 pandas==1.0.5

The Dash and pandas libraries will be installed in the virtual environment. The virtual environment allows the use of specific versions of the libraries, similar to those used in this tutorial.

Finally, you will need some data that can be downloaded from the accompanying lesson materials.

Save the data file in the root directory of the project. By now, you should have a virtual environment with the required libraries and data in the project root folder. The project structure looks like this: avocado.csv

avocado_analytics/
├── venv/
└── avocado.csv

How to create an app with Dash

Let’s break down the process of creating a Dash application into two steps:

  1. We initialize the application and define the appearance using the application layout ( layout).
  2. We determine through callbacks ( callbacks) which parts of the application are interactive and what they react to.

Initializing the Dash Application

First, let’s create an empty file called app.py. Next, we will fill it out step by step and explain what is happening, and at the end of the section, you will find its entire contents.

Here are the first few lines of app.py:

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

data = pd.read_csv("avocado.csv")
data = data.query("type == 'conventional' and region == 'Albany'")
data["Date"] = pd.to_datetime(data["Date"], format="%Y-%m-%d")
data.sort_values("Date", inplace=True)

app = dash.Dash(__name__)

First, we import the required libraries:

  • dash will help initialize the application
  • dash_core_components allows you to create interactive components: charts, drop-down lists, date ranges, etc.
  • dash_html_components allows you to access HTML tags
  • pandas helps to read and display data in an organized manner

Next, we read the data and process it for use in the control panel. On the last line, we create an instance of the Dash class.

If you’ve used Flask before, then the initialization of the Dash class is already familiar to you. In Flask, we usually initialize a WSGI (short for Web Server Gateway Interface) application with Flask(__name__). For Dash apps, we use Dash(__name__).

Defining the Dash Application Layout

Now we will define the layout of the application, its appearance. In our case, the layout will consist of a title, description and two diagrams.

app.layout = html.Div(
    children=[
        html.H1(children="Avocado Analytics",),
        html.P(
            children="Analyze the behavior of avocado prices"
            " and the number of avocados sold in the US"
            " between 2015 and 2018",
        ),
        dcc.Graph(
            figure={
                "data": [
                    {
                        "x": data["Date"],
                        "y": data["AveragePrice"],
                        "type": "lines",
                    },
                ],
                "layout": {"title": "Average Price of Avocados"},
            },
        ),
        dcc.Graph(
            figure={
                "data": [
                    {
                        "x": data["Date"],
                        "y": data["Total Volume"],
                        "type": "lines",
                    },
                ],
                "layout": {"title": "Avocados Sold"},
            },
        ),
    ]
)

Well, let’s go step-by-step what’s going on here.

This code defines layout property of app object . The appearance of the application is described using a tree structure consisting of Dash components.

We start by defining the parent component html.Div, then add a heading html.H1and paragraph html.Pas children. These components are equivalent to HTML tags div, h1and p accordingly. Component arguments are used to change the attributes or content of tags. For example, to indicate what is inside a div tag , we use in html.Div an argument children.

Components also have other arguments, such as style, className or id that refer to attributes of HTML tags. In the next section, we’ll see how to use these properties to style the toolbar.

Thus, the Python code will be converted to the following HTML code:

<div>
  <h1>Avocado Analytics</h1>
  <p>
    Analyze the behavior of avocado prices and the number
    of avocados sold in the US between 2015 and 2018
  </p>
  <!-- The rest of the app -->
</div>

Next two components of dcc.Graph are described below. The first chart displays the average avocado prices over the study period, and the second shows the number of avocados sold in the US during the same period.

Under the hood, Dash uses Plotly.js to create graphs. The dcc.Graph components expect a figure object or a Python dictionary containing the graph data and layout that we are passing in our case.

There are two lines of code left to help launch the application:

if __name__ == "__main__":
    app.run_server(debug=True,
                   host = '127.0.0.1')

These lines allow you to run your Dash application locally using Flask’s built-in server. The debug = Trueparameter from app.run_server allows hot reloads: when we make changes to the application, it automatically reloads without restarting the server.

Finally, the full version of app.py. You can copy the code to blank app.py and check the result.

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

data = pd.read_csv("avocado.csv")
data = data.query("type == 'conventional' and region == 'Albany'")
data["Date"] = pd.to_datetime(data["Date"], format="%Y-%m-%d")
data.sort_values("Date", inplace=True)

app = dash.Dash(__name__)

app.layout = html.Div(
    children=[
        html.H1(children="Avocado Analytics",),
        html.P(
            children="Analyze the behavior of avocado prices"
            " and the number of avocados sold in the US"
            " between 2015 and 2018",
        ),
        dcc.Graph(
            figure={
                "data": [
                    {
                        "x": data["Date"],
                        "y": data["AveragePrice"],
                        "type": "lines",
                    },
                ],
                "layout": {"title": "Average Price of Avocados"},
            },
        ),
        dcc.Graph(
            figure={
                "data": [
                    {
                        "x": data["Date"],
                        "y": data["Total Volume"],
                        "type": "lines",
                    },
                ],
                "layout": {"title": "Avocados Sold"},
            },
        ),
    ]
)

if __name__ == "__main__":
    app.run_server(debug=True,
                   host = '127.0.0.1')

It’s time to finally ✨launch the application ✨.

Open a terminal in the project root and in the virtual project environment. Run python app.py, then go to the address http://localhost:8050in your browser.

The control panel should look something like this:

We now have a working version, but we will improve it further.

🌟Controlling panel appearance

The reason why I liked Dash is that it becomes very flexible in customizing the look and feel of your application. We can use our own CSS or JavaScript files, embed images, and configure additional options.

How to style Dash components

You can style components in two separate ways:

  • Use a style argument of distinct components.
  • Provide an external CSS file.

The style argument takes a Python dictionary with key-value pairs consisting of the CSS property names and the values ​​we want to set.

When we want to change the size and color of the H1 element in app.py, we can set the style argument like this:

html.H1(
    children="Avocado Analytics",
    style={"fontSize": "48px", "color": "red"},
),

In this case, the title will be formatted in 48 pixels.

The downside to ease of use styleis that code like this will become more difficult to maintain as the codebase grows. If there are several of the same components on the control panel, most of the code will be repeated. You can use a CSS file instead.

If you want to include your own local CSS or JavaScript files, you must create a folder named assets/ in the root directory of the project and save the necessary files in it.

You can then use the className arguments or id of components to style them using CSS. When converted to HTML tags, these arguments match the class and id attributes .

When we want to customize the font size and text color of an H1 element in app.py, we can use an className argument:

html.H1(
    children="Avocado Analytics",
    className="header-title",
),

Setting the argument specifies the className class attribute for the H1element. Then, in the CSS file (style.css) in the assets/ folder, we specify how we want it to look:

.header-title {
  font-size: 48px;
  color: red;
}

How to improve the toolbar appearance

Let’s find out how to customize the appearance of the toolbar. Let’s make the following improvements:

  • Add the site icon ( favicon) and title.
  • Let’s change the font family.
  • We use an external CSS file to style the Dash components.

Adding external resources to the application

Let’s create assets/folder in the root of the project. Save the favicon.ico icon and the style.css.

By now, the project structure should look like this:

avocado_analytics/
├── assets/
│   ├── favicon.ico
│   └── style.css
├── venv/
├── app.py
└── avocado.csv

app.py requires several changes. You need to include an external style sheet, add a title to the toolbar, and style the components using the style.cssfile:

external_stylesheets = [
    {
        "href": "https://fonts.googleapis.com/css2?"
                "family=Lato:wght@400;700&display=swap",
        "rel": "stylesheet",
    },
]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = "Avocado Analytics: Understand Your Avocados!"

Here we specify the CSS file and font family that we want to load into the application. External files are loaded before the application body is loaded. The external_stylesheets argument is used to add external CSS files, and external_scripts is used for external JavaScript files such as a Google Analytics script.

Customizing component styles

In the code below, we add className with the appropriate class selector to each of the components representing the title of the dashboard:

app.layout = html.Div(
    children=[
        html.Div(
            children=[
                html.P(children="🥑", className="header-emoji"),
                html.H1(
                    children="Avocado Analytics", className="header-title"
                ),
                html.P(
                    children="Analyze the behavior of avocado prices"
                    " and the number of avocados sold in the US"
                    " between 2015 and 2018",
                    className="header-description",
                ),
            ],
            className="header",
        ),

The header-description class assigned to the paragraph component has a matching selector in style.css:

.header-description {
    color: #CFCFCF;
    margin: 4px auto;
    text-align: center;
    max-width: 384px;
}

Another significant change is the graphics. New code for the price chart:

html.Div(
    children=[
        html.Div(
            children=dcc.Graph(
                id="price-chart",
                config={"displayModeBar": False},
                figure={
                    "data": [
                        {
                            "x": data["Date"],
                            "y": data["AveragePrice"],
                            "type": "lines",
                            "hovertemplate": "$%{y:.2f}"
                                                "<extra></extra>",
                        },
                    ],
                    "layout": {
                        "title": {
                            "text": "Average Price of Avocados",
                            "x": 0.05,
                            "xanchor": "left",
                        },
                        "xaxis": {"fixedrange": True},
                        "yaxis": {
                            "tickprefix": "$",
                            "fixedrange": True,
                        },
                        "colorway": ["#17B897"],
                    },
                },
            ),
            className="card",
        ),

We removed the default bar that appears on the chart and set the hover pattern so that when you hover over the data point, the price is displayed in dollars. So $2.5 will be displayed instead of 2.5.

We also set up the axis, the color of the picture, the format of the title in the section of the chart layout. We also wrapped the schedule in html.Div with the class card class. This will give the graphic a white background and add a little shadow underneath. Similar changes have been made to the sales and volume schedules. Here is the complete code of the updated app.py:

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
data = pd.read_csv("avocado.csv")
data = data.query("type == 'conventional' and region == 'Albany'")
data["Date"] = pd.to_datetime(data["Date"], format="%Y-%m-%d")
data.sort_values("Date", inplace=True)
external_stylesheets = [
    {
        "href": "https://fonts.googleapis.com/css2?"
        "family=Lato:wght@400;700&display=swap",
        "rel": "stylesheet",
    },
]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = "Avocado Analytics: Understand Your Avocados!"
app.layout = html.Div(
    children=[
        html.Div(
            children=[
                html.P(children="🥑", className="header-emoji"),
                html.H1(
                    children="Avocado Analytics", className="header-title"
                ),
                html.P(
                    children="Analyze the behavior of avocado prices"
                    " and the number of avocados sold in the US"
                    " between 2015 and 2018",
                    className="header-description",
                ),
            ],
            className="header",
        ),
        html.Div(
            children=[
                html.Div(
                    children=dcc.Graph(
                        id="price-chart",
                        config={"displayModeBar": False},
                        figure={
                            "data": [
                                {
                                    "x": data["Date"],
                                    "y": data["AveragePrice"],
                                    "type": "lines",
                                    "hovertemplate": "$%{y:.2f}"
                                                     "<extra></extra>",
                                },
                            ],
                            "layout": {
                                "title": {
                                    "text": "Average Price of Avocados",
                                    "x": 0.05,
                                    "xanchor": "left",
                                },
                                "xaxis": {"fixedrange": True},
                                "yaxis": {
                                    "tickprefix": "$",
                                    "fixedrange": True,
                                },
                                "colorway": ["#17B897"],
                            },
                        },
                    ),
                    className="card",
                ),
                html.Div(
                    children=dcc.Graph(
                        id="volume-chart",
                        config={"displayModeBar": False},
                        figure={
                            "data": [
                                {
                                    "x": data["Date"],
                                    "y": data["Total Volume"],
                                    "type": "lines",
                                },
                            ],
                            "layout": {
                                "title": {
                                    "text": "Avocados Sold",
                                    "x": 0.05,
                                    "xanchor": "left",
                                },
                                "xaxis": {"fixedrange": True},
                                "yaxis": {"fixedrange": True},
                                "colorway": ["#E12D39"],
                            },
                        },
                    ),
                    className="card",
                ),
            ],
            className="wrapper",
        ),
    ]
)
if __name__ == "__main__":
    app.run_server(debug=True)

The panel of the updated version looks like this: app.py

Adding interactive elements to your Dash application

Dash’s interactivity is based on the paradigm of reactive programming. This means that we can link the components and elements of the application that we want to update. If the user interacts with an input component, such as a drop-down list or slider, then the data output object, such as a graph, will automatically respond to input changes.

Let’s make the control panel interactive. The new version will allow the user to interact with the following filters:

  • Production region.
  • Avocado type.
  • Date range.

Let’s start by replacing the local version of app.pywith the new version:

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd
import numpy as np
from dash.dependencies import Output, Input

data = pd.read_csv("avocado.csv")
data["Date"] = pd.to_datetime(data["Date"], format="%Y-%m-%d")
data.sort_values("Date", inplace=True)

external_stylesheets = [
    {
        "href": "https://fonts.googleapis.com/css2?"
        "family=Lato:wght@400;700&display=swap",
        "rel": "stylesheet",
    },
]
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.title = "Avocado Analytics: Understand Your Avocados!"

app.layout = html.Div(
    children=[
        html.Div(
            children=[
                html.P(children="🥑", className="header-emoji"),
                html.H1(
                    children="Avocado Analytics", className="header-title"
                ),
                html.P(
                    children="Analyze the behavior of avocado prices"
                    " and the number of avocados sold in the US"
                    " between 2015 and 2018",
                    className="header-description",
                ),
            ],
            className="header",
        ),
        html.Div(
            children=[
                html.Div(
                    children=[
                        html.Div(children="Region", className="menu-title"),
                        dcc.Dropdown(
                            id="region-filter",
                            options=[
                                {"label": region, "value": region}
                                for region in np.sort(data.region.unique())
                            ],
                            value="Albany",
                            clearable=False,
                            className="dropdown",
                        ),
                    ]
                ),
                html.Div(
                    children=[
                        html.Div(children="Type", className="menu-title"),
                        dcc.Dropdown(
                            id="type-filter",
                            options=[
                                {"label": avocado_type, "value": avocado_type}
                                for avocado_type in data.type.unique()
                            ],
                            value="organic",
                            clearable=False,
                            searchable=False,
                            className="dropdown",
                        ),
                    ],
                ),
                html.Div(
                    children=[
                        html.Div(
                            children="Date Range",
                            className="menu-title"
                            ),
                        dcc.DatePickerRange(
                            id="date-range",
                            min_date_allowed=data.Date.min().date(),
                            max_date_allowed=data.Date.max().date(),
                            start_date=data.Date.min().date(),
                            end_date=data.Date.max().date(),
                        ),
                    ]
                ),
            ],
            className="menu",
        ),
        html.Div(
            children=[
                html.Div(
                    children=dcc.Graph(
                        id="price-chart", config={"displayModeBar": False},
                    ),
                    className="card",
                ),
                html.Div(
                    children=dcc.Graph(
                        id="volume-chart", config={"displayModeBar": False},
                    ),
                    className="card",
                ),
            ],
            className="wrapper",
        ),
    ]
)


@app.callback(
    [Output("price-chart", "figure"), Output("volume-chart", "figure")],
    [
        Input("region-filter", "value"),
        Input("type-filter", "value"),
        Input("date-range", "start_date"),
        Input("date-range", "end_date"),
    ],
)
def update_charts(region, avocado_type, start_date, end_date):
    mask = (
        (data.region == region)
        & (data.type == avocado_type)
        & (data.Date >= start_date)
        & (data.Date <= end_date)
    )
    filtered_data = data.loc[mask, :]
    price_chart_figure = {
        "data": [
            {
                "x": filtered_data["Date"],
                "y": filtered_data["AveragePrice"],
                "type": "lines",
                "hovertemplate": "$%{y:.2f}<extra></extra>",
            },
        ],
        "layout": {
            "title": {
                "text": "Average Price of Avocados",
                "x": 0.05,
                "xanchor": "left",
            },
            "xaxis": {"fixedrange": True},
            "yaxis": {"tickprefix": "$", "fixedrange": True},
            "colorway": ["#17B897"],
        },
    }

    volume_chart_figure = {
        "data": [
            {
                "x": filtered_data["Date"],
                "y": filtered_data["Total Volume"],
                "type": "lines",
            },
        ],
        "layout": {
            "title": {"text": "Avocados Sold", "x": 0.05, "xanchor": "left"},
            "xaxis": {"fixedrange": True},
            "yaxis": {"fixedrange": True},
            "colorway": ["#E12D39"],
        },
    }
    return price_chart_figure, volume_chart_figure


if __name__ == "__main__":
    app.run_server(debug=True,
                   host='127.0.0.1')

Then you need to update style.css with the following code:

body {
    font-family: "Lato", sans-serif;
    margin: 0;
    background-color: #F7F7F7;
}

.header {
    background-color: #222222;
    height: 288px;
    padding: 16px 0 0 0;
}

.header-emoji {
    font-size: 48px;
    margin: 0 auto;
    text-align: center;
}

.header-title {
    color: #FFFFFF;
    font-size: 48px;
    font-weight: bold;
    text-align: center;
    margin: 0 auto;
}

.header-description {
    color: #CFCFCF;
    margin: 4px auto;
    text-align: center;
    max-width: 384px;
}

.wrapper {
    margin-right: auto;
    margin-left: auto;
    max-width: 1024px;
    padding-right: 10px;
    padding-left: 10px;
    margin-top: 32px;
}

.card {
    margin-bottom: 24px;
    box-shadow: 0 4px 6px 0 rgba(0, 0, 0, 0.18);
}

.menu {
    height: 112px;
    width: 912px;
    display: flex;
    justify-content: space-evenly;
    padding-top: 24px;
    margin: -80px auto 0 auto;
    background-color: #FFFFFF;
    box-shadow: 0 4px 6px 0 rgba(0, 0, 0, 0.18);
}

.Select-control {
    width: 256px;
    height: 48px;
}

.Select--single > .Select-control .Select-value, .Select-placeholder {
    line-height: 48px;
}

.Select--multi .Select-value-label {
    line-height: 32px;
}

.menu-title {
    margin-bottom: 6px;
    font-weight: bold;
    color: #079A82;
}

How to create interactive components

New html.Div above charts includes two dropdowns and a date range selector that the user can use to filter data and update charts.

This is how it looks in app.py:

html.Div(
    children=[
        html.Div(
            children=[
                html.Div(children="Region", className="menu-title"),
                dcc.Dropdown(
                    id="region-filter",
                    options=[
                        {"label": region, "value": region}
                        for region in np.sort(data.region.unique())
                    ],
                    value="Albany",
                    clearable=False,
                    className="dropdown",
                ),
            ]
        ),
        html.Div(
            children=[
                html.Div(children="Type", className="menu-title"),
                dcc.Dropdown(
                    id="type-filter",
                    options=[
                        {"label": avocado_type, "value": avocado_type}
                        for avocado_type in data.type.unique()
                    ],
                    value="organic",
                    clearable=False,
                    searchable=False,
                    className="dropdown",
                ),
            ],
        ),
        html.Div(
            children=[
                html.Div(
                    children="Date Range",
                    className="menu-title"
                    ),
                dcc.DatePickerRange(
                    id="date-range",
                    min_date_allowed=data.Date.min().date(),
                    max_date_allowed=data.Date.max().date(),
                    start_date=data.Date.min().date(),
                    end_date=data.Date.max().date(),
                ),
            ]
        ),
    ],
    className="menu",
),

The drop-down lists and date range selector serve as menus for interacting with the data:

The first component in the menu is the Region dropdown. Component code:

html.Div(
    children=[
        html.Div(children="Region", className="menu-title"),
        dcc.Dropdown(
            id="region-filter",
            options=[
                {"label": region, "value": region}
                for region in np.sort(data.region.unique())
            ],
            value="Albany",
            clearable=False,
            className="dropdown",
        ),
    ]
),

Here’s what each parameter means:

  • id - element identifier.
  • options - options displayed when selecting the dropdown list. Waits for a dictionary with labels and values.
  • value - the default value when loading the page.
  • clearable - Allows the user to leave the field blank if set True.
  • className - class selector used to apply styles

The Type and Data Range selectors have the same structure as the Region drop-down menu.

Now let’s take a look at the components of dcc.Graphs:

html.Div(
    children=[
        html.Div(
            children=dcc.Graph(
                id="price-chart", config={"displayModeBar": False},
            ),
            className="card",
        ),
        html.Div(
            children=dcc.Graph(
                id="volume-chart", config={"displayModeBar": False},
            ),
            className="card",
        ),
    ],
    className="wrapper",
),

Components lack figureargument compared to the previous version of the figuretoolbar. This is because the argument will now be generated by the callback function using the input that the user sets with the Region, Type, and Data Range selectors.

💬How to define callbacks

We have defined how the user will interact with the application. Now we need to make the application respond to user actions. For this we will use the callback functions ( callbacks).

Dash callback functions are regular Python functions with a decorator called app.callback.

When the input changes, a callback function runs, performs predefined operations (such as filtering a dataset), and returns the result to the application. Basically, callbacks bind input and output data in an application.

Here is the callback function used to update the graphs:

@app.callback(
    [Output("price-chart", "figure"), Output("volume-chart", "figure")],
    [
        Input("region-filter", "value"),
        Input("type-filter", "value"),
        Input("date-range", "start_date"),
        Input("date-range", "end_date"),
    ],
)
def update_charts(region, avocado_type, start_date, end_date):
    mask = (
        (data.region == region)
        & (data.type == avocado_type)
        & (data.Date >= start_date)
        & (data.Date <= end_date)
    )
    filtered_data = data.loc[mask, :]
    price_chart_figure = {
        "data": [
            {
                "x": filtered_data["Date"],
                "y": filtered_data["AveragePrice"],
                "type": "lines",
                "hovertemplate": "$%{y:.2f}<extra></extra>",
            },
        ],
        "layout": {
            "title": {
                "text": "Average Price of Avocados",
                "x": 0.05,
                "xanchor": "left",
            },
            "xaxis": {"fixedrange": True},
            "yaxis": {"tickprefix": "$", "fixedrange": True},
            "colorway": ["#17B897"],
        },
    }

    volume_chart_figure = {
        "data": [
            {
                "x": filtered_data["Date"],
                "y": filtered_data["Total Volume"],
                "type": "lines",
            },
        ],
        "layout": {
            "title": {
                "text": "Avocados Sold",
                "x": 0.05,
                "xanchor": "left"
            },
            "xaxis": {"fixedrange": True},
            "yaxis": {"fixedrange": True},
            "colorway": ["#E12D39"],
        },
    }
    return price_chart_figure, volume_chart_figure

First, we define the output using Output objects. These objects take two arguments:

  • The identifier of the element that they will change when they execute the function.
  • Property of the item being changed. For example, Output("price-chart", "figure") update the figure property of the "price-chart" item.

Then we define the inputs using Input objects, they also take two arguments:

  • The ID of the item that they will watch for changes.
  • The property of the observed element that they should accept when a change occurs.

That is Input("region-filter", "value"), it will monitor the "region-filter"element’s changes and will accept its property if the element changes.

Note

The object discussed here is Input imported from dash.dependencies. Do not confuse it with a component coming from dash_core_components. These objects are not interchangeable and have different purposes.

In the last lines of the above block, we define the body of the function. In the above example, the function takes input (region, avocado type, and date range), filters it, and generates objects for price and volume charts.

This is the latest version of our toolbar. We made it not only beautiful but also interactive. The only missing step is to make the result shareable with others.

Deploying a Dash application on Heroku

We have finished building the application. We have a beautiful, fully interactive dashboard. Now we will learn how to deploy it.

In fact, Dash apps are the same as Flask apps, so they have the same deployment capabilities. In this section, we will deploy the application to Heroku hosting (with a free plan).

Before starting, make sure you have installed the Heroku Command Line Interface (CLI) and Git. To make sure that both programs are present on the system, run the version check commands in the terminal:

git --version
heroku --version

Next, we need to make a small change to app.py. After initializing the application, add a variable named server:

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
server = app.server

This add-on is required to run the application using a WSGI server. The built-in Flask server is not recommended for use in a production environment as it cannot handle a lot of traffic.

In the root directory of the project, create a file with a name in which we specify the Python version for the Heroku application: runtime.txt

python-3.8.6

When deployed, Heroku will automatically detect that this is a Python application and use the appropriate build package. If you provide the runtime.txt file as well, the server will determine the Python version that the application will use.

Then, in the root directory of the project, create requirements.txt file where we list the libraries required to install the Dash application on the web server:

dash==1.13.3
pandas==1.0.5
gunicorn==20.0.4

In the requirements.txt file there is a gunicornpackage, which we have not mentioned before. Gunicorn is basically a HTTP server that is often used to deploy Flask applications in a production environment.

Now let’s create a file named Procfile with the following content:

web: gunicorn app:server

This file tells the Heroku application what commands to run to launch our application.

Then you need to initialize the Git repository. To do this, go to the root directory of the project and run the following command:

git init

This command will initiate the creation of a Git repository for avocado_analytics/. That is, Git will keep track of the changes we make to files in that directory.

However, there are files that are not worth tracking with Git. For example, we usually do not want to track the contents of the virtual environment directory, bytecode files, and metadata files such as .DS_Store.

Create a file in the root directory named .gitignore and the following contents:

# Only if you are using macOS
venv *.pyc .DS_Store

This ensures that the repository does not track unnecessary files. Now let’s fix the state of the project:

git add . git commit -m 'Add dashboard files'

Make sure everything is in place before the last step. The project structure should look like this:

avocado_analytics/
├── assets/
│   ├── favicon.ico
│   └── style.css
├── venv/
├── app.py
├── avocado.csv
├── Procfile
├── requirements.txt
└── runtime.txt

Finally, you need to create an application in Heroku, upload your code there using Git, and run the application on one of the free Heroku server options. To do this, run the following commands:

heroku create APP-NAME  # Insert your app name instead of APP-NAME
git push heroku master
heroku ps:scale web=1

That’s it. We created and deployed a data dashboard. To access the application, just copy the link: https://APP-NAME.herokuapp.com/ and replace it with the name you defined in the previous step. APP-NAME

Conclusion

Congratulations! You have just created, configured and deployed your dashboard using Dash. We’ve gone from a simple dashboard to fully interactive and deployed on a remote server. With this knowledge, we can use Dash to create analytic applications that can be shared with colleagues and customers.

#webapp #dashboards #python #dash #datavisualizations

Data Visualizations Tutorial | Web App Dashboards with Python & Dash
Jack  Wood

Jack Wood

1626155160

Data Analysis and Data Dashboards in Excel : Day-3

Data Analysis and Data Dashboards in Excel : Day-3

7 Days Free Bootcamp on Data Analysis and Data Dashboards in Excel  in collaboration with Microsoft Learn Student Ambassador Program and Google Developer Groups…

Link to data last class data:
https://drive.google.com/file/d/1HF9_JnWv7yCwcCS-G_R_6wje9wygfIQ0/view?usp=sharing

Link to data visualization data:
https://drive.google.com/file/d/1e6-sOrqAOyh4F5gUi7wZp8x8mmTLaddQ/view?usp=sharing

Link to the notebook:  
https://github.com/ShapeAI/Python-and

Student Influencer Program Application:
https://forms.gle/52RNVYRtM94x4v9B7

#data #analysis #dashboards #excel

Data Analysis and Data Dashboards in Excel : Day-3
Jack  Wood

Jack Wood

1626068700

Data Analysis and Data Dashboards in Excel : Day-2

7 Days Free Bootcamp on Data Analysis and Data Dashboards in Excel  in collaboration with Microsoft Learn Student Ambassador Program and Google Developer Groups…

Link to data:
https://drive.google.com/file/d/1HF9_JnWv7yCwcCS-G_R_6wje9wygfIQ0/view?usp=sharing

Link to the notebook:  
https://github.com/ShapeAI/Python-and

Student Influencer Program Application:
https://forms.gle/52RNVYRtM94x4v9B7

#analysis #data #dashboards #excel #google #microsoft

Data Analysis and Data Dashboards in Excel : Day-2
Ruth  Nabimanya

Ruth Nabimanya

1623835967

Monitor PostgreSQL Performance: Arctype Dashboard

Building a dashboard in Arctype that allows us to monitor database performance in real-time and more fully understand PostgreSQL’s unique features.

Why Monitor PostgreSQL Database Health?

Just like monitoring our applications, it is very much necessary to monitor our database system. We want to monitor things substantially more granular than system-level processes — things such as:

  • How many queries actually make use of the index?
  • How effective is the database cache?
  • The number of open connections.

And so on.

Hardware metrics are essential, but can only get us so far, and will not help us make concrete decisions — like which queries to optimize and how we are using our database in general. Since PostgreSQL is an open-source database, it offers a lot of insights for free without having to rely on costly tools. Most of the metrics we are going to track are available by default since they are required for the query planner, but there are other critical areas for which we have to enable certain extensions/contrib modules that ship along with PostgreSQL.

Introduction to the Arctype Tool

Arctype is a very neat database tool that can be used not just as an SQL editor but also as a platform upon which complex dashboards can be both custom-built and shared around with developers/users. To understand its true power, we are going to consider a practical use case — monitoring a PostgreSQL database health.

#database #tutorial #postgresql #schema #dashboards #database tutorial

Monitor PostgreSQL Performance: Arctype Dashboard
Adelle  Hackett

Adelle Hackett

1590219960

Filter Your Dashboards with MongoDB Charts

MongoDB Charts on Atlas now supports dashboard-level filters, allowing you to quickly change the context of a single dashboard to better focus your analysis.

#mongodb #dashboards

Filter Your Dashboards with MongoDB Charts