Callback dataframe output, "ValueError: Wrong number of items passed"

When I try to output a bootstrap table (dbc.Table.from_dataframe()) into my layout, I get “ValueError: Wrong number of items passed 18, placement implies 1”.

Here’s a generic example of what I’m trying to do. I think I’m missing something simple. Any thoughts? I’ve tried only returning the dataframe, as well as returning the df inside of a component. I think this might be a pandas issue but I’m not sure.

df = pd.DataFrame('data.csv')

app.layout = dbc.Container(

    children=[
        
        dbc.Row(
            dbc.Col(
                dcc.Dropdown(
                    id="dropdown-1",
                    placeholder='Select something',
                    options=[{'label':x, 'value':x} for x in some_list],
                    value='something',
                    multi=False,
                    clearable=False
                )
            )
        ),
        
        dbc.Row(
            dbc.Col(
                html.Div(id='table')
            )
        )

    ]
)

@app.callback(
    Output('table', 'children'),
    Input('dropdown-1', 'value')
)
def my_dataframe_for_table(input_value):
    
    df_filtered = df[(df['filter_column'] == input_value)]

    return dbc.Card(dbc.Table.from_dataframe(df_filtered), body=True)

Hi @nlyle

It’s hard to see what’s going on without some sample data. Here is a MWE that you can try:

import dash
import pandas as pd
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc

df = pd.read_csv(
    "https://raw.githubusercontent.com/plotly/datasets/master/gapminderDataFiveYear.csv"
)

app = dash.Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])


controls = html.Div(
    dcc.Dropdown(
        id="dropdown",
        options=[{"label": i, "value": i} for i in df["country"].unique()],
        multi=True,
        value=[],
    ),
    className="m-4",
)

dbc_table = html.Div(id="dbc-table")

app.layout = dbc.Container(
    [
        html.H1("Table with a Dropdown"),
        html.Hr(),
        dbc.Row(dbc.Col([controls, dbc_table])),
    ],
    fluid=True,
)


@app.callback(Output("dbc-table", "children"), Input("dropdown", "value"))
def update_table(country_dd):
    dff = df.copy() if country_dd == [] else df[df["country"].isin(country_dd)]
    return dbc.Card(dbc.Table.from_dataframe(dff), body=True)


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

1 Like

Thanks @AnnMarieW, this helps me know I’m on the right track! Your code works in my browser, which is a good sign. I’m still having issues with my actual project data, and I think it has to do with how I’m manipulating my dataframe (maybe).

The error tells me that the “placement” is expecting something other than what I’m passing:ValueError: Wrong number of items passed 18, placement implies 1.

I can’t supply the actual data because it’s not public, but here’s a more accurate representation of what I’m trying to do:


# This df has 18 columns. The runtime error is "Wrong number of items passed 18, placement implies 1"
df = pd.DataFrame('data.csv')

app.layout = dbc.Container(
    fluid=True,
    children=[

        # I have two input dropdowns
        dbc.Row(
            [
                dbc.Col(
                    dcc.Dropdown(
                        id="dropdown-country",
                        placeholder='Select country',
                        options=[{'label':x, 'value':x} for x in df['country'].unique()],
                        value="United States",
                        multi=False,
                        clearable=False
                    ),
                    width=3.5
                ),

                dbc.Col(
                    dcc.Dropdown(
                        id="dropdown-year",
                        placeholder='Select years(s)',
                        options=[{'label':x, 'value':x} for x in df['year'].unique()],
                        value=[2018, 2019, 2020, 2021],
                        multi=True,
                        clearable=False
                    ),
                    width=3.5
                )
            ],
        ),
        dbc.Row(
            dbc.Col(
                html.Div(id='table-country-summary'), # output table
            )
        )
    ]
)

@app.callback(
    Output('table-country-summary', 'children'),
    Input('dropdown-country', 'value'),
    Input('dropdown-year', 'value')
)
def headcount_summary_df(country, year):
    
    # create a filtered dataframe
    df_filtered = df_headcounts[
    (df_headcounts['country'] == country) &
    (df_headcounts['year'].isin(year))
    ]

    # I only want a subset of columns
    df_display = df_filtered[['Col1', 'Col2', 'Col3', 'Col4']]

    return dbc.Card(
        dbc.Table.from_dataframe(
            df_display,
            striped=True,
            borderless=True,
            hover=True,
            responsive=True,
        ),
        body=True
    )

I noticed in your callback, you made a copy first (df.copy()). Does plotly expect me to do that? It seems it is registering the original 18 columns in my base dataframe, and the not the smaller df created in the callback. Or, maybe it’s something else.

Right, it’s probably something with the data.

You could try adding breakpoints and inspecting the data in your callback, or you can just add a print(df_filtered) and print(df_display) or print(df_display.info()) etc. to see what’s going on.

1 Like

Small update,: When I run the app and the components fail to load date due to the error, they seem to populate when I adjust an input dropdown. But the callback error still pops up. Not sure if that helps illuminate the possible cause. I have a feeling there’s some simple control flow I should add for the df prep.

Ok, thanks @AnnMarieW !