Elevate Your Dashboard Interactivity In Dash
Tags: Plotly, Callback, Dashboard, Python, Coronavirus

What is callbacks in dash

In dash, a callback can be understood as a two-way tunnel linked between python function and the application.

Specifically, two types of cargo, Input and Output , are delivered inside a callback from two directions, Input is the cargo delivered from app to function , which generated via user’s actions in the app (e.g. input a value, select a row, select a item from dropdown menu, hover cursor above a scatter point etc.). Reversely, Output is the cargo from function to app , which returned by the function based on Input .

Both Input and Output have two arguments, component_id and component_property . component_id ensures callback to identify right sender and receiver while component_property is the entity of cargo. That said, based on these component_id , callback knows which component should be monitored for its component_property as Input and to which component should be assigned the component_property returned from function as Output .

In the following example adopted from Dash tutorial, we can see that the two components (i.e. dcc.Input() and html.Div() ) within the html.Div() container each has an id . These two ids have assigned to Output and Input in the callback , respectively. Consequently, value input by user ( value property of dcc.Input with id as ‘my-id’) will be passed to update_output_div(input_value) and the returned result will be assigned to children property of html.Div() with id as ‘my-div’ .

Sample dash code

Most importantly, callback monitors the input cargo traffic in real-time. As in above example, update_output_div(input_value) is triggered once there is a change inside the input box and the children content updates immediately (Figure 2). This feature enable users to see feedbacks from the application immediately after making an action.

Figure 2 | Example application

You may notice that the component_property is just the property of a given component, which means that we can return any properties of a component via a callback function.

Once we figured out the concept of callback in dash, let’s dive into the code of my dashboard.

Callback in this dashboard

Figure 3 | codes of map container

Here I first added one more html.Div() (Figure 3, line523-line563) sub-container inside the container where the map resides. Within this sub-container, there are two components, html.H5() for the title and dash_tale.DataTable() (Dash DataTable is an interactive table component designed for viewing, editing, and exploring large datasets) for the data table.

Still remember the first type of interactivity, the sorting function? This one is simple, it can be directly set by sort_action (line536, it enables data to be sorted on a per-column basis, which accepts any one value of none , native and custom ) within DataTable component. Here we just used native , which sorts data based on their types (e.g. ascending for number and alphabet for string).

To be able to select row in the DataTable, we also need to set row_selectable='single' (line534), the selection UI will then display in front of each row of data.

As for the map component (i.e, dcc.graph() ), you can find that its id is ‘datatable-interact-map’ (line519) while the DataTable component with an id of ‘datatable-interact-location’ (line529). These are two ids used in the callback. I like to use meaningful id names which helps to maintain the code in future.

Alright, everything in the app side is ready, now let’s move to the callback part. In our case, as the Input cargo, we have derived_virtual_selected_rows (this is not an arbitrary name, it is a list of index of select row for dash_table.DataTable component) from DataTable, the cargo will then deliver to the function to return a figure property for dcc.graph() .

Thus, as shown in Figure 4, we assigned corresponding `id` to Output and Input , in the meantime, tagged correct property for callback to monitor. Note that Input must be in a list.

Figure 4 | callback decorator

Last, let’s finish the function side. The interactivity we want is to let user to select one row from the DataTable, map will then automatically move to and zoom-in the selected Country/Region. In addition, at the start of the application, the initial center point and zoom-level should show the whole world map.

Callback and its function will be called when the application is first time initiated. However, when the application is first rendered, there is no row is selected, hence derived_virtual_selected_rows will be None . This may cause issue for the function relies on derived_virtual_selected_rows . That is why you can see from line590 to line591 (Figure 5), at the beginning of the function, we set derived_virtual_selected_rows as an empty list. Once user made a selection, the index of the selected row of the DataTable will be stored inside derived_virtual_selected_rows . As we only enabled single selection, it will contain only one item. To access this index, we hence just need to call derived_virtual_selected_rows[0] .

Figure 5 | Function wrapped by callback

By using the go.layout.mapbox.Center() (Figure 5, line639–641), we can specify coordinates where map should be centered and its zoom-in level. Thus, when the application is first launched and the derived_virtual_selected_rows is an empty list, we will use predefined coordinates and zoom-in level. Once there is a selection inside derived_virtual_selected_rows , callback will update the map with corresponding coordinates and zoom-in level.

lat=3.684188 if len(derived_virtual_selected_rows)==0 else dff['lat'][derived_virtual_selected_rows[0]]

lon=148.374024 if len(derived_virtual_selected_rows)==0 else dff['lon'][derived_virtual_selected_rows[0]] zoom=1.2 if len(derived_virtual_selected_rows)==0 else 4

Hurray, we now add two types of interactivity for the dashboard using callback. I hope you find this post useful and now have an idea about callback in dash.

Here are lists I used to learn dash callback: