Lab: Introduction to Dash¶

Dash is an easy-to-use framework that can be used to build interactive Python web applicacations and dashboards. This lab is an introduction to the basics of Dash suitable for students near the end of CS1 and later.

This lab covers using Dash UI components and accompanies an associated assignment that introduces interactive data visualizations in Dash.

Reference for this lab¶

Dash Tutorial: https://dash.plotly.com/

Getting Started with Dash¶

Dash is a Python framework for creating interactive web-based applications.

  • especially useful for data-centric applications
  • designed to work well with Plotly visualizations

If you have not done so already, install the dash package with pip. This lab also uses requests, pandas, and plotly which you may also need to install.

python3 -m ensurepip --upgrade
python3 -m pip install requests
python3 -m pip install pandas
python3 -m pip install plotly
python3 -m pip install dash

Your first Dash app¶

Copy the following code into a file called dash_hello.py and run it. When it runs, it should display a message like this in your terminal:

Screen%20Shot%202022-02-16%20at%209.24.06%20PM.png

It appears that the program is stuck doing nothing, but it is actually running a little webserver right on your computer. You can see the web page that it is generating by opening a web browser and going to http://127.0.0.1:8050/

In [ ]:
#these are the components we need from Sash
from dash import Dash, html, dcc

#this creates an object representing your application
#you should have this line for all Dash apps
app = Dash(__name__)

#the layout describes all of the pieces that display on the page
#the html.Div allows you to pass a list of things to display
app.layout = html.Div([
    dcc.Markdown(
        children = 
            """
                ## Hello there!

                This is my __Dash__ web application.

                Isn't it _neat_?

            """
    ),

    dcc.Markdown(
        children = """
                    It can have multiple markdown cells.
                    * with
                    * bullets 
                    * even
                """
    )
])

#this will launch your application in a web server
#you should have this line for all Dash apps
if __name__ == '__main__':
    app.run_server(debug=True)

When you open your browser, you should see the "Hello there!" message on the page that looks something like this:

Lab Exercise 1¶

Add a third Markdown element with a new message that you come up with.

Things to notice¶

  • Dash is capable of displaying documents written using html and Markdown, two popular web-based formatting languages. Markdown is what is shown here - it's really basic but gets the job done. You can check out more about writing Markdown here: https://www.markdownguide.org/basic-syntax/
  • Each Markdown component has a named parameter called children - this is where you put the text you want displayed.
  • If you want to stop your Dash app, go back to the terminal, hold down your <control> key on your keyboard and hit the c key.

Input and Callbacks¶

Dash has many other components besides just Markdown.

The following code has an Input component which allows users to type into an input text box.

Notice that each component may also be given an id by assigning a value to the id parameter when creating that object. This will be useful for referring to this component in other parts of the code.

It also has a callback function which is defined to run any time the value in the Input textbox changes.

Notice the @app.callack decorator which describes the inputs (i.e., parameters) and outputs (i.e., returns) of the function.

Update your dash_hello app with this code and check it out. If your development web server is still running, you may not have to restart it to see the changes, but if anything goes wrong, you can always stop the server (with <control>-c) and re-run it.

In [ ]:
from dash import Dash, html, dcc
from dash.dependencies import Input, Output

app = Dash(__name__)

app.layout = html.Div(children = [
    dcc.Markdown(
        id = "name_prompt",
        children = "## Enter your name"
    ),

    dcc.Input(
        id = "name_input",
        value = "" #initially there is no value for the user input
    ),

    dcc.Markdown(
        id = "output_message",
        children = "" #initially the Markdown string is empty
    )
])

@app.callback(
    Output("output_message","children"),
    Input("name_input","value"),
)
def my_cool_message_generator(user_name):
    my_message = "Hello "+user_name+"!"
    return my_message

if __name__ == '__main__':
    app.run_server(debug=True)

Your application should now be interactive - try typing your name in the input box and watch the message update.

Lab Exercise 2¶

The following code introduces a new kind of component - the Radioitem. Run this code and answer the following questions:

  • What is a Radioitem?
  • How many callback functions does this app have?
  • What causes each of the callback functions to run? Why?
  • What inputs and outputs do each callback function use?
In [ ]:
from dash import Dash, html, dcc
from dash.dependencies import Input, Output

app = Dash(__name__)

