How to update html table values by dropdown list

Hello!
I am trying to update html table values depending on a dropdown list menu. The program it is supposed to read all the necessary from a database (.db) but applying a filter depending on a “device selection”.

I am doing the following to generate the table, I don’t show the function “read_db” as is simple what it does:

def operation_limits_table(dev_sel):
    # Filling up rows of the table
    id_weak_max = read_db(dev_sel, 'id_weak_max', '')
    id_mod_max = read_db(dev_sel, 'id_mod_max', '')
    id_strong_max = read_db(dev_sel, 'id_strong_max', '')

    gm_weak_max = read_db(dev_sel, 'gm_weak_max', '')
    gm_mod_max = read_db(dev_sel, 'gm_mod_max', '')
    gm_strong_max = read_db(dev_sel, 'gm_strong_max', '')

    my_dict = {
        'id':{
            'min' : ['weak →', id_weak_max[0], '← moderate →', id_mod_max[0], '← strong →', id_strong_max[0], '← vel.sat'],
            'max' : ['weak →', id_weak_max[1], '← moderate →', id_mod_max[1], '← strong →', id_strong_max[1], '← vel.sat']
        },
        'gm':{
            'min' : ['weak →', gm_weak_max[0], '← moderate →', gm_mod_max[0], '← strong →', gm_strong_max[0], '← vel.sat'],
            'max' : ['weak →', gm_weak_max[1], '← moderate →', gm_mod_max[1], '← strong →', gm_strong_max[1], '← vel.sat']
        }
    }

    bodyTrs = []
    for param in my_dict:
        rowTds = []
        rowTds.append(html.Td(param, rowSpan=2))
        for lab in my_dict[param]:
            rowTds.append(html.Td(lab))
            for val in my_dict[param][lab]:
                rowTds.append(html.Td(val))
            bodyTrs.append(html.Tr(rowTds))
            rowTds = []

    table = html.Table([
        html.Thead([
            html.Tr([
                html.Th('Parameter', style=header_index_cell_style),
                html.Th('Type', style=header_index_cell_style),
                html.Th('t1', style=header_index_cell_style),
                html.Th('v1', style=header_column_cell_style),
                html.Th('t2.', style=header_column_cell_style),
                html.Th('v2', style=header_column_cell_style),
                html.Th('t3.', style=header_column_cell_style),
                html.Th('v3', style=header_column_cell_style),
                html.Th('t4', style=header_column_cell_style)
            ])
        ], style=header_section_style),
        html.Tbody(bodyTrs)
    ], id='op_limits_table')
    return table

I set the layout in this way:

# =========================================================================================== #
#                                       MAIN APP
# =========================================================================================== #
app = Dash(__name__)

# Define the layout of the Dashboard
app.layout = [
    html.Div(children='Technology Characterization'),
    dcc.Dropdown(dev_list, dev_list[0], id='device_selection'),
    dcc.Dropdown(id='dim_sel'),
    dcc.Dropdown(id='temp_sel'),
    dcc.Dropdown(id='skew_sel'),
    operation_limits_table(dev_sel)
]

There will be more dropdown list in the future, but let’s focus in only one. My callbacks:

# =========================================================================================== #
#                                          CALLBACKS
# =========================================================================================== #
# Callback for device selection
@callback(
    [Output(component_id='img_testbench_sel', component_property='src'),
    Output(component_id='img_testbench_text', component_property='children'),
    Output(component_id='dim_sel', component_property='options'),
    Output(component_id='temp_sel', component_property='options'),
    Output(component_id='skew_sel', component_property='options')],
    [Input(component_id='device_selection', component_property='value')]
)
def update_testbench_image(device_sel):
    img_path = app.get_asset_url(device_sel + '.png') 
    # dim_options = update_sel_options(device_sel, "nlength")
    dim_options =  [{'label': 'Select all', 'value': 'all_values'}] + [{'label':str(np.round(x*1e6, 2)) + u" \u03bcm", 'value':x} for x in update_sel_options(device_sel, "nlength")]
    temp_options = [{'label': 'Select all', 'value': 'all_values'}] + [{'label':str(int(x))+u' \N{DEGREE SIGN}C', 'value':x} for x in update_sel_options(device_sel, "TDEGC")]
    skew_options = [{'label': 'Select all', 'value': 'all_values'}] + [{'label':x, 'value':x} for x in update_sel_options(device_sel, "skew")]
    return img_path, img_path, dim_options, temp_options, skew_options


