Adding rows of datatable with drop-down list as input

Hi:

I am new to Dash and I am working on a interactive table these days. I am following the example here: Editable DataTable | Dash for Python Documentation | Plotly for adding new rows in a table. However, I would like to prefer adding a new function that whenever I add a new row, the cell of the row will have the drop-down list that shows the valid options. However my code doesn’t work:

import dash
from dash.dependencies import Input, Output, State
import dash_table
import dash_core_components as dcc
import dash_html_components as html
from collections import OrderedDict
import pandas as pd

app = dash.Dash(__name__)


columns = ['Business Unit', 'Strategic Initiative', 'Projects', 'FTE 2021', 'PD 2021', 'Time Start', 'Time Duration']
BU = ['L', 'P', 'D', 'S']

columns_list = [{'name': 'Business Unit', 'id': 'columns 0', 'deletable': False, 'renamable': False, 'presentation': 'dropdown'}]
columns_list.extend([{
                'name': columns[i],
                'id': f'columns {i}',
                'deletable': False,
                'renamable': False
                } for i in range(1, len(columns))])


app.layout = html.Div([
        dash_table.DataTable(
            id='my-table',
            columns = columns_list,
            data=[],
            editable=True,
            row_deletable=True,
            
            dropdown={
                'Business Unit': {
                    'options': [
                        {'label': i, 'value': i}
                        for i in BU
                    ]
                }
            },
            
            style_cell={'textAlign': 'middle'},
            
            style_data_conditional=[
                {
                    'if': {'row_index': 'odd'},
                    'backgroundColor': 'rgb(248, 248, 248)'
                }
            ],
            
            style_header={
                'backgroundColor': 'rgb(230, 230, 230)',
                'fontWeight': 'bold'
            }
        ),


        html.Br(),
        html.Button('Add New Row', id='editing-rows-button', n_clicks=0),
        html.Button('Calculate PD', id='calculate-pd', n_clicks=0, style={"margin-left": "15px"}),

])

@app.callback(
        Output('my-table', 'data'),
        [Input('editing-rows-button', 'n_clicks'),
         Input('calculate-pd','n_clicks')],
        [State('my-table', 'data'),
         State('my-table', 'columns')])
def add_row(btn1, btn2, rows, columns):
    ctx = dash.callback_context

    if not ctx.triggered:
        button_id = 'No clicks yet'
    else:
        button_id = ctx.triggered[0]['prop_id'].split('.')[0]
    
    #if n_clicks > 0:
    if button_id == 'editing-rows-button':
        rows.append({c['id']: '' for c in columns})
    elif button_id == 'calculate-pd':
        for row in rows:
            try:
                row['columns 4'] = float(row['columns 3']) * 251
            except:
                row['columns 4'] = 0
    return rows



if __name__=='__main__':
    app.run_server(host='0.0.0.0', debug=False)

Could you help me to figure how to perform this? Thanks

This is the adoption of dash documentation examples to achieve needed functionality:

from dash import Dash, dash_table, html
from dash.dependencies import Input, Output, State
from collections import OrderedDict
import pandas as pd

app = Dash(__name__)

df = pd.DataFrame(OrderedDict([
    ('climate', ['Sunny', 'Snowy', 'Sunny', 'Rainy']),
    ('temperature', [13, 43, 50, 30]),
    ('city', ['NYC', 'Montreal', 'Miami', 'NYC'])
]))


app.layout = html.Div([
    dash_table.DataTable(
        id='table-dropdown',
        data=df.to_dict('records'),
        columns=[
            {'id': 'climate', 'name': 'climate', 'presentation': 'dropdown'},
            {'id': 'temperature', 'name': 'temperature'},
            {'id': 'city', 'name': 'city', 'presentation': 'dropdown'},
        ],

        editable=True,
        row_deletable=True,

        dropdown={
            'climate': {
                'options': [
                    {'label': i, 'value': i}
                    for i in df['climate'].unique()
                ]
            },
            'city': {
                'options': [
                    {'label': i, 'value': i}
                    for i in df['city'].unique()
                ]
            }
        }
    ),

    html.Button('Add Row', id='table-dropdown-button', n_clicks=0)
])


@app.callback(
    Output('table-dropdown', 'data'),
    Input('table-dropdown-button', 'n_clicks'),
    State('table-dropdown', 'data'),
    State('table-dropdown', 'columns'))
def add_row(n_clicks, rows, columns):
    if n_clicks > 0:
        rows.append({c['id']: '' for c in columns})
    return rows


if __name__ == '__main__':
    app.run_server(debug=True)

Here is the result:
2023-04-19 11-07-57

1 Like