Search code examples
pythonplotlyplotly-dashplotly-python

Table with subcolumns under go.Table and go.Figure


I am having trouble on making a table for a dash dashboard go.Figure() using go.Table() (I am open to other suggestions) that has different number of columns inside one, as for example:

|Column 1       | Column 2        |
|Sub C.1|Sub C.2| Sub C.1| Sub C.2|
| data1 | data2 | data 3 | data 4 |

It always sets the "extra" columns to the right.

Here is the code of my failed last attempt:

import plotly.graph_objects as go

tb1 = go.Table(
    header=dict(values=['<b>Column 1</b>', '<b>Column 2</b>'],
                fill_color='paleturquoise',
                align='left'),

)


tb2 = go.Table(
    header=dict(values=['<b>Sub 1</b>', '<b>Sub 1</b>', '<b>Sub 2</b>', '<b>Sub 2</b>'],
                fill_color='paleturquoise',
                align='left'),
    cells=dict(values=[[1, 2], [3, 4], [5, 6], [7, 8]],
               fill_color=[['brown', 'green'], 'red', ],
               align='left'),

)



overall = go.Figure(data=[tb1, tb2])
overall.show()

Thank you for the feedback!


Solution

  • Here is a working example using dash_table, that also has how to set conditional colors:

    import dash_table
    import dash
    import pandas as pd
    
    
    def datatable_settings_multiindex(df, flatten_char='_'):
        ''' Plotly dash datatables do not natively handle multiindex dataframes.
        This function generates a flattend column name list for the dataframe,
        while structuring the columns to maintain 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:
                i = [str(x) for x in i]
                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
    
    
    delays = pd.Series(data=['delay 1', 'delay 2', 'delay 3'], index=['F1', 'F2', 'F3'])
    jitters = pd.Series(data=['jitter 1', 'jitter 2', 'jitter 3'], index=['F1', 'F2', 'F3'])
    delays2 = pd.Series(data=['delay 1', 'delay 2', 'delay 3'], index=['F1', 'F2', 'F3'])
    jitters2 = pd.Series(data=['jitter 1', 'jitter 2', 'jitter 3'], index=['F1', 'F2', 'F3'])
    df = pd.concat([delays, jitters, delays2, jitters2], axis=1)
    df.columns = pd.MultiIndex.from_product([[1, 2], ['Delays', 'Jitters']])
    df.insert(0, 'Files', ['File 1', 'File 2', 'File 3'])
    
    df_columns, df_data = datatable_settings_multiindex(df)
    
    col_del1 = pd.Series(data=["blue", "gray", "black"])  # , index=['F1', 'F2', 'F3'])
    col_jit1 = pd.Series(data=["purple", "pink", "green"])  # , index=['F1', 'F2', 'F3'])
    col_del2 = pd.Series(data=["blue", "gray", "black"])  # , index=['F1', 'F2', 'F3'])
    col_jit2 = pd.Series(data=["purple", "pink", "green"])  # , index=['F1', 'F2', 'F3'])
    df_col = pd.concat([col_del1, col_jit1, col_del2, col_jit2], axis=1)
    df_col.columns = pd.MultiIndex.from_product([[1, 2], ['Delays', 'Jitters']])
    df_col.insert(0, 'Files', ["red", "yellow", "orange"])
    
    #
    c_list = []
    
    df_columns[0]['name'][1] = df_columns[0]['name'][0]
    
    j = 0
    for row in df_col.itertuples():
        for i in range(len(df_columns)):
            color_dict = {}
            color_dict.update(
                {
                    'if': {'row_index': row[0], 'column_id': df_columns[i]['id']},
                    'backgroundColor': row[i + 1]
                }
            )
            c_list.append(color_dict)
        j += 1
    
        #######
    # Create a Dash app
    app = dash.Dash()
    
    # Add the table to the app
    app.layout =dash_table.DataTable(
        id='datatable_id',
        columns=df_columns,
        data=df_data,
    
        style_data_conditional=c_list,
    
        style_header={
            'backgroundColor': 'gray',
            'fontWeight': 'bold'
        },
        merge_duplicate_headers=True
    )
    
    # Run the app
    app.run_server(debug=True)