[Python hundred days basic series] Day34 - Dash_table front-end sorting, filtering, selection and paging

Video Explanation:

1, Related functions

1.1 DataTable function of modifying and transforming data view

  • Sort by column (sort_action='native ')
  • Filter by column (filter_action='native ')
  • Edit cell (editable=True)
  • Delete row (row_deletable=True)
  • Delete columns (columns[i].deletable=True)
  • Select rows (row_selectable ='single '|'multi')
  • Select columns (column_selectable ='single '|'multi' and columns[i].selectable=True)
  • Paging front end (page_action='native ')
  • hidden_columns = [])

1.2 quick description of filtering

dash_table defines its own syntax to perform filtering operations. The following are some examples of specific data sets in this section:

  • Asia enter in the "container" field
  • 5000 enter in the gdpPercap column

  • < 80 enter in the "lifeExp" column

2, Sort or filter on the front page

2.1 code

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

# csv_url = 'https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv'
df = pd.read_csv('data/gapminder2007.csv')

app = dash.Dash(__name__)

app.layout = html.Div([
    dash_table.DataTable(
        id='datatable-interactivity',
        columns=[
            # Tables can be deleted and selected
            {"name": i, "id": i, "deletable": True, "selectable": True} for i in df.columns
        ],
        data=df.to_dict('records'),

        # Editable
        editable=True,

        # filter_action filtering mode: values of 'custom', 'native' or 'none'; Default value 'none'
        # ’none ', the filter UI is not displayed,
        # 'native', the filter UI is displayed, and the filter logic is processed by the table
        # ’custom ', the filtering UI is displayed, but the developer programs the filtering through callback (where filter_query or derived_filter_query_structure will be input and data will be output)
        filter_action="native",

        # sort_action sorting mode: the value of 'custom', 'native' or 'none'; Default value 'none'
        # ’none ', the sorting UI is not displayed
        #  'native', the sorting UI is displayed, and the sorting logic is processed by the table
        # ’custom ', the sorting UI is displayed, but the developers program the sorting through callbacks (sort_by input and data output)
        sort_action="native",

        #  sort_mode sorting mode: 'single' or 'multi'; Default value 'single'
        # 'single ': executed as a single column
        # 'multi ': sorting can be performed across multiple columns (for example, sorting by country / region, sorting within each country / region, sorting by year)
        sort_mode="multi",

        # column_selectable column selection mode: 'single', 'multi', or False; Default False
        # When you select a column, its id is included in the selected_ Columns and derived_ viewport_ selected_ In columns
        # Single, the user can select a single column or a group of merged columns through the radio button that appears in the header row
        # multi, the user can select multiple columns or merge column groups through the check box that will appear in the header row
        column_selectable="single",

        # row_selectable line selection mode: 'single', 'multi', or False; Default False
        # When a row is selected, its index is included in the selected_rows
        # Single, the user can select a single line through the radio button that will appear next to each line
        # multi, the user can select multiple rows by the check box that appears next to each row
        row_selectable="multi",

        # row_deletable: if True, an x will appear next to each row, and the user can delete the row
        row_deletable=True,

        # selected_columns contains the ID of the column selected by the UI element that appears when
        selected_columns=[],

        # selected_rows contains the index of the selected row in the UI element that appears when passing through
        selected_rows=[],

        # page_action paging mode: 'custom', 'native' or 'none'; default ‘native’
        # ’native ': all data is passed to the table in advance, and the paging logic is processed by the table
        # 'custom': data is transferred to the table page by page at a time, and paging logic is processed through callback
        # 'none': disable paging and render all data at once
        page_action="native",

        # Current page
        page_current= 0,

        # Lines per page, 250 by default
        page_size= 5,
    ),
    html.Div(id='datatable-interactivity-container')
])

@app.callback(
    Output('datatable-interactivity', 'style_data_conditional'),
    Input('datatable-interactivity', 'selected_columns')
)
def update_styles(selected_columns):
    return [{
        # Changes the background color of the selected column
        'if': { 'column_id': i },
        'background_color': '#D2F3FF'
    } for i in selected_columns]


@app.callback(
    Output('datatable-interactivity-container', "children"),
    # derived_virtual_data (dictionary list): this attribute indicates the visible status of all pages after data application front-end sorting and filtering
    Input('datatable-interactivity', "derived_virtual_data"),
    # derived_virtual_selected_rows: from selected_ The angle of rows represents the index (derived_virtual_indexes the order in which the original rows appear after filtering and sorting).
    Input('datatable-interactivity', "derived_virtual_selected_rows"))
