Step-by-step guide to your first interactive dash app — Part V

Paolo Molignini, PhD
5 min readOct 29, 2022

--

Welcome to part V of my guide to writing and deploying a dash app for data visualization! If you have read parts I to IV, you should be familiar with most of the modules that we need to make our monkeypox-tracking app work (just as a reminder, the repository can be found here): we have gone through the skeleton of the app (except the details of the callback), the data generation and manipulation, and the layout. Today, we will look at the figure generation in plots.py and discover how plotly graph objects work.

There are three functions in plots.py: get_default_layout(), get_worldmap_fig(), and get_tot_cases_fig(). The first function is just a collection of dictionary entries which specify the layout properties, such as the margins (on line 22), the labels for the axes (on lines 25 and 27), and the color template (on line 29). The resulting dictionary will be passed to the graph object we define for the second figure containing the time evolution of the monkeypox cases.

Figure for choropleth worldmap

The second function defines the first figure, the choropleth worldmap showing the cumulative number of cases worldwide for a given date. In line 44, you can see the definition of the graph object (go) Figure. This component must be provided with the argument “data”, which is a tuple of so-called “trace” instances, i.e. figure data structures. Common ones are:

  • go.Scatter: graph object encompassing line charts, scatter charts, text charts, and bubble charts.
  • go.Bar and go.Histograms: for bar charts, stacked bar charts, and histograms; useful to represent data distributions.
  • go.Heatmap: to display 2D data (matrices) as colored plots.
  • go.Pie: to visualize pie charts and sectors.
  • go.Surface: to visualize 3D plots as surfaces (functions of two variables).

For a more comprehensive list, check out this webpage. In simple terms, these are all graph objects for displaying data structures, i.e. the “content” of our figure, while go.Figure is the “container” of such graph objects.

In our example, we employ go.Choropleth to show a worldmap colored as a heatmap to display different numbers of cases in different countries. This graph object, like basically all the other ones you will encounter, is a tree-like data structure formed of a series of dictionaries with precise attributes. For our go.Choropleth figure, we must provide a list of locations, which are standardized codes corresponding to different countries (line 45), and a list of values in the attribute “z”, which we take to be the number of monkeypox cases per country. This attribute will codify the color of each country according to our colormap. Both lists are contained in the dataframe current_df, which we have seen in part III. We also specify an attribute called “text”, which will indicate the name of the country when we select it. All the other attributes specify the visuals of the choropleth map. For instance, as a color scale we input “cmap”, our custom-defined color scale. Marker_line_color and marker_line_width control the borders between countries

After we have defined the graph object, we call the method update_layout in line 57. This is a very useful way to modify the appearance of our figure *after* having defined it (for instance, it could be put into a callback function to dynamically change how the figure looks!). In our example, we specify the dimensions of the figure via width and height, the attributes of the map via geo (background color, projection type etc.), and the colors of the background, the border, and the fonts. After we have “massaged” our plot to look how we want, we return the figure in line 69.

Figure for cumulative cases

The third and final function generates the figure that plots the number of cases (and the corresponding exponential fit) as a function of time for a given selection of countries. Here, we encounter another way of constructing figures by adding traces (see lines 83, 94, 107, and 121). A trace is a graph object that can be plotted in the same figure with other traces. This is very useful when you want to display several curves on the same axes, for instance if you want to show how a function behaves as you change a parameter, or in our case, compare similar data that stems from different sources (cumulative cases for different countries).

The way traces work is very easy. First, you need to define the container for your plots. In our case, this is a go.Figure (line 80), whose layout is initialized to be the default layout we defined at the top of the module plots.py. Then, you simply call the figure with the method add_trace:

MyFig.add_trace(another_go_object)

The type of plot that we pass to the figure is go.Scatter, a type of scatter plot which displays a sequence of pairs given as input variables x and y. As you can see from the screenshots, the x variable is the same for all scatter plots (the date extracted from the cases_df dataframe). The y variables are instead the total number of cases with its exponential fit, and the cases for all the countries we have selected in country_list (in the for loop of lines 106 and 120). Some of the attributes that we pass to change the appearance of the plots are:

  • fill: specifies whether the area below the lines will be filled or not.
  • mode: specifies what type of plot we want, e.g. discrete markers (“markers”) or, as in this case, continuous curves (“lines”).
  • line: gives attributes to the plotted line, such as color, width, type of line (solid, dotted, dashed etc.). It is passed as a dictionary.
  • name: the name of the line/markers that will appear in the legend.

We conclude the function by updating the size of the layout and providing a legend:

All done! We now have a functional module that creates the plotly/Dash figures we want to display in our app. This also concludes the review of all the modules in our app. The only thing left to do is to analyze in depth our callback function that will make the app come alive, but that’s for next time ;)

Thanks for reading!

--

--

Paolo Molignini, PhD

Researcher in theoretical quantum physics at Stockholm University with a passion for programming, data science, and probability & statistics.