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

Paolo Molignini, PhD
5 min readOct 30, 2022

--

Welcome back to my guide to writing and deploying a dash app for data visualization! Hopefully you have read parts I to V and are now familiar with all the bits and bobs in the app. The only thing that we have not discussed in detail so far is the callback, a function used to dynamically modify the properties of the app and give it “life”. This will be the content of part VI, so let’s dig right in!

Dash callbacks

Before discussing the callback function in detail, it’s probably useful to remind ourselves what we want to achieve with it. In our app, we have two main figures that show some of the data we acquired — one choropleth worldmap showing the cumulative number of monkeypox cases for a given date, and another figure displaying the time evolution of such cases for a selection of countries. At the same time, we have seen previously that we have constructed a series of dynamical components such as dropdown menus, checklists, and buttons to change some of the input variables. In particular, we want to be able to change the date when the cases are plotted, the list of countries displayed in the second figure, and the number of days after which we perform the exponential fit for the curves in the second figure. The callback is going to take these changeable inputs and generate new data and new figures from them.

In the screenshot below you can find a snippet of the code in app.py where the callback is defined. You can see that, essentially, the callback is just a regular python function as highlighted by the def keyword in line 97, plus a decorator written immediately above the function, signalled by the syntax

@app.callback(Outputs, Inputs, States, options)

The function itself takes as input four variables:

  • updated_current_date_str: this is the new value of the date (in string format) which is updated when we click on the update button.
  • n_clicks: if you recall from our analysis of the layout, n_clicks is an attribute of the update button that tracks how many times we click on it. This variable refers to that attribute.
  • country_list: this is the list of countries with available data that we can select from the dropdown / checkbox menu, and comes from the corresponding attribute in that component.
  • initial_day_fit_str: this is the (integer) value for the days after which we want to start the exponential fit, which comes from the corresponding dropdown menu.

As you can see, those are all variables that correspond to parts of the app that we can dynamically change, such as counters for button clicks or the values of certain attributes in other components. What do we do with these inputs? Well, you can see it from line 99 onward.

The if-statement is just a trick to prevent the callback from firing if the date has not been changed. You can read more about the PreventUpdate method here. Then, we transform some of the input variables in different formats in lines 103/104 before using them as input for the function calls that we have seen when looking at the data extraction (line 107), data fit (line 108), and figure generation (lines 111/112).

In practice, what we are doing is really simple: we are just regenerating the data and the figures with new input! In line 113 we additionally update the text that is displayed at the top of the page, and so we have all of our updated components that we want to show once the callback is triggered: two new figures, and a new text for the top of the page. The callback function will send these outputs directly to the components, to update the corresponding attributes.

How does that work? Everything is done automatically by the function with the help of the decorator. Let’s examine the decorator a bit more closely. As you can see, it contains a list with three kinds of objects: Output, Input, and State (and some options like prevent_initial_call, which as the name suggests just prevents the callback from firing when the app is loaded for the first time). The syntax for these object is always the same. It is a pair of strings. The first element of the pair indicates the id of the component of interest, which is used as input, state, or output. The second component is the target attribute of the component, which will be taken as input or modified as an output. Simple, no? In more detail:

  • Input: these are the attributes of the components which will cause the callback to fire when they are changed. For example, in our app we want the callback to be triggered in two cases: either when the date attribute of the date picker is changed, or when the update button is clicked (i.e. its attribute n_clicks changes).
  • State: every other component attribute that you need to pass to your callback to change other components can be passed as a state. A state input will not trigger the callback. This distinction is really neat, because it gives us the power of changing many different attributes of different components before firing the callback. In our example, we pass the value of the country list toggle and of the fit start dropdown menu as a state, because we don’t want to trigger the callback immediately after we have modified them. What happens is that, we first modify their values, and then the callback is triggered only once when we click on the update button. Of course, the callback will fire right away when the date in the date picker is modified, but this type of change is separate and does not depend on the value of the other dropdown menus.
  • Output: all the components that are modified by the callback have to be listed in the decorator as outputs. The returns of the function will be the new values for the attributes of the components that will be modified once the callback is triggered. In our case, we change the content of the two figures, identified by their id’s, and the HTML component that encodes the first text on top of the page.

Note that you cannot have different callbacks referring to the same component id (having the same outputs), so sometimes you have to think carefully about how to design your callback functions. Most of the time this is not a very big limitation, though. You can also write callback that update components with pattern matching, but this is an advanced function and I will not discuss it here.

Congratulations! Now you know everything you need to thoroughly understand my monkeypox app and are ready to create your very own, including callback to dynamically code how your app responds to clicks and data selection.

Your app will be fully functional locally, but if you want to share it with the world, there is one more step you need to take: you need to deploy it on a server. In the next and last part this guide, we will see how to do that for free on Heroku!

Thanks for reading :)

--

--

Paolo Molignini, PhD

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