Issue - displaying a dataframe with filters

Hello everyone,

I’m a newbie here and I’m glag to start using Dash. I have some knwoledge in Python and Pandas. For my first dashboard, I’m using a French database about food. I just want to:
1- Display a table (dataframe)
2- Make a selection on one or several columns using a dropdown tool and update the table according to this selection.

I looked at the Dash tutorial and guide so as some posts on this forum but I just don’t understand what is happening with my program. I don’t understand the issue and I need some help. I got a Callback error updating data_table.

I’m also not sure to understand how to write the callback. I apparently need to create a def in it but I don’t understand when the parameters I create in this definition are called and how they are linked to my dropdown choices.

I also read somewhere that sometimes we need several callbacks. But in some graph examples I saw in the data guide, they were using only one callback.

Here’s my code. Could you give me some advices?

Thanks so much!
Alpy

# =============================================================================
# Initialization
# =============================================================================

# Packages
# --------

# Pandas
import pandas as pd

# Numpy
import numpy as np

# Functools
from functools import reduce

# Datetime timedelta
from datetime import timedelta

import os
import datetime
import sys
import random

# Plotly Dash
import dash
import dash_core_components as dcc
import dash_html_components as html
import dash_table
from dash.dependencies import Input, Output
from dash_table import DataTable
from dash.exceptions import PreventUpdate

# Plotly
import plotly.express as px


# =============================================================================
# Data importation
# =============================================================================

# AGRIBALYSE.xlsx
agribalyse = pd.ExcelFile (r'E:\Programmation\Python\Agribalyse\AGRIBALYSE.xlsx')

# Detail ingrédient sheet
tmp_ingredients = pd.read_excel(agribalyse, r'Detail ingredient')


# =============================================================================
# Data management
# =============================================================================

# Abribalyse database with fill-in of all missing rows for products
ingredients=tmp_ingredients.fillna(method='ffill')

# List of columns to display in the application
ingredients_tab_data=ingredients[["Nom Français", "Groupe d'aliment", "Sous-groupe d'aliment", "Ingredients"]]

# List of available products
available_produtcs = ingredients['Nom Français'].unique()



# =============================================================================
# Dash application
# =============================================================================

# Style sheet
# -----------

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']


# Application call
# ----------------

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
        html.Div([
                html.H1("Agribalyse"),
                html.Div('''
                         This is a database about food and ecology. The table below shows the products and ingredients.
                         '''),
                html.Div('')
        ]),
        html.Div([
                dcc.Dropdown(
                        id='select_column',
                        options=[{'label':i, 'value': i} for i in available_produtcs],
                        value='Pizza jambon fromage',
                        #multi=True
                )
        ]),
        dash_table.DataTable(
            id='data_table',
            columns=[{"name": i, "id": i} for i in ingredients_tab_data.columns],
            data=ingredients_tab_data.to_dict("rows")
        )
])                
             
@app.callback(
        Output('data_table', 'data'),
        Input('select_column', 'value')
)

def update_table(value):
    data=ingredients_tab_data[ingredients_tab_data["Nom Français"] == value]
    return data

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

Hi @Alpy And welcome to the Dash community :slight_smile:

The data in the table needs to be in the required format, which is a list of dictionaries. In the table definition, it’s done like this:

data=ingredients_tab_data.to_dict("rows")

The callback needs to be the same… currently, the data is still a dataframe. You could try something like:

    dff=ingredients_tab_data[ingredients_tab_data["Nom Français"] == value]
    return dff.to_dict("rows")

Note: if you are on the latest version of Pandas you may get a runtime message like this:

...pandas/core/frame.py:1485: FutureWarning: Using short name for 'orient' is deprecated. Only the options: ('dict', list, 'series', 'split', 'records', 'index') will be used in a future version. Use one of the above to silence this warning.

You can fix it by changing:
data=dataframe.to_dict("rows"),
to this:
data=dataframe.to_dict("records"),

PS… This sounds delicious :yum:

'Pizza jambon fromage' 
1 Like

Hi @AnnMarieW and thank you very much for your answer. This is just working fine now.

I’m not sure I understood how is working the definition though. Wheh I put the following code, it’s working but I never initialized the parameter nor set it during the execution of the application. How my parameter “product” is linked to my dropdown since I never called anything as “product” before in the program?

def update_table(product):
    data=ingredients_tab_data[ingredients_tab_data["Nom Français"] == product]
    return data.to_dict("rows")

Also I’d like to ask a question if I may:
I’d like to get, at first, the dataset fully displayed. I set the value to value=[ ] in the dropdown. It is working, and I can use my dropdown as usual. Still I got a callback error: ValueError: Lengths must match to compare. Do you know a way out of this issue?

Thank you very much again! (And yes, “pizza jambon fromage” is really good, it’s like a Regina : ] )

Initializing the function variables is one of the magic things that happens with the Dash callback decorator.

The callback is triggered whenever any of the Inputs - (In your program, the dropdown) changes. You only have one Input which is the value property of the dropdown. You can use any name for the input argument in the function - it automatically corresponds to the Input in the decorator.

When you have multiple Inputs, the arguments are positional - just like any Python function. In a Dash callback, they need to match the order they appear in the @app.callback decorator.

More on callbacks here: https://dash.plotly.com/basic-callbacks

The error is a Pandas thing. If the dropdown is set to multi = True, then value is a list. The filter would look like:

data=ingredients_tab_data[ingredients_tab_data["Nom Français"].isin(product)]
1 Like

Thank you again, sorry for my late answer. This is working fine now ! : )

1 Like