app.layout = html.Div(children = [
    dcc.Markdown(
        id = "name_prompt",
        children = "## Enter your name"
    ),

    dcc.Input(
        id = "name_input",
        value = "" #initially there is no value for the user input
    ),

    dcc.Markdown(
        id = "major_prompt",
        children = "What is your major?"
    ),

    dcc.RadioItems(
        id = "major_radio_items",
        options = ["Computer Science","Data Analytics","Artificial Intelligence","Information Systems","Other"],
        value = "Computer Science"
    ),

    dcc.Markdown(
        id = "name_output_message",
        children = "" #initially the Markdown string is empty
    ),

    dcc.Markdown(
        id = "major_output_message",
        children = "" #initially the Markdown string is empty
    )
])

@app.callback(
    Output("name_output_message","children"),
    Input("name_input","value"),
)
def my_cool_message_generator(user_name):
    my_message = "Hello "+user_name+"!"
    return my_message

@app.callback(
    Output("major_output_message","children"),
    Input("major_radio_items","value"),
)
def message_for_major(user_major):
    my_message = "Dash is great for "+user_major+" applications."
    return my_message

if __name__ == '__main__':
    app.run_server(debug=True)

Lab Exercise 3¶

Dropdown is another component that is similar to Radioitems. What do you think that is supposed to do differently? In the code above, change the Radioitems to Dropdown and run it.

You can find documentation and examples on how to use each of these components here:

  • https://dash.plotly.com/dash-core-components/radioitems
  • https://dash.plotly.com/dash-core-components/dropdown
  • https://dash.plotly.com/dash-core-components/checklist

Browse through the other components on the left side of the page to get an idea of what other options you have.

Multiple Inputs affecting the same output¶

You can make multiple inputs affect the same output by listing multiple Input objects with a single callback function.

Notice how the inputs are related to the parameters in the example below:

In [ ]:
from dash import Dash, html, dcc
from dash.dependencies import Input, Output

app = Dash(__name__)

app.layout = html.Div(children = [
    dcc.Markdown(
        id = "name_prompt",
        children = "## Enter your name"
    ),

    dcc.Input(
        id = "name_input",
        value = "" #initially there is no value for the user input
    ),

    dcc.Markdown(
        id = "major_prompt",
        children = "What is your major?"
    ),

    dcc.RadioItems(
        id = "major_radio_items",
        options = ["Computer Science","Data Analytics","Artificial Intelligence","Information Systems","Other"],
        value = "Computer Science"
    ),

    dcc.Markdown(
        id = "output_message",
        children = "" #initially the Markdown string is empty
    )
])

@app.callback(
    Output("output_message","children"),
    Input("name_input","value"),
    Input("major_radio_items","value"),
)
def my_cool_message_generator(user_name,user_major): #the two params come from the two Input()
    if user_name == "": #the user hasn't entered a name yet
        return ""  #so return blank for the output message
    else:
        my_message = user_name + " is learning about " + user_major 
        return my_message


if __name__ == '__main__':
    app.run_server(debug=True)

Loading and using other data with Dash applications¶

Even though global variables are usually a bad idea, you can use them to retain data (so you don't have to reload from a file or Web API every time the callback function runs).

In this example DATA is a global variable with COVID country data we worked with previously.

In [ ]:
from dash import Dash, html, dcc
from dash.dependencies import Input, Output
import requests

#read the country-level data from the API
response = requests.get("https://api.covid19api.com/summary")
DATA = response.json()

app = Dash(__name__)

app.layout = html.Div(children = [
    dcc.Markdown(
        id = "country_prompt",
        children = "## Enter the name of a country"
    ),

    dcc.Input(
        id = "country_input",
        value = "" #initially there is no value for the user input
    ),

    dcc.Markdown(
        id = "output_message",
        children = "" #initially the Markdown string is empty
    )
])

@app.callback(
    Output("output_message","children"),
    Input("country_input","value"),
)
def display_covid_data(country_name):
    data_display = ""
    for curr_country in DATA["Countries"]:
        if curr_country["Country"] == country_name:
            data_display = "### "+country_name+"\n\n"
            data_display += "New confirmed cases: "+str(curr_country["NewConfirmed"])+"\n\n"
            data_display += "Total deaths: "+str(curr_country["TotalDeaths"])+"\n\n"
            data_display += "as of "+DATA["Date"]+"\n\n"

    return data_display

if __name__ == '__main__':
    app.run_server(debug=True)

Run this and try typing in the name of some countries

Lab Exercise 4¶

Change the above application so that all of the countries listed in the records of DATA["Countries"] appear as options in a dropdown list. Then allow the user to look up stats based on that dropdown instead of the input box.