Table with subcolumns under go.Table and go.Figure

Question:

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!

Asked By: João P.

||

Answers:

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)
Answered By: João P.