Dashtable update from callback (rows+columns)

Hi,

I am new to Dash and struggling with a callback on DataTable by updating rows and columns - wheter with one callback (updating rows+columns at once) or two callbacks (updating rows, columns separate) (both have same Input).

My input is a date-picker. By default an empty table is supposed to be displayed (works).
By updating the date-picker, it should reload the table (as children from table-wrapper).
It looks like it is reloading - but all columns disappear and rows are empty.

this is my code (url not working):

# -*- coding: utf-8 -*-

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash_table as dct

import pandas as pd
#import numpy as np
from datetime import datetime as dt


def get_data(get_date):

   date_url = format(get_date, '%d-%m-%Y&submit=1')
   # example url
   get_url = 'https://www.url.org/file.xls'
   data = pd.read_excel(get_url + date_url)
   
   return data


################# 
# Creates a empty table for header
def create_empty_table():
   
    tblcols=[{'name': 'time', 'id': 'time'},
             {'name': 'PTE', 'id': 'PTE'}, 
             {'name': 'Status', 'id': 'Status'}
             ]
    
    table = dct.DataTable(
                id='live-table',
                data=[{}], 
                columns=tblcols,
                style_cell={'textAlign': 'center','min-width':'50px'},
            ),
    
    return table


#################
# Creates a table 
def create_table(data):
    
    tblrows=data.to_dict('rows'), 
    tblcols=[{'name': i, 'id': i} for i in data.columns],
            
    table = dct.DataTable(
                id='live-table',
                data=tblrows, 
                columns=tblcols,
                style_cell={'textAlign': 'center','min-width':'50px'}
            ),
    return table


#################

ext_css = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=ext_css)

# create table empty table 
table = create_empty_table()


### app layout
app.layout = html.Div(children=[
        
        html.Div(id='date-pick-wrapper',
                 style={'margin': '0 auto', 'width':'160px'},
                 children=dcc.DatePickerSingle(
                        id='date-picker',
                        min_date_allowed=dt(2007, 1, 1),
                        max_date_allowed=dt.date(dt.now()),
                        initial_visible_month=dt.date(dt.now()),
                        placeholder='Select a date',
                        #date=dt.date(dt.now()),
                        display_format='DD.MM.YYYY'
                    )
        ),
        html.Br([]),         
        html.Div(id='output-container-date-picker',style={'text-align': 'center'}),
        html.Br([]), 
        html.Br([]), 
        html.Div(id='table-wrapper',
                 style={'width': 'auto', 'overflow-y': 'scroll','max-width': '90vw', 'margin':'0 auto 50px'},
                 children=table           
        )
])   
### app layout finished


################# 
# Date Picker 
@app.callback(
        Output('output-container-date-picker', 'children'),
        [Input('date-picker', 'date')])
def update_output(date):
        string_prefix = 'bla bla: '
        string_end = '.'
        if date is not None:
            date = dt.strptime(date, '%Y-%m-%d')
            date_string = date.strftime('%d %B %Y')
        else:
            date_string = 'not yet selected'
            
        return string_prefix + date_string + string_end


################# 
# Live Update of table 
@app.callback(
        Output('table-wrapper', 'children'),
        [Input('date-picker', 'date')])
def update_table_live(date):
        
        if date is not None:
            date = dt.strptime(date, '%Y-%m-%d')
            #getting data for date
            data = get_data(date)
            # create table
            table = create_table(data)
        else:
            table = create_empty_table() 
        
        return table     

#app.config.supress_callback_exceptions = True

if __name__ == '__main__':
    app.run_server(host='0.0.0.0', port=9990, debug=True,)

My installed versions are:
dash 0.36.0
dash-core-components 0.42.1
dash-html-components 0.13.4
dash-renderer 0.17.0
dash-table 3.1.11

Can you shed some light on this for me please?
Thanks :slight_smile:

Hey @richklau,

you should not choose “Children” as the property of the table. You will indeed have to do two callbacks, one for the columns, and one for the data.

I answered the same question a couple of weeks ago. You will have a concrete example with a date picker as well :

https://community.plotly.com/t/datepickerrange-to-update-data-table/16193/5?u=qdumont

I hope this will help you,

Quentin

1 Like

Hey @qdumont

thanks a lot, its working now!
Funny thing I have already tried this before but forgot one comma, so I always ended it up in same behaviour as before with one callback.

For further understanding, may I ask you one more question:

In another app I actually have one graph and one dataTable - based on data of two static URLs. Furthermore I am using dcc.Intervall to update the graph plus dataTable. I only have two callbacks (one for graph, one for dataTable) and its working fine - I am updating (rows + columns) there.
I wonder why…
Does dcc.Intervall initialize the whole app again?

To close this thread - my final solution:

 html.Div(id='table-wrapper',
                 style={'width': 'auto', 'overflow-y': 'scroll','max-width': '90vw', 'margin':'0 auto 50px'},
                 children=dct.DataTable(id='live-table',
                                        data=tblrows, 
                                        columns=tblcols,
                                        style_cell={'textAlign': 'center','min-width':'50px'},
                                     )
                 )


################# 
# Live Update of tables columns
@app.callback(
        Output('live-table', 'columns'),
        [Input('date-picker', 'date')])
def update_tblcols_live(date):
        
        if date is not None:
            date = dt.strptime(date, '%Y-%m-%d')
            data = get_data(date)
            tblcols = create_table_col(data)            
        else:
            tblcols = create_empty_table_col() 

        return tblcols     

# Live Update of tables rows
@app.callback(
        Output('live-table', 'data'),
        [Input('date-picker', 'date')])
def update_tblrows_live(date):
        
        if date is not None:
            date = dt.strptime(date, '%Y-%m-%d')
            data = get_data(date)
            tblrows = create_table_row(data)    
        else:
            tblrows = create_empty_table_row() 
        return tblrows

Sorry, I am not quite sure to understand what you are asking. And for dcc.Intervall, I did not have the chance to try it yet, so I don’t know that much sorry. All I could eventually do is send you the official documentation : https://dash.plot.ly/live-updates. However, from what I understood, the Interval component reload only component, and not the full app. Just a guess.

Cheers

Hi, I have quite similar case where I have one graphe and one dash table both need to be updated once the data source changed. I used dcc.Interval to initiate the update, it works quite well for the graphe, but dash_table doesnt update.
I wonder if it is because the dcc.interval doesnt work for dash_table?? Thank you!

Hi Jie,

Could you show your code? Without it, it is pretty hard to see what’s not working.

I believe @jie‘s post was a duplicate of Live update dash_table, which got solved over there :slight_smile:

1 Like