Filter Dash Table With Dropdown

Hello!

I am just getting started with Dash so apologies in advance if anything is confusing or if I mess up formatting of this topic post. I would like to be able to update a Dash-table with a dropdown component.

Context:
For a project I am working with recipe data to build a dashboard that lets a user search for recipes based on the ingredients they have on hand or length of preparation time. The fields in the data are things like ‘ingredients’, ‘description’, ‘recipe_id’ etc. The data has around 230000 rows. It is probably important here to point out that the ‘ingredients’ field is a field of lists, with each recipe containing a list value of all it’s ingredients as elements in this list. My goal is to have the user enter ingredients into a dropdown and have this dropdown update a dash table that only shows recipes which contain each of the user entered ingredients. I know that dash tables allow filtering but this doesn’t allow for entering multiple different ingredients (I think!).

implementation so far:
I have gotten my ‘ingredient’ field into a working drop down using the following:

#Read dataframe
recipe_rating = pd.read_csv('recipe_rating.csv')

#Establish a value and id pair dictionary of all the potential ingredients to appear in drop down component
recipe_rating["ingredients"] = recipe_rating["ingredients"].apply(eval)
ingredient_array = np.unique([*itertools.chain.from_iterable(recipe_rating.ingredients)])
ingredient_list = ingredient_array.tolist()
ingredient_dict = [{'label': i, 'value': i} for i in ingredient_list]

app.layout = html.Div([
    html.H1("Data Table GO!"),
    html.Br(),
    dcc.Dropdown(id = 'ingredient_dropdown', options = ingredient_dict, multi=True),...

The drop down appears as follows:

This allows the user to select multiple ingredients.

I have also been able to incorporate a dash-table but am having a hard time linking the two objects. My whole application so far is:

import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output
import pandas as pd
import plotly.express as px
from jupyter_dash import JupyterDash
import dash_table


#Establish a value and id pair dictionary of all the potential ingredients to appear in drop down component
ingredient_array = np.unique([*itertools.chain.from_iterable(recipe_rating.ingredients)])
ingredient_list = ingredient_array.tolist()
ingredient_dict = [{'label': i, 'value': i} for i in ingredient_list]

app = JupyterDash(__name__)

app.layout = html.Div([
    html.H1("Data Table GO!"),
    html.Br(),
    dcc.Dropdown(id = 'ingredient_dropdown', options = ingredient_dict, multi=True),
    html.Br(),
    html.Br(),
    dash_table.DataTable(
        id='recipe_datatable',
        columns=[{"name": i, "id": i} for i in sorted(recipe_rating.columns)],
        data=recipe_rating.to_dict('records'),  # starts table with all data 
        editable=True,              # allow editing of data inside all cells
        filter_action="native",     # allow filtering of data by user ('native') or not ('none')
        sort_action="native",       # enables data to be sorted per-column by user or not ('none')
        sort_mode="single",         # sort across 'multi' or 'single' columns
        column_selectable="multi",  # allow users to select 'multi' or 'single' columns
        row_selectable="multi",     # allow users to select 'multi' or 'single' rows
        row_deletable=True,         # choose if user can delete a row (True) or not (False)
        selected_columns=[],        # ids of columns that user selects
        selected_rows=[],           # indices of rows that user selects
        page_action="native",       # all data is passed to the table up-front or not ('none')
        page_current=0,             # page number that user is on
        page_size=8,                # number of rows visible per page
    ),

    html.Br(),
    html.Br(),
])

@app.callback(
Output('recipe_datatable', 'data'), #I used 'data' as the 'component_property' somewhat as guess
Input('ingredient_dropdown', 'value'))

def update_table(ingredients):
    ingredient_df = recipe_rating[recipe_rating['ingredients'].apply(lambda x: set(ingredients).issubset(set(x)))]
    recipe_dict = ingredient_df.to_dict()
    return recipe_dict #assumed I need dictionary to represent data in dash-table

app.run_server(mode="jupyterlab", port=2146)

When I run this application both the table and the dropdown correctly load but I am somehow not correctly linking them. My error message is:

In the callback for output(s):
recipe_datatable.data
Output 0 (recipe_datatable.data) is already in use.
Any given output can only have one callback that sets it.
To resolve this situation, try combining these into
one callback function, distinguishing the trigger
by using dash.callback_context if necessary.

I am a bit at a loss on what I need to be changing. I think it would be great for a user to be able to enter multiple ingredients and then further filter that with a dash-table. Any help would be really appreciated!

UPDATE:

I was able to get the functionality working. For posterity I will leave the above code. The fix was changing the line in my app call back function:

from:
recipe_dict = ingredient_df.to_dict()

to:
recipe_dict = ingredient_df.to_dict(‘records’)

Functionality is working but I am still getting an error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-21-ce88ef2df79d> in update_table(ingredients=None)
     49 
     50 def update_table(ingredients):
---> 51     ingredient_df = recipe_rating[recipe_rating['ingredients'].apply(lambda x: set(ingredients).issubset(set(x)))]
        ingredient_df = undefined
        global recipe_rating =         Unnamed: 0  recipe_id       user_id 

....


TypeError: 'NoneType' object is not iterable

Any insight on this new error would be great. Maybe it has something to do with the dropdown being initially blank? (I was having issues assigning a default dropdown value). Sorry this post has gotten so long - I didn’t see many related posts on applying a component to a table to I decided to leave all original material up.