3

I am trying to display a data frame with Dash. The data frame that I have is https://www.kaggle.com/timoboz/superbowl-history-1967-2020. My goal is to show the data frame on the webpage with one search button that dynamically searches all the columns and filters the data frame.

So far, I have the following code that displays the dataframe.

import pandas as pd
import dash
import dash_table
from dash.dependencies import Input, Output
df  = pd.read_csv('./Data/superbowl.csv')
PAGE_SIZE = 10
app = dash.Dash(__name__)

app.layout = dash_table.DataTable(
    id='datatable-paging',
    columns=[
        {"name": i, "id": i} for i in df.columns #sorted(df.columns)
    ],
    page_current=0,
    page_size=PAGE_SIZE,
    page_action='custom',

    sort_action='custom',
    sort_mode='single',
    sort_by=[]
)


@app.callback(
    Output('datatable-paging', 'data'),
    [Input('datatable-paging', "page_current"),
     Input('datatable-paging', "page_size"),
     Input('datatable-paging', 'sort_by')])
def update_table(page_current,page_size,sort_by):
    if len(sort_by):
        dff = df.sort_values(
            sort_by[0]['column_id'],
            ascending=sort_by[0]['direction'] == 'asc',
            inplace=False
        )
    else:
        # No sort is applied
        dff = df

    return dff.iloc[
           page_current * page_size:(page_current + 1) * page_size
           ].to_dict('records')



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

Output so far After reading through the documentation https://dash.plot.ly/datatable/callbacks especially 'Backend Paging with Filtering', I couldn't find a way to have like a single textbox that would search all the columns and filter the data frame for the matched entries.

3
  • Try adding filter_action='native' as an argument within dash_table.DataTable Commented Feb 18, 2020 at 15:33
  • 1
    @sumshyftw that adds filtering per column. I am trying to consolidate all the filter to one textbox/input box which filters across all the columns. Commented Feb 18, 2020 at 16:26
  • filter_action native is not server side sorting AFAIK Commented May 28, 2020 at 21:10

1 Answer 1

7

The best way to do this would be to use an input component for your search query. This can then update the table by doing a pandas filter. This returns all the rows where any cell contains the text.

Example filter callback below:

@app.callback(
    Output('datatable', 'data'),
    [Input('filter-input', 'value')])
def update_table(filter_string):
    dff = df[df.apply(lambda row: row.str.contains(filter_string, regex=False).any(), axis=1)]
    return dff.to_dict('records')

Your input component below (note the use of debounce - this means that the callback will only be actioned when the user presses enter):

With import dash_core_components as dcc

dcc.Input(value='', id='filter-input', placeholder='Filter', debounce=True)

Taking your current code and putting this all together:

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

df = pd.read_csv('./Data/superbowl.csv')
PAGE_SIZE = 10
app = dash.Dash(__name__)

app.layout = html.Div([
    dcc.Input(value='', id='filter-input', placeholder='Filter', debounce=True),
    dash_table.DataTable(
        id='datatable-paging',
        columns=[
            {"name": i, "id": i} for i in df.columns  # sorted(df.columns)
        ],
        page_current=0,
        page_size=PAGE_SIZE,
        page_action='custom',

        sort_action='custom',
        sort_mode='single',
        sort_by=[]
    )
])


@app.callback(
    Output('datatable-paging', 'data'),
    [Input('datatable-paging', 'page_current'),
     Input('datatable-paging', 'page_size'),
     Input('datatable-paging', 'sort_by'),
     Input('filter-input', 'value')])
def update_table(page_current, page_size, sort_by, filter_string):
    # Filter
    dff = df[df.apply(lambda row: row.str.contains(filter_string, regex=False).any(), axis=1)]
    # Sort if necessary
    if len(sort_by):
        dff = dff.sort_values(
            sort_by[0]['column_id'],
            ascending=sort_by[0]['direction'] == 'asc',
            inplace=False
        )

    return dff.iloc[
           page_current * page_size:(page_current + 1) * page_size
           ].to_dict('records')


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

Hope this helps,

Ollie

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.