Bring Drag & Drop to Dash with Dashboard Engine. 💫 Learn how at our next webinar!

Dash Table with Multicolumns from MultiIndex

I need some help, please. Trying to create Table with multiple columns.
Simple ways, like in tutorial do work however when I try to create DashTable from pd.MultiIndex I constantly get error: Error loading layout. I work with Jupyter Lab. I tried different approaches. I compared content of app.layout, data and .columns and can’t figure it out.

Here is sample code to recreate an error

import dash 
import dash_table
from jupyter_dash import JupyterDash
import pandas as pd


## Create DataFrame

DictA = {('A', '10'): {0: 1, 1: 11, 2: 111},
 ('B', '20'): {0: 2, 1: 22, 2: 222},
 ('C', '30'): {0: 3, 1: 33, 2: 333},
 ('D', '40'): {0: 4, 1: "A", 2: 'B'}}

df = pd.DataFrame.from_dict(DictA)



# app = JupyterDash(__name__) # For Jupyter Lab
app = dash.Dash(__name__)


app.layout = dash_table.DataTable(
                    data = df.to_dict('records'),
                    columns=[{"name": [c[0], c[1]], "id": c[1]} for c in df.columns],
                                )
   
if __name__ == '__main__':
    app.run_server(debug=True)
    
# app.run_server(mode='jupyterlab', port = 8090, dev_tools_ui=True, #debug=True,
#           dev_tools_hot_reload =True, threaded=True)     

I found a way around. I’m still open for better solution.
Changes are marked with dashes.

import dash_table
from jupyter_dash import JupyterDash
import pandas as pd


## Create DataFrame

DictA = {('A', '10'): {0: 1, 1: 11, 2: 111},
 ('B', '20'): {0: 2, 1: 22, 2: 222},
 ('C', '30'): {0: 3, 1: 33, 2: 333},
 ('D', '40'): {0: 4, 1: "A", 2: 'B'}}

df = pd.DataFrame.from_dict(DictA)



app = JupyterDash(__name__) # For Jupyter Lab
# app = dash.Dash(__name__)


bottom_col_row = df.columns.get_level_values(1)  #------------
df.columns = df.columns.droplevel(1)             #------------


app.layout = dash_table.DataTable(
                    data = df.to_dict('records'),
                    columns=[{'name': [x[0], x[1]], 'id': x[0]} for x in zip(df.columns, bottom_col_row)], #------------
                                )
   
# if __name__ == '__main__':
#     app.run_server(debug=True)
    
app.run_server(mode='jupyterlab', port = 8090, dev_tools_ui=True, #debug=True,
          dev_tools_hot_reload =True, threaded=True)  ```

I wrote a quick function to take a MultiIndex dataframe and generates a data_table formatted column list and then flattening the column list in the actual dataframe. This works better then dropping column levels because it handles situations where sublevel columns have the same name.

The output from the function provides the columns and data parameters for the dash_table.DataTable funciton.

def datatable_settings_multiindex(df, flatten_char = '_'):
    ''' Plotly dash datatables do not natively handle multiindex dataframes. This function takes a multiindex column set
    and generates a flattend column name list for the dataframe, while also structuring the table dictionary to represent the
    columns in their original multi-level format.  
    
    Function returns the variables datatable_col_list, datatable_data for the columns and data parameters of 
    the dash_table.DataTable'''
    datatable_col_list = []
        
    levels = df.columns.nlevels
    if levels == 1:
        for i in df.columns:
            datatable_col_list.append({"name": i, "id": i})
    else:        
        columns_list = []
        for i in df.columns:
            col_id = flatten_char.join(i)
            datatable_col_list.append({"name": i, "id": col_id})
            columns_list.append(col_id)
        df.columns = columns_list

    datatable_data = df.to_dict('records')
    
    return datatable_col_list, datatable_data