def update_graphs(rows, derived_virtual_selected_rows):
    # When the table is rendered for the first time, ` derived_virtual_data ` and ` derived_virtual_selected_rows ` is' none '. This is due to an
    # This is due to a feature of Dash (Dash will call the callback function when rendering the component for the first time, and the unapplied attribute is always None)
    # Therefore, if 'rows' is' None', the component has just been rendered and its value will be the same as the component's dataframe.
    # You can also set 'derived' when initializing components_ virtual_ data=df.to_ Rows ('dict ') ` is set to' None 'instead of' None 'here.
    if derived_virtual_selected_rows is None:
        derived_virtual_selected_rows = []
    # First render, dff=df, otherwise dff equals
    dff = df if rows is None else pd.DataFrame(rows)
    # Selected and unselected rows are displayed in different colors
    colors = ['#7FDBFF' if i in derived_virtual_selected_rows else '#0074D9'
              for i in range(len(dff))]

    return [
        dcc.Graph(
            id=column,
            figure={
                "data": [
                    {
                        "x": dff["country"],
                        "y": dff[column],
                        "type": "bar",
                        "marker": {"color": colors},
                    }
                ],
                "layout": {
                	# The x-axis label rotates 45 degrees
                    "xaxis": {"automargin": True, 'tickangle': 45},
                    "yaxis": {
                        "automargin": True,
                        "title": {"text": column}
                    },
                    "height": 150,
                    "margin": {"t": 10, "l": 10, "r": 10},
                },
            },
        )
        # if column in dff checks whether the column exists, because the user may delete the column. If 'column.deletable=False', there is no need to check
        for column in ["pop", "lifeExp", "gdpPercap"] if column in dff
    ]


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

2.2 page display

3, Row ID

3.1 about row ID

  1. When using transformation (sorting, filtering, paging), it is difficult to match rows (visible rows, selected rows, active rows) with the original data because the row index may not have its original meaning. To simplify this logic, Dash adds support for Row IDs. Each row of data can have an 'ID' key, which should contain a string or a number. If you want to display these values, you can include columns with id = 'ID', but usually they remain hidden. All attributes of some rows are listed by index, and there are also variants of column TRAVEL ID:
  • derived_virtual_indices/ derived_virtual_row_ids: filter the row order of all pages after sorting (for front-end paging).
  • derived_viewport_indices/ derived_viewport_row_ids: the order of rows on the currently visible page.
  • selected_rows/ selected_row_ids: when row_ When selectable is enabled and there is a check box next to each row, these are the selected rows. Note that even filtered or paged rows can remain selected.
  • derived_virtual_selected_rows/ derived_virtual_selected_row_ids: selected rowset filtered and sorted across all pages
  • derived_viewport_selected_rows/ derived_viewport_selected_row_ids: the selected rowset on the currently visible page.
  1. Typically, several of these attributes contain the same data, but in other cases, it is important to choose the right attributes for the specific user interaction you think of. You want to respond to the selected rows, even if they are not on the current page, even if they are filtered out.
  2. There are also properties that refer to specific cells in the table. In addition to the row and column indexes, these include the row and column ID s of the cells:
  • active_cell: This is the data cell where the user places the cursor by clicking and / or arrow keys. It is a dictionary with keys:
    • Row: row index (integer) - may be affected by sorting, filtering, or paging conversion.
    • Column: column index (integer)
    • row_id: the field of the id line, which remains unchanged during the conversion process.
    • column_id: the field of the id column.
  • start_cell: if the user selects multiple cells, use shift click or shift arrow keys to start the selection. Has the same form as active_cell, and usually have the same value, but after selecting the area, the user can be active_cell changes by pressing or cycling through the selection of cells.
  • end_cell: opposite the corner of the selected area start_cell. It also has the same form as active_cell.
  • selected_cells: an array of dictionaries. The form of each dictionary is active_cell to list each selected cell.

3.2 same sample code implemented using row ID

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

# csv_url = 'https://raw.githubusercontent.com/plotly/datasets/master/gapminder2007.csv'
df = pd.read_csv('data/gapminder2007.csv')
# Add an id column and set it as the index. In this case, the only id happens to be the country name,
df['id'] = df['country']
df.set_index('id', inplace=True, drop=False)

app = dash.Dash(__name__)

