Creating Interactive Data Tables in Plotly Dash
By: Akash Kaul
Tags: Dash, Dashboard, Data Science, Data Visualization, Python Programming

Creating Interactive Data Tables in Plotly Dash

Photo by Markus Spiske on Unsplash

Motivation

Plotly Dash is an incredibly powerful framework that allows you to create fully-functional data visualization dashboards. Using Dash, you can create a full front-end experience using only Python. The library does a great job of abstracting away from the complicated HTML, CSS, and JS associated with all of the different web app components. While this is very nice, it sometimes becomes confusing.

For example, Dash provides the dash_table.DataTable component, which is a table that comes with lots of prebuilt, ready-to-use functionalities. However, some of these features are hard to find or understand, and so getting the table to work exactly as you imagined is very tricky. So, I decided to document two table features that are not very well advertised, but which I feel are extremely important to creating a truly dynamic table.

Handling click events

Adding click events to your data table is a great way to make your dashboard more interactive. Thankfully, this one actually isn’t too difficult.

Using the active_cell component of the DataTable, you can easily get the data of a cell the user clicks on.

A callback using active_cell would look something like this:

@app.callback(

Output('output_div', 'children'),

Input('data_table', 'active_cell'),

State('data_table', 'data')

)

def getActiveCell(active_cell, data): if active_cell:

col = active_cell['column_id']

row = active_cell['row']

cellData = data[row][col] return html.P(f'row: {row}, col: {col}, value: {cellData}') return html.P('no cell selected')

The input is the active_cell component, which means selecting a cell is what causes this callback to fire. Also, note how the callback is sensitive to the data of the table. Without this, you can only access the row and column of the selected cell and not the actual value inside.

Using this callback in a full app would look something like this:

app = dash.Dash(__name__) app.layout = html.Div([ dash_table.DataTable(

id='data_table',

columns=[{

'name': 'Column {}'.format(i),

'id': 'column-{}'.format(i),

} for i in range(1, 5)],

data=[

{'column-{}'.format(i): (j + (i-1)*5) for i in range(1, 5)}

for j in range(5)

]

),

html.Div(id='output_div')

]) @app.callback(

Output('output_div', 'children'),

Input('data_table', 'active_cell'),

State('data_table', 'data')

)

def getActiveCell(active_cell, data):

if active_cell:

col = active_cell['column_id']

row = active_cell['row']

cellData = data[row][col] return html.P(f'row: {row}, col: {col}, value: {cellData}') return html.P('no cell selected') if __name__ == '__main__':

app.run_server(debug=True)

Here’s what the code looks like in action:

Example Data Table with click callback

Adding live updates

This option is great for dashboards that need to display information in real-time (i.e. a dashboard that monitors the usage of some service).

The live updates are divided into 2 main ideas.

Update Interval

In order to update the table periodically, you have to set up an interval for how often the data should change. This is done with the dcc.Interval component from Dash.

This component stores a value, n_intervals, which tracks how many intervals of some specified length have passed.

You can see a full example of using the Interval for updates in the Dash documentation.

The declaration for the dcc.Interval component looks like this:

dcc.Interval(

id='interval-component',

interval=1*1000, # in milliseconds

n_intervals=0

)

And the callback for the n_intervals component looks like this:

@app.callback(

Output('component-to-update', 'property'),

Input('interval-component', 'n_intervals')

)

def update(n_intervals):

if n_intervals > 0:

# update table data

Appending Data

Now that we have a way to periodically perform some action, we need to use this method to update the table data.

We can do this by modifying the callback above. All we have to do is change the output to the data attribute of the table, as well as add a state for data.

This new callback looks like this:

@app.callback(

Output('data_table', 'data'),

Input('interval-component', 'n_intervals'),

[State('data_table', 'data'), State('data_table', 'columns')]

)

def updateData(n, data, columns):

if n > 0:

data.append({c['id']: n for c in columns})

return data

This callback takes in the data already in the table and appends a new row.

Adding this callback to the app detailed above, along with adding the dcc.Interval component to the layout creates the following dashboard.

Live periodic updates to the data table

Note: It’s a good idea to have the interval controlled by a toggle or switch so that it doesn’t run forever. You can do this by updating the disabled attribute of the dcc.Interval in a callback.

Conclusion

In this short blog, we saw two methods of adding extra functionality to a Dash DataTable. Adding click events and live updates are both awesome ways to make your data table more interactive, more flexible, and more powerful.

Try out these features in your own dashboards to truly take your visualization to the next level.

If you liked this blog, let me know!