Datatable
Datatable Creation
import dash
import pandas as pd
from dash import html
from dash import dcc
from dash import dash_table
from dash.dependencies import Output, Input
from dash.exceptions import PreventUpdate

app = dash.Dash(__name__)

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')

app = dash.Dash(__name__)

app.layout = html.Div([dash_table.DataTable(id = 'table'),
    html.Button('Click', id = 'button'),
    html.Div(id = 'output')
    ])

@app.callback(
    Output('table', 'data'),
    Output('table', 'columns'),
    Output('table', 'page_size'),
    Output('table', 'page_current'),
    Input('button', 'n_clicks'))
def update_table(n_clicks):
    if not n_clicks:
        raise PreventUpdate
    data=df.to_dict('records')
    columns=[{'id': c, 'name': c} for c in df.columns]
    return data, columns, 20, 1

if __name__ == '__main__':
    app.run_server(debug=True)
        
Datatable Style
import collections
import dash
import pandas as pd

from dash.dependencies import Output, Input
from dash.exceptions import PreventUpdate

from dash import html
from dash import dcc
from dash import dash_table
import plotly.graph_objects as go

app = dash.Dash(__name__)

df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')

app = dash.Dash(__name__)

app.layout = dash_table.DataTable(
    style_data={
        'whiteSpace': 'normal',
        'height': 'auto',
    },
    style_header = {'color': 'red'},
    style_cell_conditional=[
        {'if': {'column_id': 'country'},
         'width': '30%'},
        {'if': {'column_id': 'pop'},
         'width': '30%'},
    ],
    style_cell = {'width': '180px'},
    style_table = {'color': 'silver'},
    data=df.to_dict('records'),
    columns=[{'id': c, 'name': c} for c in df.columns],
    fixed_rows = {'headers': True, 'data': 1},
    page_size = 100,
    page_action = 'native',
    tooltip_data=[
        {
            column: {'value': str(value), 'type': 'markdown'}
            for column, value in row.items()
        } for row in df.to_dict('records')
    ],
    tooltip_duration=None,
)