app.layout = html.Div([
    dash_table.DataTable(
        id='datatable-row-ids',
        columns=[
            # Tables can be deleted and selected
            {"name": i, "id": i, "deletable": True} for i in df.columns
            # Omit id column
            if i !='id'
        ],
        data=df.to_dict('records'),

        # Editable
        editable=True,

        # filter_action filtering mode: values of 'custom', 'native' or 'none'; Default value 'none'
        # ’none ', the filter UI is not displayed,
        # 'native', the filter UI is displayed, and the filter logic is processed by the table
        # ’custom ', the filtering UI is displayed, but the developer programs the filtering through callback (where filter_query or derived_filter_query_structure will be input and data will be output)
        filter_action="native",

        # sort_action sorting mode: the value of 'custom', 'native' or 'none'; Default value 'none'
        # ’none ', the sorting UI is not displayed
        #  'native', the sorting UI is displayed, and the sorting logic is processed by the table
        # ’custom ', the sorting UI is displayed, but the developers program the sorting through callbacks (sort_by input and data output)
        sort_action="native",

        #  sort_mode sorting mode: 'single' or 'multi'; Default value 'single'
        # 'single ': executed as a single column
        # 'multi ': sorting can be performed across multiple columns (for example, sorting by country / region, sorting within each country / region, sorting by year)
        sort_mode="multi",

        # column_selectable column selection mode: 'single', 'multi', or False; Default False
        # When you select a column, its id is included in the selected_ Columns and derived_ viewport_ selected_ In columns
        # Single, the user can select a single column or a group of merged columns through the radio button that appears in the header row
        # multi, the user can select multiple columns or merge column groups through the check box that will appear in the header row
        # column_selectable="single",

        # row_selectable line selection mode: 'single', 'multi', or False; Default False
        # When a row is selected, its index is included in the selected_rows
        # Single, the user can select a single line through the radio button that will appear next to each line
        # multi, the user can select multiple rows by the check box that appears next to each row
        row_selectable="multi",

        # row_deletable: if True, an x will appear next to each row, and the user can delete the row
        row_deletable=True,

        # selected_columns contains the ID of the column selected by the UI element that appears when
        # selected_columns=[],

        # selected_rows contains the index of the selected row in the UI element that appears when passing through
        selected_rows=[],

        # page_action paging mode: 'custom', 'native' or 'none'; default ‘native’
        # ’native ': all data is passed to the table in advance, and the paging logic is processed by the table
        # 'custom': data is transferred to the table page by page at a time, and paging logic is processed through callback
        # 'none': disable paging and render all data at once
        page_action="native",

        # Current page
        page_current= 0,

        # Lines per page, 250 by default
        page_size= 5,
    ),
    html.Div(id='datatable-row-ids-container')
])


@app.callback(
    Output('datatable-row-ids-container', "children"),
    # derived_virtual_data (dictionary list): this attribute indicates the visible status of all pages after data application front-end sorting and filtering
    Input('datatable-row-ids', "derived_virtual_row_ids"),
    # derived_virtual_selected_rows: from selected_ The angle of rows represents the index (derived_virtual_indexes the order in which the original rows appear after filtering and sorting).
    Input('datatable-row-ids', "selected_row_ids"),
    Input('datatable-row-ids', "active_cell"))
def update_graphs(row_ids, selected_row_ids, active_cell):
    """
    When the table is rendered for the first time, `derived_virtual_data` and `derived_virtual_selected_rows` yes `None`. This is due to an
    This is due to Dash A characteristic (Dash The callback function is called when the component is rendered for the first time, and the unapplied property is always None).
    Therefore, if'rows'by'None',The component has just been rendered, and its value will be the same as that of the component dataframe Same.
    When initializing a component, you can also'derived_virtual_data=df.to_rows('dict')`Set to'None',Not here'None'. 
    """
    # Selected id collection
    selected_id_set = set(selected_row_ids or [])

    if row_ids is None:
        dff = df
        # pandas Series is like a list here
        row_ids = df['id']
    else:
        dff = df.loc[row_ids]

    active_row_id = active_cell['row_id'] if active_cell else None

    # Selected and unselected rows are displayed in different colors
    colors = ['#FF69B4' if id == active_row_id
                else '#7FDBFF' if id in selected_id_set
                else '#0074D9'
              for id in row_ids]

    return [
        dcc.Graph(
            id=column + '--row-ids',
            figure={
                "data": [
                    {
                        "x": dff["country"],
                        "y": dff[column],
                        "type": "bar",
                        "marker": {"color": colors},
                    }
                ],
                "layout": {
                    "xaxis": {"automargin": True, 'tickangle': 45},
                    "yaxis": {
                        "automargin": True,
                        "title": {"text": column}
                    },
                    "height": 150,
                    # The outer margin is 10 on the left and right of the top
                    "margin": {"t": 10, "l": 10, "r": 10},
                },
            },
        )
        # if column in dff checks whether the column exists, because the user may delete the column. If 'column.deletable=False', there is no need to check
        for column in ["pop", "lifeExp", "gdpPercap"] if column in dff
    ]


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

3.3 page display

Tags: Python

Posted on Tue, 16 Nov 2021 22:35:21 -0500 by robche