Plotly Dash DataTable : How create Multi-Headers Table from Pandas Multi-Headers Dataframe

This is an example of creating a Multi-Headers Table as by Dash examples:

import dash
import dash_table
import pandas as pd

app = dash.Dash(__name__)

app.layout = dash_table.DataTable(
        {"name": ["", "Year"], "id": "year"},
        {"name": ["City", "Montreal"], "id": "montreal"},
        {"name": ["City", "Toronto"], "id": "toronto"},
        {"name": ["City", "Ottawa"], "id": "ottawa"},
        {"name": ["City", "Vancouver"], "id": "vancouver"},
        {"name": ["Climate", "Temperature"], "id": "temp"},
        {"name": ["Climate", "Humidity"], "id": "humidity"},
            "year": i,
            "montreal": i * 10,
            "toronto": i * 100,
            "ottawa": i * -1,
            "vancouver": i * -10,
            "temp": i * -100,
            "humidity": i * 5,
        for i in range(10)

if __name__ == '__main__':

enter image description here
This example of my pandas data frame :

data={('user_profile_id', ''): {0: 968, 1: 969},
 ('email', ''): {0: '', 1: ''},
 ('results', 'Cope'): {0: 15, 1: 25},
 ('results', 'Baba'): {0: 100, 1: 45},
 ('results', 'Susu'): {0: 120, 1: 75},
 ('results', 'Zizi'): {0: 150, 1: 52},
 ('results', 'Fufu'): {0: 250, 1: 2},
 ('feedback', 'Cope'): {0: 'Good', 1: 'Didn’t try it on'},
 ('feedback', 'Baba'): {0: 'Good', 1: 'Didn’t try it on'},
 ('feedback', 'Susu'): {0: 'Bad', 1: 'Didn’t try it on'},
 ('feedback', 'Zizi'): {0: 'Bad', 1: 'Didn’t try it on'},
 ('feedback', 'Fufu'): {0: 'Bad', 1: 'Didn’t try it on'}
df = pd.DataFrame.from_dict(data)

enter image description here

How can I make the Dash DataTable Multi-Headers as in the example from my Pandas Multi-Headers Dataframe?


Letting the table style aside, I believe there is a minor modification needed in the data and columns definition to make it work. In a nutshell, you need to transform the multiIndex in a single string in order to use it as column id in the DataFrame.
There are many ways of doing it, I will just write one that I believe is the simplest in your case.

For columns:

columns = [{"name": col, "id": "_".join(col)} for col in df.columns]

For data, I will use df.to_dict('records') format to do it, but I guess you could rename the columns on the fly when passing it to DataFrame:

data = [ {"_".join(col): val for col, val in row.items() } for row in df.to_dict('records')]

Note that the column ids are in the format level1_level2 (separated by _).

Hope that this helps!