if __name__ == '__main__':
    app.run_server(debug=True)
        
        
  • columns, list of dist
  • data, list of dicts
  • data=df.to_dict('records')
            
  • page_size, int
  • page_action, string
  • fixed_rows, dict
  • fixed_columns, dict
  • Styles Priority
  • 1. style_data_conditional
    2. style_data # excludes the header and filter cells.
    3. style_filter_conditional
    4. style_filter
    5. style_header_conditional
    6. style_header # header cells
    7. style_cell_conditional
    8. style_cell # includes the header cells, the data cells, and the filter cells
            
  • style_table, dict
  • style_table = {'height': '600px', 'overflowY': 'auto', 'width': '300px'}
            
  • style_cell, dict
  • style_cell = {'background-color': 'rgba(51, 51, 51, 1)', # background color
        'text-align':'center', # text alignment
        'minWidth': 95, 'maxWidth': 95, 'width': 95, # fixed cell width
        }
            
  • style_cell_conditional, list of dicts
  • # widths of individual columns
    style_cell_conditional=[
            {'if': {'column_id': 'Date'},
             'width': '30%'},
            {'if': {'column_id': 'Region'},
             'width': '30%'},
        ]
            
  • style_header
  • style_header = {'color': 'red', 'fontWeight': 'bold'}
            
  • style_header_conditional, list of dicts
  •  style_header_conditional = [
            {'if': {'column_id': 'year'},
             'width': '40%', 'color': 'blue'
            }
        ]
            
  • style_data, dict
  • style_data = {'font-size': '18px'} # excludes the header and filter cells
            
  • style_data_conditional, list of dicts
  • style_data_conditional=[
               {
                   'if': {'row_index': 'odd', 'state': 'active'}, # and
                   'backgroundColor': 'rgb(248, 248, 248)',
                   'color': 'white',
               },
               # union
            {
                'if': {'state': 'active'},
                'backgroundColor': 'black'
            }
           ],
            
  • style_as_list_view
  • style_as_list_view=True, # not have borders between the columns
            
  • filtery_query, string
  • style_data_conditional=[
               {
                   'if': {
                    'filter_query': '{year} > 2000 &↦ {year} < 2005',
                    'column_id': ['country', 'year'] # colored columns, by default, color the whole row
                   },
                'backgroundColor': 'tomato',
                'color': 'white'
               },
           ],
            
    style_data_conditional=[
               {
                   'if': {
                    'filter_query': '{{year}} = {}'.format(df['year'].max()),
                   },
                'backgroundColor': 'tomato', # color the whole row
                'color': 'white'
               },
           ],
            
    style_data_conditional=[
               {
                   'if': {
                    'filter_query': '{continent} contains "As"',
                    'column_id': 'year' # colored column
                },
                   'backgroundColor': 'RebeccaPurple'
               },
           ],
            
  • display the top n values
  • style_data_conditional=[
               {
                   'if': {
                    'filter_query': '{{year}} = {}'.format(i),
                },
                   'backgroundColor': 'RebeccaPurple'
               }
             for i in df['year'].nlargest(3)
           ],
            
  • highlight the values below average in each column
  • style_data_conditional=[
                {
                    'if': {
                        'filter_query': '{{{}}} <= {}'.format(col, value),
                        'column_id': col
                    },
                    'backgroundColor': '#FF4136',
                    'color': 'white'
                } for (col, value) in df.quantile(0.5).iteritems()
           ],
            
  • Number Formating
  • from dash.dash_table.Format import Format, Group, Scheme, Trim
    
    # the general form of a specifier in d3 rules
    [[fill]align][sign][symbol][0][width][,][.precision][type]
            
  • Delimiter
  • columns=[{'id': c, 'name': c}
            if c != 'pop' else
            {'id': c, 'name': c+'_', 'type':'numeric', 'format':Format(group=True,  groups=[2, 3, 2])} # 3,18,899,23
            for c in df.columns],
            
  • Padding
  • columns=[{'id': c, 'name': c}
                 if c != 'pop' else
                 {'id': c, 'name': c+'_', 'type':'numeric', 'format':Format(padding=True, padding_width=18)}
                 for c in df.columns],
            
  • Precision
  • columns=[{'id': c, 'name': c}
                 if c != 'pop' else
                 {'id': c, 'name': c+'_', 'type':'numeric', 'format':Format(precision=4, scheme=Scheme.fixed)}
                 for c in df.columns],
            
  • Symbol
  • columns=[{'id': c, 'name': c}
                 if c != 'pop' else
                 {'id': c, 'name': c+'_', 'type':'numeric', 'format':Format(symbol=Symbol.yes, symbol_prefix='@')}
                 for c in df.columns],
            
    Interaction Operations
    sort_action='native' # sorting by columns
    filter_action='native' # filtering by columns
    editable=True # editing the cells
    row_deletable=True # deleting rows
    row_selectable='single' | 'multi' # Selecting rows 
    page_action='native' | 'custom' # paging
            
    Column/Columns Selection
  • column_selectable, 'single', or 'multi'
  • columns[i].selectable, boolean
  • selected_columns, list of strings
  • derived_viewport_selected_columns, list of strings
  • import dash
    import pandas as pd
    from dash import html
    from dash import dcc
    from dash import dash_table
    from dash.dependencies import Output, Input
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([dash_table.DataTable(
        id = 'table',
        data=df.to_dict('records'),
        columns=[{'id': c, 'name': c, 'selectable': True} for c in df.columns],
        column_selectable='multi',
        selected_columns = ['year'],
        hidden_columns = ['year'],
        page_size = 20
    ),
                  html.Div(id = 'output')
        ])
    
    @app.callback(
        Output('output', 'children'),
        Input('table', 'selected_columns'),
        Input('table', 'derived_viewport_selected_columns'))
    def update_table(columns, view_columns):
        print(type(columns), columns)
        print(type(view_columns), view_columns)
        return columns
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Column/Columns Hidding
  • automatically add a toggle button to switch columns shown/hidden
  • hidden_columns, list of strings
  • columns[i].hideable, boolean
  • import dash
    import pandas as pd
    from dash import html
    from dash import dcc
    from dash import dash_table
    from dash.dependencies import Output, Input
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([dash_table.DataTable(
        id = 'table',
        data=df.to_dict('records'),
        columns=[{'id': c, 'name': c, 'hideable':True} for c in df.columns],
        hidden_columns = ['year'],
        page_size = 20
    ),
                  html.Div(id = 'output')
        ])
    
    @app.callback(
        Output('output', 'children'),
        Input('table', 'hidden_columns'))
    def update_table(columns):
        return str(columns)
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Column/Columns Deletion
  • deletable, boolean
  • import dash
    import pandas as pd
    from dash import html
    from dash import dcc
    from dash import dash_table
    from dash.dependencies import Output, Input
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([dash_table.DataTable(
        id = 'table',
        data=df.to_dict('records'),
        columns=[{'id': c, 'name': c, 'deletable': True} for c in df.columns],
        page_size = 20
    ),
                  html.Div(id = 'output')
        ])
    
    @app.callback(
        Output('output', 'children'),
        Input('table', 'columns'),
        Input('table', 'data'))
    def update_table(columns, data):
        print(len(data[0]))
        column_names = [column['name'] for column in columns]
        return str(column_names)
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Column/Columns Clearing
  • clearable, boolean
  • import dash
    import pandas as pd
    from dash import html
    from dash import dcc
    from dash import dash_table
    from dash.dependencies import Output, Input
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([dash_table.DataTable(
        id = 'table',
        data=df.to_dict('records'),
        columns=[{'id': c, 'name': c, 'clearable': True} for c in df.columns],
        page_size = 20
    ),
                  html.Div(id = 'output')
        ])
    
    @app.callback(
        Output('output', 'children'),
        Input('table', 'columns'),
        Input('table', 'data'))
    def update_table(columns, data):
        print(data[0])
        column_names = [column['name'] for column in columns]
        return str(column_names)
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Column/Columns Renaming
  • renamable, boolean
  • import dash
    import pandas as pd
    from dash import html
    from dash import dcc
    from dash import dash_table
    from dash.dependencies import Output, Input
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([dash_table.DataTable(
        id = 'table',
        data=df.to_dict('records'),
        columns=[{'id': c, 'name': c, 'renamable': True} for c in df.columns],
        page_size = 20
    ),
                  html.Div(id = 'output')
        ])
    
    @app.callback(
        Output('output', 'children'),
        Input('table', 'columns'),
        Input('table', 'data'))
    def update_table(columns, data):
        print(data[0])
        column_names = [column['name'] for column in columns]
        return str(column_names)
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Native Row/Rows Selection
  • row_selectable, 'single', 'multi', False, enable row selection
  • selected_rows, list of integers
  • derived_viewport_indices, list of integers, the original indices of rows in the current page
  • derived_viewport_selected_rows, list of integers
  • derived_viewport_data, list of dicts, the data on the current page
  • derived_virtual_indices, list of integers, the indices across all pages
  • derived_virtual_selected_rows, list of integers
  • derived_virtual_data, list of dicts, the visible data across all pages
  • filter_action
  • Operators
  • import dash
    import pandas as pd
    from dash import html
    from dash import dcc
    from dash import dash_table
    from dash.dependencies import Output, Input
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([dash_table.DataTable(
        id = 'table',
        data=df.to_dict('records'),
        columns=[{'id': c, 'name': c} for c in df.columns],
        row_selectable = 'multi',
        row_deletable = True,
        filter_action = 'native', # native filter
        page_size = 20,
        sort_action="native", # native sort
        sort_mode="multi",
        page_action='native', # native paging
    ),
                  html.Div(id = 'output')
        ])
    
    @app.callback(
        Output('output', 'children'),
        Input('table', 'selected_rows'),
        Input('table', 'derived_viewport_indices'),
        Input('table', 'derived_virtual_indices'),
        Input('table', 'derived_viewport_selected_rows'),
        Input('table', 'derived_virtual_selected_rows'),
        Input('table', 'data'),
        Input('table', 'derived_viewport_data'),
        Input('table', 'derived_virtual_data'))
    def update_table(indices, viewport_indices, virtual_indices, selected_indices, virtual_selected_indices, data, viewport_data, virtual_data):
        #if not indices:
            #raise PreventUpdate
        #print(indices)
        #print(viewport_indices)
        #print(virtual_indices)
        #print(selected_indices)
        #print(virtual_selected_indices)
        #if viewport_data:
            #print(len(viewport_data))
        #return str(viewport_data)
        if virtual_data:
            print(virtual_data[10])
            print(len(virtual_data))
        return len(data)
        #return str([data[index] for index in indices])
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Custom Row/Rows Selection

    # backend paging
    import dash
    from dash.dependencies import Input, Output
    from dash import dash_table
    import pandas as pd
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv')
    
    df[' index'] = range(1, len(df) + 1)
    
    app = dash.Dash(__name__)
    
    PAGE_SIZE = 5
    
    app.layout = dash_table.DataTable(
        id='datatable-paging',
        columns=[
            {"name": i, "id": i} for i in sorted(df.columns)
        ],
        page_current=0,
        page_size=PAGE_SIZE,
        page_action='custom'
    )
    
    @app.callback(
        Output('datatable-paging', 'data'),
        Output('datatable-paging', 'page_count'),
        Input('datatable-paging', "page_current"),
        Input('datatable-paging', "page_size"))
    def update_table(page_current,page_size):
        num = int(df.shape[0]/PAGE_SIZE)
        if df.shape[0]%PAGE_SIZE > 0:
            num += 1
        return df.iloc[
            page_current*page_size:(page_current+ 1)*page_size
        ].to_dict('records'), num
    
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    # backend paging with sorting
    import dash
    from dash import html
    from dash.dependencies import Input, Output, State
    from dash import dash_table
    from dash.exceptions import PreventUpdate
    import pandas as pd
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv')
    
    df[' index'] = range(1, len(df) + 1)
    
    app = dash.Dash(__name__)
    
    PAGE_SIZE = 5
    
    app.layout = html.Div([dash_table.DataTable(
        id='datatable-paging',
        columns=[
            {"name": i, "id": i} for i in sorted(df.columns)
        ],
        row_selectable='single',
        cell_selectable=False,
        page_current=0,
        page_size=PAGE_SIZE,
        page_action='custom',
        sort_action='custom',
        sort_mode='multi',
        sort_by=[]
        ),
        html.Div(id='display')])
    
    @app.callback(
        Output('datatable-paging', 'data'),
        Output('datatable-paging', 'page_count'),
        Input('datatable-paging', "page_current"),
        Input('datatable-paging', "page_size"),
        Input('datatable-paging', "sort_by"))
    def update_table(page_current,page_size, sort_by):
        num = int(df.shape[0]/PAGE_SIZE)
        if df.shape[0]%PAGE_SIZE > 0:
            num += 1
    
        print(sort_by)
        if len(sort_by):
            dff = df.sort_values(
                [col['column_id'] for col in sort_by],
                ascending=[
                    col['direction'] == 'asc'
                    for col in sort_by
                ],
                inplace=False
            )
            print('Sorted ...')
        else:
            # No sort is applied
            dff = df
    
        return dff.iloc[
            page_current*page_size:(page_current+ 1)*page_size
        ].to_dict('records'), num
    
    @app.callback(
        Output('display', 'children'),
        Input('datatable-paging', 'derived_viewport_selected_rows'),
        State('datatable-paging', 'data'))
    def display_output(index, rows):
        print(index)
        if not index:
            raise PreventUpdate
        if len(index) == 0:
            raise PreventUpdate
        return str(rows[index[0]])
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    # backend paging with filtering and sorting
    import dash
    from dash.dependencies import Input, Output
    from dash import dash_table
    import pandas as pd
    
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv')
    
    PAGE_SIZE = 5
    
    app.layout = dash_table.DataTable(
        id='table-filtering',
        columns=[
            {"name": i, "id": i} for i in sorted(df.columns)
        ],
    
        # backend paging parameters
        page_current=0,
        page_size=PAGE_SIZE,
        page_action='custom',
    
        # filtering parameters
        filter_action='custom',
        filter_query='',
    
        # sorting parameters
        sort_action='custom',
        sort_mode='multi',
        sort_by=[]
    )
    
    operators = [['ge ', '>='],
                 ['le ', '<='],
                 ['lt ', '<'],
                 ['gt ', '>'],
                 ['ne ', '!='],
                 ['eq ', '='],
                 ['contains '],
                 ['datestartswith ']]
    
    
    def split_filter_part(filter_part):
        for operator_type in operators:
            for operator in operator_type:
                if operator in filter_part:
                    name_part, value_part = filter_part.split(operator, 1)
                    name = name_part[name_part.find('{') + 1: name_part.rfind('}')]
    
                    value_part = value_part.strip()
                    v0 = value_part[0]
                    if (v0 == value_part[-1] and v0 in ("'", '"', '`')):
                        value = value_part[1: -1].replace('\\' + v0, v0)
                    else:
                        try:
                            value = float(value_part)
                        except ValueError:
                            value = value_part
    
                    # word operators need spaces after them in the filter string,
                    # but we don't want these later
                    return name, operator_type[0].strip(), value
    
        return [None] * 3
    
    
    @app.callback(
        Output('table-filtering', "data"),
        Output('table-filtering', "page_count"),
        Input('table-filtering', "page_current"),
        Input('table-filtering', "page_size"),
        Input('table-filtering', 'sort_by'),
        Input('table-filtering', "filter_query"))
    def update_table(page_current,page_size, sort_by, filter):
        # filtering
        filtering_expressions = filter.split(' && ')
        dff = df
        for filter_part in filtering_expressions:
            col_name, operator, filter_value = split_filter_part(filter_part)
            if operator in ('eq', 'ne', 'lt', 'le', 'gt', 'ge'):
                dff = dff.loc[getattr(dff[col_name], operator)(filter_value)]
            elif operator == 'contains':
                dff = dff.loc[dff[col_name].str.contains(filter_value)]
            elif operator == 'datestartswith':
                dff = dff.loc[dff[col_name].str.startswith(filter_value)]
    
        # get number of pages
        num = int(dff.shape[0]/PAGE_SIZE)
        if dff.shape[0]%PAGE_SIZE > 0:
            num += 1
    
        # sorting
        print(sort_by)
        if len(sort_by):
            dff = dff.sort_values(
                [col['column_id'] for col in sort_by],
                ascending=[
                    col['direction'] == 'asc'
                    for col in sort_by
                ],
                inplace=False
            )
    
        # backend paging
        return dff.iloc[
            page_current*page_size:(page_current+ 1)*page_size].to_dict('records'), num
    
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Cell
  • active_cell
  • start_cell
  • end_cell
  • selected_cells, a list of dict
  • import dash
    import pandas as pd
    from dash import html
    from dash import dcc
    from dash import dash_table
    from dash.dependencies import Output, Input
    from dash.exceptions import PreventUpdate
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([dash_table.DataTable(
        id = 'table',
        data=df.to_dict('records'),
        columns=[{'id': c, 'name': c, 'selectable': True} for c in df.columns],
        page_action='native',
        page_size = 20
    ),
                  html.Div(id = 'output')
        ])
    
    @app.callback(
        Output('output', 'children'),
        Input('table', 'data'),
        Input('table', 'active_cell'),
        Input('table', 'selected_cells'),
        Input('table', 'start_cell'),
        Input('table', 'end_cell')
    )
    def update_table(columns, active_cell, selected_cells, start_cell, end_cell):
        print('active_cell: ', active_cell)
        #print(selected_cells)
        print('start_cell: ', start_cell)
        print('end_cell: ', end_cell)
        return str(selected_cells)
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Editable
    import dash
    from dash import html
    from dash import dash_table
    from dash.dependencies import Output, Input, State
    from dash.exceptions import PreventUpdate
    import pandas as pd
    import numpy as np
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/Emissions%20Data.csv').reset_index()
    df['Emission'] = df['Emission'].map(lambda x: '{0:.2f}'.format(x))
    
    app.layout = html.Div([dash_table.DataTable(
            id='table',
            data=df.to_dict('records'),
            columns=[
                {'name': i, 'id': i} if i != 'Emission' else {'name': i, 'id': i, 'editable': True} for i in df.columns  # create editable column/columns
            ],
            fixed_rows={ 'headers': True, 'data': 0 },
            #editable=True, # make whole table editable
            page_action='native'
        ), html.Button('Click', id = 'button'), html.Div(id = 'output')
        ])
    
    @app.callback(
        Output('output', 'children'),
        State('table', 'data'),
        Input('button', 'n_clicks'))
    def update_table(data, n_clicks):
        if not n_clicks:
            raise PreventUpdate
        return str(data)
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Tooltips
  • tooltip, dict
  • tooltip_conditional, dict
  • tooltip_data, list of dicts
  • tooltip_header, dict
  • tooltip_delay, int
  • tooltip_duration, int
  • import dash
    import pandas as pd
    from dash import html
    from dash import dcc
    from dash import dash_table
    from dash.dependencies import Output, Input
    from dash.exceptions import PreventUpdate
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([dash_table.DataTable(
        id = 'table',
        data=df.to_dict('records'),
        columns=[{'id': c, 'name': c} for c in df.columns],
        tooltip_header={i: {'value':'**{}**'.format(i), 'type': 'markdown'} for i in df.columns},
        tooltip_data=[
            {
                column: {'value': '**{}**  \n Comments'.format(str(value)), 'type': 'markdown'}
                for column, value in row.items()
            } for row in df.to_dict('records')
        ],
        tooltip_delay=0,
        tooltip_duration=None
        ),
        ])
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    import dash
    import pandas as pd
    from dash import html
    from dash import dcc
    from dash import dash_table
    from dash.dependencies import Output, Input
    from dash.exceptions import PreventUpdate
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv')
    
    app = dash.Dash(__name__)
    
    app.layout = html.Div([dash_table.DataTable(
        id = 'table',
        data=df.to_dict('records'),
        columns=[{'id': c, 'name': c} for c in df.columns],
        tooltip ={i: {
            'value': '**{}**'.format(i),
            'use_with': 'both',  # both refers to header & data cell
            'type': 'markdown'
        } for i in df.columns},
        tooltip_conditional=[
            {
                'if': {
                    'filter_query': '{year} > 2000'
                },
                'type': 'markdown',
                'value': '![Recent]({})'.format(app.get_relative_path('/assets/Air-Force-Logo.png'))
            }
        ],
        tooltip_delay=0,
        tooltip_duration=None
        ),
        ])
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Virtualization
  • Rendering a subset of the data at any instant to improve the performance
  • Automatically decide the table height
  • import dash
    from dash import dash_table
    import pandas as pd
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/Emissions%20Data.csv').reset_index()
    df['Emission'] = df['Emission'].map(lambda x: '{0:.2f}'.format(x))
    
    app.layout = dash_table.DataTable(
            id='table-virtualization',
            data=df.to_dict('records'),
            columns=[
                {'name': i, 'id': i} for i in df.columns
            ],
            fixed_rows={ 'headers': True, 'data': 0 },
            virtualization=True,
            page_action='none'
    )
    
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Dropdowns
    import dash
    from dash import html
    from dash import dash_table
    from dash.dependencies import Output, Input, State
    from dash.exceptions import PreventUpdate
    import pandas as pd
    import numpy as np
    
    app = dash.Dash(__name__)
    
    df = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/Emissions%20Data.csv').reset_index()
    df['Emission'] = df['Emission'].map(lambda x: '{0:.2f}'.format(x))
    temp = np.zeros((df.shape[0], 1)).astype(int)
    df['label'] = temp
    
    app.layout = html.Div([dash_table.DataTable(
            id='table',
            data=df.to_dict('records'),
            columns=[
                {'name': i, 'id': i} if i != 'label' else {'name': i, 'id': i, 'presentation': 'dropdown', 'editable': True} for i in df.columns
            ],
            fixed_rows={ 'headers': True, 'data': 0 },
            #editable=True,
            dropdown={
                'label': {'options': [{'label':'0', 'value':0}, {'label':'1', 'value':1}]},
            },
            virtualization=True,
            page_action='native'
        ), html.Button('Click', id = 'button'), html.Div(id = 'output')
        ])
    
    @app.callback(
        Output('output', 'children'),
        State('table', 'data'),
        Input('button', 'n_clicks'))
    def update_table(data, n_clicks):
        if not n_clicks:
            raise PreventUpdate
        return str(data)
    
    if __name__ == '__main__':
        app.run_server(debug=True)
            
    Persistence
    persistence = True,
    
    # define persistent properties
    persisted_props = [ 'columns.name', 'filter_query', 'hidden_columns', 'selected_columns', 'selected_rows', 'sort_by'],
    
    # local, keep after browser quit
    # session, keep on page reset, clear after browser quit
    # memory, reset on page reset
    persistence_type = 'local',
            
    Reference
  • D3 Rules
  • Datatable Reference
  • Documentation