###############
@callback(
    [Output(component_id='op_limits_table', component_property='children')],
    [Input(component_id='device_selection', component_property='value')]
)
def update_op_limits(device_sel):
    return operation_limits_table(device_sel)

The important one is the last one, I don’t know how to do it to update the table values in this callback.

This is the result in the page:

But I get this error, and values are not updating depending on the device selection:

If somebody could give me a hand, I’ll appreciate it a lot, thanks!

Hey @Josane13, welcome to the forums.

Wrap your returns with a list like this:

return [operation_limits_table(device_sel)]

You need to do this, because of having the Output() in a list:

[Output(component_id='op_limits_table', component_property='children')]

:blush: Hablas español?!! Why a html Table?
Why don’t you try https://dash.plotly.com/dash-ag-grid/getting-started some AG-Grid o Datatable?
You’ve already got a dict there to put it into a table, give it a try and see what happens.
Anyway, I hope you could figure it out!

Hi @AIMPED ! Thanks, now the table appears and update, but I don’t know why appears twice, I think it’s because I am calling the function two times, one in the app.layout, second in the callback but I don’t know how to manage that in another way:

Hola @JuanG :blush: Sí, hablo español, estoy usando una tabla html porque no he encontrado la forma de combinar filas con AG-Grid o Datatable, no sé si sabes si hay alguna forma.


I’m using a html table because I couldn’t find a way to merge rows using “AG-Grid” or Datatable, but for sure this will be easier, on the other hand I want to format the table like following example, and I think it will be more straightforward with html:

Thanks and regards,
Jose Antonio.

1 Like

Hi!

At the end I could manage to solve this, it seems the “id” and table generation should be in “layout” not inside the function, I did the following and now is working:

        html.Div([
            html.Div(html.H2('OP-LIMITS')),
            html.Div(html.Table([html.Tbody(operation_limits_table(dev_default), id='op_limits_table')]))
        ],

The function only returns the body of the table:

def operation_limits_table(dev_sel, filter_sel=''):
    # Filling up rows of the table
    for param in param_list:
        globals()[param + "_weak_max"] = read_db(dev_sel, param + '_weak_max', filter_sel)
        globals()[param + "_mod_max"] = read_db(dev_sel, param + '_mod_max', filter_sel)
        globals()[param + "_strong_max"] = read_db(dev_sel, param + '_strong_max', filter_sel)

    # Create dictionary with the results
    my_dict = {}
    for param in param_list:
        my_dict[param] = {}
        my_dict[param]['min'] =  ['weak →', Quantity(globals()[param + "_weak_max"][0], param_list[param]).render(prec=2), '← moderate →', Quantity(globals()[param + "_mod_max"][0], param_list[param]).render(prec=2), '← strong →', Quantity(globals()[param + "_strong_max"][0], param_list[param]).render(prec=2), '← vel.sat']
        my_dict[param]['max'] =  ['weak →', Quantity(globals()[param + "_weak_max"][1], param_list[param]).render(prec=2), '← moderate →', Quantity(globals()[param + "_mod_max"][1], param_list[param]).render(prec=2), '← strong →', Quantity(globals()[param + "_strong_max"][1], param_list[param]).render(prec=2), '← vel.sat']

    bodyTrs = []
    for param in my_dict:
        rowTds = []
        rowTds.append(html.Td(param, rowSpan=2, className='table-highlight'))
        for labl in my_dict[param]:
            rowTds.append(html.Td(labl, className='table-highlight'))
            for val in my_dict[param][labl]:
                rowTds.append(html.Td(val))
            # For the latest add the border
            if (labl == list(my_dict[param])[-1]):
                bodyTrs.append(html.Tr(rowTds))
            else:
                bodyTrs.append(html.Tr(rowTds))
            rowTds = []

    return bodyTrs
    # return table

Thanks a lot!

It´s looking pretty good!