简体   繁体   English

Plotly-Dash:如何过滤具有多个 dataframe 列的仪表板?

[英]Plotly-Dash: How to filter dashboard with multiple dataframe columns?

I have a Python dashboard built using dash , that I want to filter on either the Investor or the Fund column.我有一个使用dash构建的 Python 仪表板,我想在InvestorFund列上进行过滤。

  Investor    Fund Period Date Symbol  Shares  Value
0     Rick  Fund 3  2019-06-30   AVLR       3      9
1     Faye  Fund 2  2015-03-31    MEG      11     80
2     Rick  Fund 3  2018-12-31    BAC      10    200
3      Dre  Fund 4  2020-06-30   PLOW       2     10
4     Faye  Fund 2  2015-03-31   DNOW      10    100
5     Mike  Fund 1  2015-03-31    JNJ       1     10
6     Mike  Fund 1  2018-12-31    QSR       4     20
7     Mike  Fund 1  2018-12-31  LBTYA       3     12

In other words, the user should be able to input one or more investors, and/or one or more Funds in the same filter field, and the dashboard will update accordingly.换言之,用户应该能够在同一筛选字段中输入一个或多个投资者,和/或一个或多个基金,并且仪表板将相应更新。 So I think I need to change:所以我认为我需要改变:

options=[{'label': i, 'value': i} for i in df['Investor'].unique()]

to something like groupby but am not positive?groupby这样的东西,但不是积极的? Here is my code:这是我的代码:

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

data = {'Investor': {0: 'Rick', 1: 'Faye', 2: 'Rick', 3: 'Dre', 4: 'Faye', 5: 'Mike', 6: 'Mike', 7: 'Mike'},
        'Fund': {0: 'Fund 3', 1: 'Fund 2', 2: 'Fund 3', 3: 'Fund 4', 4: 'Fund 2', 5: 'Fund 1', 6: 'Fund 1', 7: 'Fund 1'},
        'Period Date': {0: '2019-06-30', 1: '2015-03-31', 2: '2018-12-31', 3: '2020-06-30', 4: '2015-03-31', 5: '2015-03-31', 6: '2018-12-31', 7: '2018-12-31'},
        'Symbol': {0: 'AVLR', 1: 'MEG', 2: 'BAC', 3: 'PLOW', 4: 'DNOW', 5: 'JNJ', 6: 'QSR', 7: 'LBTYA'},
        'Shares': {0: 3, 1: 11, 2: 10, 3: 2, 4: 10, 5: 1, 6: 4, 7: 3},
        'Value': {0: 9, 1: 80, 2: 200, 3: 10, 4: 100, 5: 10, 6: 20, 7: 12}}
df = pd.DataFrame.from_dict(data)

def generate_table(dataframe, max_rows=100):
    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +

        # Body
        [html.Tr([
            html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
        ]) for i in range(min(len(dataframe), max_rows))]
    )

app = dash.Dash()
app.layout = html.Div(
    children=[html.H4(children='Investor Portfolio'),
    dcc.Dropdown(
        id='dropdown',
        options=[{'label': i, 'value': i} for i in df['Investor'].unique()],
        multi=True, placeholder='Filter by Investor or Fund...'),
    html.Div(id='table-container')
])

@app.callback(dash.dependencies.Output('table-container', 'children'),
    [dash.dependencies.Input('dropdown', 'value')])

def display_table(dropdown_value):
    if dropdown_value is None:
        return generate_table(df)
    dff = df[df.Investor.str.contains('|'.join(dropdown_value))]
    dff = dff[['Investor', 'Period Date', 'Symbol','Shares', 'Value']]
    return generate_table(dff)

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

I am admittedly pretty new to Dash, but from what I can tell, you can achieve what you want by extending your options list, and then using an or condition in the dff that you are displaying in the Dash App to include the Fund column.诚然,我对 Dash 很陌生,但据我所知,您可以通过扩展选项列表,然后在 Dash 应用程序中显示的dff中使用or条件来包含Fund列来实现您想要的。

This is a bit brute force, and a nicer solution would be for Dash to know which columns your selected options are coming from.这有点蛮力,一个更好的解决方案是让 Dash 知道您选择的选项来自哪些列。 However, this would only be an issue if entries from different columns contained the same string (and here the unique values for Investor and Fund aren't ever the same).但是,只有当来自不同列的条目包含相同的字符串时,这才会成为问题(并且这里InvestorFund的唯一值永远不会相同)。

import dash
import dash_core_components as dcc
import dash_html_components as html
import pandas as pd

data = {'Investor': {0: 'Rick', 1: 'Faye', 2: 'Rick', 3: 'Dre', 4: 'Faye', 5: 'Mike', 6: 'Mike', 7: 'Mike'},
        'Fund': {0: 'Fund 3', 1: 'Fund 2', 2: 'Fund 3', 3: 'Fund 4', 4: 'Fund 2', 5: 'Fund 1', 6: 'Fund 1', 7: 'Fund 1'},
        'Period Date': {0: '2019-06-30', 1: '2015-03-31', 2: '2018-12-31', 3: '2020-06-30', 4: '2015-03-31', 5: '2015-03-31', 6: '2018-12-31', 7: '2018-12-31'},
        'Symbol': {0: 'AVLR', 1: 'MEG', 2: 'BAC', 3: 'PLOW', 4: 'DNOW', 5: 'JNJ', 6: 'QSR', 7: 'LBTYA'},
        'Shares': {0: 3, 1: 11, 2: 10, 3: 2, 4: 10, 5: 1, 6: 4, 7: 3},
        'Value': {0: 9, 1: 80, 2: 200, 3: 10, 4: 100, 5: 10, 6: 20, 7: 12}}
df = pd.DataFrame.from_dict(data)

def generate_table(dataframe, max_rows=100):
    return html.Table(
        # Header
        [html.Tr([html.Th(col) for col in dataframe.columns])] +

        # Body
        [html.Tr([
            html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
        ]) for i in range(min(len(dataframe), max_rows))]
    )

app = dash.Dash()
app.layout = html.Div(
    children=[html.H4(children='Investor Portfolio'),
    dcc.Dropdown(
        id='dropdown',
        ## extend the options to consider unique Fund values as well
        options=[{'label': i, 'value': i} for i in df['Investor'].unique()] + [{'label': i, 'value': i} for i in df['Fund'].unique()],
        multi=True, placeholder='Filter by Investor or Fund...'),
    html.Div(id='table-container')
])

@app.callback(dash.dependencies.Output('table-container', 'children'),
    [dash.dependencies.Input('dropdown', 'value')])

def display_table(dropdown_value):
    if dropdown_value is None:
        return generate_table(df)

    ## add an 'or' condition for the other column you want to use to slice the df 
    ## and update the columns that are displayed
    dff = df[df.Investor.str.contains('|'.join(dropdown_value)) | df.Fund.str.contains('|'.join(dropdown_value))]
    dff = dff[['Investor', 'Fund', 'Period Date', 'Symbol','Shares', 'Value']]
    return generate_table(dff)

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

在此处输入图像描述

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM