KeyError: 'outputs_list'

Hello,

Looking for some help here. I’m working on a dashboard of sports data.

There are 2 inputs: a dropdown for offense type, and a checklist for seasons to include. Depending on offense type, a different table will be returned.

I get no errors when running the script in my IDE; it generates a dashboard with the inputs that I have in the layout. However, the table itself is just blank cells. Please note: the table itself loads with the new column names, and the table headers change when I change the checklist selection. However, the cells themselves remain blank.

When I attempt to run update_table with some manual input, I get the following error message:

output_spec = kwargs.pop(“outputs_list”)**
KeyError: ‘outputs_list’**

Callback script is posted below. Thanks in advance for any help.

@app.callback(
[Output(‘datatable’, ‘data’),
Output(‘datatable’,‘columns’)],
[Input(‘season_select’,‘value’),
Input(‘offense_type’, ‘value’)])

def update_table(season, offense_type):

dff = df[df.year.isin(season)]

passing_cols = ['Player','Team','Conference','Opponent','Week','Year','Pass Att','Comp','Pass Yds','Pass TD','INT','Sack','Fumble','EPA']
rushing_cols = ['Player','Team','Conference','Opponent','Week','Year','Rush Att','Rush Yds','Rush TD','Fumble','EPA']
receiving_cols = ['Player','Team','Conference','Opponent','Week','Year','Targets','Receptions','Receiving Yards','Receiving TDs','Fumble','EPA']

if offense_type == 'Passing':
    data = dff[dff.pass_attempt == 1].groupby(['passer'
            ,'offense'
            ,'offense_conference'
            ,'defense'
            ,'week'
            ,'year'])[['pass_attempt'
                ,'complete_pass'
                ,'yards_gained'
                ,'touchdown_pass'
                ,'interception'
                ,'sack'
                ,'fumble'
                ,'ppa']].sum().reset_index(drop=False).to_dict('records')
    columns=[{'name':i,'id':i} for i in passing_cols]

elif offense_type == 'Rushing':
    data = dff[dff.rush_attempt == 1].groupby(['rusher'
            ,'offense'
            ,'offense_conference'
            ,'defense'
            ,'week'
            ,'year'])[['rush_attempt'
                ,'yards_gained'
                ,'touchdown_rush'
                ,'fumble'
                ,'ppa']].sum().reset_index(drop=False).to_dict('records')
    columns=[{'name':i,'id':i} for i in rushing_cols]

else:
    data = dff[dff.pass_attempt == 1].groupby(['receiver'
            ,'offense'
            ,'offense_conference'
            ,'defense'
            ,'week'
            ,'year'])[['pass_attempt'
                ,'complete_pass'
                ,'yards_gained'
                ,'touchdown_pass'
                ,'fumble'
                ,'ppa']].sum().reset_index(drop=False).to_dict('records')
    columns=[{'name':i,'id':i} for i in receiving_cols]

return data, columns

if name == ‘main’:
app.run_server(debug=True)

Hi @superflexerff

One thing to check is that the column ids match the columns in the dataframe

As a test, try changing

columns=[{'name':i,'id':i} for i in passing_cols]

to:

columns=[{'name':i,'id':i} for i in data.columns]

Hi @AnnMarieW,

Since the script changes the dataframe to a dict, I get an attribute error:

AttributeError: ‘list’ object has no attribute ‘columns’

I have tried removing the .to_dict(‘records’) from inside the if statements and moving it down, but then I get an unhashable type error when I try to return data and columns at the end of the function. Updated script below–this script does not run.

@app.callback(
[Output(‘datatable’, ‘data’),
Output(‘datatable’,‘columns’)],
[Input(‘season_select’,‘value’),
Input(‘offense_type’, ‘value’),
Input(‘table_type’,‘value’),
Input(‘conference_select’,‘value’),
Input(‘team_select’,‘value’)])

def update_table(season, offense_type, table_type, conference, team):

#apply dropdown filters
dff = df[df.year.isin(season)]

#define columns for each offense type
passing_cols = ['Player','Team','Conference','Opponent','Week','Year','Pass Att','Comp','Pass Yds','Pass TD','INT','Sack','Fumble','EPA','EPA Per Pass']
rushing_cols = ['Player','Team','Conference','Opponent','Week','Year','Rush Att','Rush Yds','Rush TD','Fumble','EPA','EPA Per Rush']
receiving_cols = ['Player','Team','Conference','Opponent','Week','Year','Targets','Receptions','Receiving Yards','Receiving TDs','Fumble','EPA','EPA Per Target']

#logic for determining which table to return
if offense_type == 'Passing':
    odf = dff[dff.pass_attempt == 1].groupby(['passer'
            ,'offense'
            ,'offense_conference'
            ,'defense'
            ,'week'
            ,'year'])[['pass_attempt'
                ,'complete_pass'
                ,'yards_gained'
                ,'touchdown_pass'
                ,'interception'
                ,'sack'
                ,'fumble'
                ,'ppa']].sum().reset_index(drop=False)
    odf['per'] = odf.ppa/odf.pass_attempt
    columns=[{"name":i,"id":i} for i in passing_cols]

elif offense_type == 'Rushing':
    odf = dff[dff.rush_attempt == 1].groupby(['rusher'
            ,'offense'
            ,'offense_conference'
            ,'defense'
            ,'week'
            ,'year'])[['rush_attempt'
                ,'yards_gained'
                ,'touchdown_rush'
                ,'fumble'
                ,'ppa']].sum().reset_index(drop=False)
    odf['per'] = odf.ppa/odf.rush_attempt
    columns=[{"name":i,"id":i} for i in rushing_cols]

else:
    odf = dff[dff.pass_attempt == 1].groupby(['receiver'
            ,'offense'
            ,'offense_conference'
            ,'defense'
            ,'week'
            ,'year'])[['pass_attempt'
                ,'complete_pass'
                ,'yards_gained'
                ,'touchdown_pass'
                ,'fumble'
                ,'ppa']].sum().reset_index(drop=False)
    odf['per'] = odf.ppa/odf.pass_attempt
    columns=[{"name":i,"id":i} for i in receiving_cols]

#setting up the dataframe to pass
odf.columns = columns
data = odf.to_dict('records')


#return to datatable
return data, columns

if name == ‘main’:
app.run_server(debug=True)

Right - I missed the .to_dict in the first version.

The point is the ids in the datatable column parameter must match the column headings in the data - exactly. If the data column is “fumble” the datatable column id must be “fumble” and not “Fumble”

If you want the table to display different headings than the headings in the dataframe, you would put that in the name parameter. Or you could rename your dataframe column headings.

Try this:

odf = dff[dff.pass_attempt == 1].groupby(['passer'
            ,'offense'
            ,'offense_conference'
            ,'defense'
            ,'week'
            ,'year'])[['pass_attempt'
                ,'complete_pass'
                ,'yards_gained'
                ,'touchdown_pass'
                ,'interception'
                ,'sack'
                ,'fumble'
                ,'ppa']].sum().reset_index(drop=False)
    odf['per'] = odf.ppa/odf.pass_attempt
    columns=[{"name":i,"id":i} for i in odf.columns]
    data=odf.to_dict("records)

If this works, then you can go to step two and make the column headings display the way you want. I

If this doesn’t work, it would be helpful to make a minimal example with some sample data, and I’ll be able to be more helpful.

Thanks! It seems like this was the issue.

The point is the ids in the datatable column parameter must match the column headings in the data - exactly. If the data column is “fumble” the datatable column id must be “fumble” and not “Fumble"

When I run this script and look at the dashboard, I am now seeing a filled out table. In order to get the “friendly names” for the columns, I’m assigning the names to odf.columns, and then calling columns=[{“name”:i,“id”:i} for i in odf.columns]. I tested to make sure this works–now when I change the dropdown for “offense type” or “year”, the table updates automatically.

Thank you for your help!

Excellent! Glad it worked for you :grinning: