1

I have two tables where the input of the first one (let's call it A) creates a second table (B). Teh first callback works fine, but after the second callback of clicking A, B is not updating anymore. Found a similiar issue here with no response though. Does anything have to be specified in the callback for the table to update? Below is a small example that demonstrates the issue (clicking once Texas for example creates a second table, but clicking Nevada afterwards does nothing). Any help would be appreciated. Thanks!

import dash
from dash import html, dcc, Output, Input, State, Dash
import dash_bootstrap_components as dbc
import pandas as pd
from dash.exceptions import PreventUpdate

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
df = pd.read_csv(
    'https://raw.githubusercontent.com/plotly/datasets/master/solar.csv')
df['user'] = '-'
df['date'] = '-'
data = {'State':  ['Texas', 'Texas', 'Texas', 'Nevada', 'Nevada', 'Nevada'],
        'Number of Solar plants': [12, 10, 13, 10, 9, 11]
        }

df2 = pd.DataFrame(data)

@app.callback(
        Output('selected_cell', 'children'),
        Output('tbl2', 'children'),
        Input('tbl', 'active_cell'),
        State('tbl', 'data')
)
def get_selected_cell(active_cell, data):
    if active_cell:
        col = active_cell['column_id']
        row = active_cell['row']
        cellData = data[row][col]
        # only if column relevant
        if active_cell['column_id'] == 'State':
            subset = df2[df2['State'] == cellData]
            selected_cell_element= html.P(cellData, id='selected_cell')
            selected_subset_table = html.Div(dash.dash_table.DataTable(
                data=subset.to_dict('records'),
                columns=[{"name": i, "id": i} for i in subset.columns],
                id='tbl2'
            ))
            return selected_cell_element,selected_subset_table
    else:
        raise PreventUpdate
    
app.layout = html.Div([
    dbc.Label('Click a cell in the table:'),
    dash.dash_table.DataTable(
        data=df.to_dict('records'),
        columns=[{"name": i, "id": i} for i in df.columns],
        id='tbl'),
    dbc.Alert(id='tbl_out'),
    html.Div(id='selected_cell'),
    html.Div(id='tbl2')
])

if __name__ == '__main__':
    app.run_server(debug=True, port=9100)
    
mizzlosis
  • 515
  • 1
  • 4
  • 17

2 Answers2

1

Figured it out: solution was that I named the div the same as the output of the div with the below changes it worked.

import dash
from dash import html, dcc, Output, Input, State, Dash
import dash_bootstrap_components as dbc
import pandas as pd
from dash.exceptions import PreventUpdate

app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
df = pd.read_csv(
    'https://raw.githubusercontent.com/plotly/datasets/master/solar.csv')
df['user'] = '-'
df['date'] = '-'
data = {'State':  ['Texas', 'Texas', 'Texas', 'Nevada', 'Nevada', 'Nevada'],
        'Number of Solar plants': [12, 10, 13, 10, 9, 11]
        }

df2 = pd.DataFrame(data)

@app.callback(
        Output('selected_cell', 'children'),
        Output('tbl2_div', 'children'), #<- change------
        Input('tbl', 'active_cell'),
        State('tbl', 'data')
)
def get_selected_cell(active_cell, data):
    if active_cell:
        col = active_cell['column_id']
        row = active_cell['row']
        cellData = data[row][col]
        # only if column relevant
        if active_cell['column_id'] == 'State':
            subset = df2[df2['State'] == cellData]
            selected_cell_element= html.P(cellData, id='selected_cell')
            selected_subset_table = html.Div(dash.dash_table.DataTable(
                data=subset.to_dict('records'),
                columns=[{"name": i, "id": i} for i in subset.columns],
                id='tbl2'
            ))
            return selected_cell_element,selected_subset_table
    else:
        raise PreventUpdate
    
app.layout = html.Div([
    dbc.Label('Click a cell in the table:'),
    dash.dash_table.DataTable(
        data=df.to_dict('records'),
        columns=[{"name": i, "id": i} for i in df.columns],
        id='tbl'),
    dbc.Alert(id='tbl_out'),
    html.Div(id='selected_cell'),
    html.Div(id='tbl2_div') #<- change------
])

if __name__ == '__main__':
    app.run_server(debug=True, port=9100)
    
python

mizzlosis
  • 515
  • 1
  • 4
  • 17
0

Thanks for the example, that really helped. The problem is your conditional statements. Your PreventUpdate condition cannot be reached if there is an active cell, but it isn't from the "State" column. Just change it to the below, and it works. This way, all paths through the logic have an explicit end. Otherwise, the function returns None and breaks the callback.

def get_selected_cell(active_cell, data):
    if active_cell:
        col = active_cell['column_id']
        row = active_cell['row']
        cellData = data[row][col]
        # only if column relevant
        if active_cell['column_id'] == 'State':
            subset = df2[df2['State'] == cellData]
            selected_cell_element= html.P(cellData, id='selected_cell')
            selected_subset_table = html.Div(dash.dash_table.DataTable(
                data=subset.to_dict('records'),
                columns=[{"name": i, "id": i} for i in subset.columns],
                id='tbl2'
            ))
            return selected_cell_element,selected_subset_table
    raise PreventUpdate
coralvanda
  • 6,431
  • 2
  • 15
  • 25
  • Thanks for the prompt response- Did you change anything else? Adding the change unfortunately does not work for me. :( – mizzlosis Jun 05 '22 at 23:51
  • That was the only change I made. The second table updated after each click, which was the issue, right? – coralvanda Jun 06 '22 at 02:26
  • Yes that was the issue- but I still have the same issue that the table does not update after the second click- only the html.P with the selected cell updates. Might it have something to do with the dash version? Which one are you using? – mizzlosis Jun 06 '22 at 08:53