我正在尝试使用绘图仪表板中的多个下拉栏来过滤数据。总共有 5 个下拉选项。我希望前 3 个独立运行,而后两个应该以双向方式链接到前 3 个。
具体来说,我要实现的功能是:
-
所有值的默认值应该始终是初始起点
-
前 3 个选项(年、季节和月)应独立运行。例如,可以将这 3 项的任意组合添加到输出中。 如果选择一项,则应使用这些值更新输出。但是,如果从另一个下拉列表中选择一个项目,则这些值应添加到输出 中。下面 i) 中的示例。
-
选项 4-5(temp 和 prec)应双向链接到前三个下拉选项(年份、季节和月份)。这应该是可逆的或双向的。 如果选择了前 3 个下拉选项之一,则应使用这些值更新表输出,并且应减少下拉列表以仅允许用户从这些值中进行选择| ||。下面的示例在 ii) 中。 提供具体示例;
i) 从第一个下拉选项中的年份中选择 2012 年。表输出显示相关值。用户应该能够在“年份”下拉列表中选择任何后续值(功能)。
但是,如果用户还想从第二个下拉选项中查看 Spr 值,则应将该数据添加到输出中 . ii) 对于应
链接到前 3 的 4-5 个下拉选项,如果在 temp 中选择 Hot 和 Mild,在 prec 中选择 Wet,则下拉列表将在前三个中列出选项应减少为:年份 = 2013, 2015;季节 = 春季、秋季;月份 = 四月、六月、十月、十二月 编辑 2:
import pandas as pd
from dash import Dash, dcc, html, Input, Output, dash_table
import dash_bootstrap_components as dbc
from itertools import cycle
import random
Year = cycle(['2012','2013','2014','2015'])
Season = cycle(['Win','Spr','Sum','Fall'])
Month = cycle(['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'])
temp_group = cycle(['Hot','Cold','Mild'])
prec_group = cycle(['Dry','Wet'])
df = pd.DataFrame(index = range(20))
df['option1'] = [next(Year) for count in range(df.shape[0])]
df['option2'] = [next(Season) for count in range(df.shape[0])]
df['option3'] = [next(Month) for count in range(df.shape[0])]
df['option4'] = [next(temp_group) for count in range(df.shape[0])]
df['option5'] = [next(prec_group) for count in range(df.shape[0])]
option1_list = sorted(df['option1'].unique().tolist())
option2_list = df['option2'].unique().tolist()
option3_list = df['option3'].unique().tolist()
option4_list = sorted(df['option4'].unique().tolist())
option5_list = sorted(df['option5'].unique().tolist())
app = Dash(__name__)
app.layout = html.Div([
dbc.Card(
dbc.CardBody([
dbc.Row([
dbc.Col([
html.P("Option 1"),
html.Div([
dcc.Dropdown(id='option1_dropdown',
options=option1_list,
value=[],
placeholder='All',
multi=True,
clearable=True),
],
style={'width': '100%', 'display': 'inline-block'})
]),
dbc.Col([
html.P("Option 2"),
html.Div([
dcc.Dropdown(id='option2_dropdown',
options=option2_list,
value=[],
placeholder='All',
multi=True,
clearable=True),
],
style={'width': '100%', 'display': 'inline-block'})
]),
dbc.Col([
html.P("Option 3"),
html.Div([
dcc.Dropdown(id='option3_dropdown',
options=option3_list,
value=[],
placeholder='All',
multi=True,
clearable=True),
],
style={'width': '100%', 'display': 'inline-block'})
]),
dbc.Col([
html.P("Option 4"),
html.Div([
dcc.Dropdown(id='option4_dropdown',
options=option4_list,
value=[],
placeholder='All',
multi=True,
clearable=True),
],
style={'width': '100%', 'display': 'inline-block'})
]),
dbc.Col([
html.P("Option 5"),
html.Div([
dcc.Dropdown(id='option5_dropdown',
options=option5_list,
value=[],
placeholder='All',
multi=True,
clearable=True),
],
style={'width': '100%', 'display': 'inline-block'})
]),
], align='center'),
]), color='dark'
),
dbc.Card(
dbc.CardBody([
dbc.Row([
html.Div([
html.Div(id='dd-output-container')
])
], align='center'),
]), color='dark'
),
dbc.Card(
dbc.CardBody([
dbc.Row([
html.Div([
dash_table.DataTable(
id='table_container',
data=df.to_dict('records')
)
])
], align='center'),
]), color='dark'
)
])
@app.callback(
Output('table_container', 'data'),
[Input('option1_dropdown', 'value'),
Input('option2_dropdown', 'value'),
Input('option3_dropdown', 'value'),
Input('option4_dropdown', 'value'),
Input('option5_dropdown', 'value')
])
def set_dropdown_options(value1, value2, value3, value4, value5):
if not value1 or value1 == 'All':
value1 = option1_list
if not value2 or value2 == 'All':
value2 = option2_list
if not value3 or value3 == 'All':
value3 = option3_list
if not value4 or value4 == 'All':
value4 = option4_list
if not value5 or value5 == 'All':
value5 = option5_list
ddf = df.query('option1 == @value1 and '
'option2 == @value2 and '
'option3 == @value3 and '
'option4 == @value4 and '
'option5 == @value5',
engine='python')
return ddf.to_dict('records')
# ====== Using this as a way to view the selections
@app.callback(
Output('dd-output-container', 'children'),
[Input('option1_dropdown', 'value'),
Input('option2_dropdown', 'value'),
Input('option3_dropdown', 'value'),
Input('option4_dropdown', 'value'),
Input('option5_dropdown', 'value')
])
def selection(value1, value2, value3, value4, value5):
# If value lists are empty or equal to the default of 'All', use the initial df values
if not value1 or value1 == 'All':
value1 = option1_list
if not value2 or value2 == 'All':
value2 = option2_list
if not value3 or value3 == 'All':
value3 = option3_list
if not value4 or value4 == 'All':
value4 = option4_list
if not value5 or value5 == 'All':
value5 = option5_list
ddf = df.query('option1 == @value1 and '
'option2 == @value2 and '
'option3 == @value3 and '
'option4 == @value4 and '
'option5 == @value5',
engine='python')
return
if __name__ == '__main__':
app.run_server(debug=True, dev_tools_hot_reload = False)
有没有办法包含原始列名称而不转换为使用整数后缀?
Is there a way to include the original column names without converting to using an integer suffix?
Year = cycle(["2012", "2013", "2014", "2015"])
Season = cycle(["Win", "Spr", "Sum", "Fall"])
Month = cycle(
["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
)
temp_group = cycle(["Hot", "Cold", "Mild"])
prec_group = cycle(["Dry", "Wet"])
df = pd.DataFrame(index=range(20))
df["Year"] = [next(Year) for count in range(df.shape[0])]
df["Season"] = [next(Season) for count in range(df.shape[0])]
df["Month"] = [next(Month) for count in range(df.shape[0])]
df["Temp"] = [next(temp_group) for count in range(df.shape[0])]
df["Prec"] = [next(prec_group) for count in range(df.shape[0])]
Year_list = sorted(df["Year"].unique().tolist())
Season_list = df["Season"].unique().tolist()
Month_list = df["Month"].unique().tolist()
Temp_list = sorted(df["Temp"].unique().tolist())
Prec_list = sorted(df["Prec"].unique().tolist())
df = df.rename(columns = {'Year':'option1',
'Season':'option2',
'Month':'option3',
'Temp':'option4',
'Prec':'option5'})
app = Dash(__name__)
app.layout = html.Div(
[
dbc.Card(
dbc.CardBody(
[
dbc.Row(
[
dbc.Col(
[
html.P("Year"),
html.Div(
[
dcc.Dropdown(
id="Year_dropdown",
options=Year_list,
value=[],
placeholder="All",
multi=True,
clearable=True,
),
],
style={
"width": "100%",
"display": "inline-block",
},
),
]
),
dbc.Col(
[
html.P("Season"),
html.Div(
[
dcc.Dropdown(
id="Season_dropdown",
options=Season_list,
value=[],
placeholder="All",
multi=True,
clearable=True,
),
],
style={
"width": "100%",
"display": "inline-block",
},
),
]
),
dbc.Col(
[
html.P("Month"),
html.Div(
[
dcc.Dropdown(
id="Month_dropdown",
options=Month_list,
value=[],
placeholder="All",
multi=True,
clearable=True,
),
],
style={
"width": "100%",
"display": "inline-block",
},
),
]
),
dbc.Col(
[
html.P("Temp"),
html.Div(
[
dcc.Dropdown(
id="Temp_dropdown",
options=Temp_list,
value=[],
placeholder="All",
multi=True,
clearable=True,
),
],
style={
"width": "100%",
"display": "inline-block",
},
),
]
),
dbc.Col(
[
html.P("Prec"),
html.Div(
[
dcc.Dropdown(
id="Prec_dropdown",
options=Prec_list,
value=[],
placeholder="All",
multi=True,
clearable=True,
),
],
style={
"width": "100%",
"display": "inline-block",
},
),
]
),
],
align="center",
),
]
),
color="dark",
),
dbc.Card(
dbc.CardBody(
[
dbc.Row(
[html.Div([html.Div(id="dd-output-container")])], align="center"
),
]
),
color="dark",
),
dbc.Card(
dbc.CardBody(
[
dbc.Row(
[
html.Div(
[
dash_table.DataTable(
id="table_container", data=df.to_dict("records")
)
]
)
],
align="center",
),
]
),
color="dark",
),
]
)
df = df.rename(columns = {'Year':'option1',
'Season':'option2',
'Month':'option3',
'Temp':'option4',
'Prec':'option5'})
def construct_query(filter_values):
additive_clauses = list()
subtractive_clauses = list()
for i, filter_value in enumerate(filter_values):
if filter_value and filter_value != "All":
clause = f"option{i + 1} == @value{i + 1}"
if i <= 3:
additive_clauses.append(clause)
else:
subtractive_clauses.append(clause)
if len(additive_clauses) > 0 or len(subtractive_clauses) > 0:
additive_section = " or ".join(additive_clauses)
subtractive_clauses = " and ".join(subtractive_clauses)
if additive_section and subtractive_clauses:
query = f"({additive_section}) and {subtractive_clauses}"
else:
query = additive_section or subtractive_clauses
return query
@app.callback(
[
Output("Year_dropdown", "options"),
Output("Season_dropdown", "options"),
Output("Month_dropdown", "options"),
],
[
Input("Temp_dropdown", "value"),
Input("Prec_dropdown", "value"),
],
)
def update_additive_options(value4, value5):
query = None
option4_query = "option4 == @value4"
option5_query = "option5 == @value5"
if value4 and value4 != "All" and value5 and value5 != "All":
query = f"{option4_query} and {option5_query}"
elif value4 and value4 != "All":
query = option4_query
elif value5 and value5 != "All":
query = option5_query
if query:
df_filtered = df.query(
query,
engine="python",
)
else:
df_filtered = df
return (
sorted(df_filtered["option1"].unique().tolist()),
df_filtered["option2"].unique().tolist(),
df_filtered["option3"].unique().tolist(),
)
@app.callback(
[Output("Temp_dropdown", "options"), Output("Prec_dropdown", "options")],
[
Input("Year_dropdown", "options"),
Input("Season_dropdown", "options"),
Input("Month_dropdown", "options"),
],
)
def update_subtractive_options(value1, value2, value3):
query = None
additive_clauses = []
for i, filter_value in enumerate([value1, value2, value3]):
if filter_value and filter_value != "All":
clause = f"option{i + 1} == @value{i + 1}"
additive_clauses.append(clause)
if len(additive_clauses) > 0:
query = " or ".join(additive_clauses)
if query:
df_filtered = df.query(
query,
engine="python",
)
else:
df_filtered = df
return (
sorted(df_filtered["option4"].unique().tolist()),
sorted(df_filtered["option5"].unique().tolist()),
)
@app.callback(
Output("table_container", "data"),
[
Input("Year_dropdown", "value"),
Input("Season_dropdown", "value"),
Input("Month_dropdown", "value"),
Input("Temp_dropdown", "value"),
Input("Prec_dropdown", "value"),
],
)
def update_table(value1, value2, value3, value4, value5):
query = construct_query(filter_values=[value1, value2, value3, value4, value5])
if query:
df_filtered = df.query(
query,
engine="python",
)
else:
df_filtered = df
return df_filtered.to_dict("records")
# ====== Using this as a way to view the selections
@app.callback(
Output("dd-output-container", "children"),
[
Input("Year_dropdown", "value"),
Input("Season_dropdown", "value"),
Input("Month_dropdown", "value"),
Input("Temp_dropdown", "value"),
Input("Prec_dropdown", "value"),
],
)
def selection(value1, value2, value3, value4, value5):
# If value lists are empty or equal to the default of 'All', use the initial df values
if not value1 or value1 == "All":
value1 = Year_list
if not value2 or value2 == "All":
value2 = Season_list
if not value3 or value3 == "All":
value3 = Month_list
if not value4 or value4 == "All":
value4 = Temp_list
if not value5 or value5 == "All":
value5 = Prec_list
ddf = df.query(
"option1 == @value1 and "
"option2 == @value2 and "
"option3 == @value3 and "
"option4 == @value4 and "
"option5 == @value5",
engine="python",
)
return
if __name__ == "__main__":
app.run_server(debug=True, dev_tools_hot_reload=False)
import pandas as pd
from dash import Dash, dcc, html, Input, Output, dash_table
import dash_bootstrap_components as dbc
from itertools import cycle
Year = cycle(["2012", "2013", "2014", "2015"])
Season = cycle(["Win", "Spr", "Sum", "Fall"])
Month = cycle(
["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
)
temp_group = cycle(["Hot", "Cold", "Mild"])
prec_group = cycle(["Dry", "Wet"])
df = pd.DataFrame(index=range(20))
df["Year"] = [next(Year) for count in range(df.shape[0])]
df["Season"] = [next(Season) for count in range(df.shape[0])]
df["Month"] = [next(Month) for count in range(df.shape[0])]
df["Temp"] = [next(temp_group) for count in range(df.shape[0])]
df["Prec"] = [next(prec_group) for count in range(df.shape[0])]
Year_list = sorted(df["Year"].unique().tolist())
Season_list = df["Season"].unique().tolist()
Month_list = df["Month"].unique().tolist()
Temp_list = sorted(df["Temp"].unique().tolist())
Prec_list = sorted(df["Prec"].unique().tolist())
app = Dash(__name__)
app.layout = html.Div(
[
dbc.Card(
dbc.CardBody(
[
dbc.Row(
[
dbc.Col(
[
html.P("Year"),
html.Div(
[
dcc.Dropdown(
id="Year_dropdown",
options=Year_list,
value=[],
placeholder="All",
multi=True,
clearable=True,
),
],
style={
"width": "100%",
"display": "inline-block",
},
),
]
),
dbc.Col(
[
html.P("Season"),
html.Div(
[
dcc.Dropdown(
id="Season_dropdown",
options=Season_list,
value=[],
placeholder="All",
multi=True,
clearable=True,
),
],
style={
"width": "100%",
"display": "inline-block",
},
),
]
),
dbc.Col(
[
html.P("Month"),
html.Div(
[
dcc.Dropdown(
id="Month_dropdown",
options=Month_list,
value=[],
placeholder="All",
multi=True,
clearable=True,
),
],
style={
"width": "100%",
"display": "inline-block",
},
),
]
),
dbc.Col(
[
html.P("Temp"),
html.Div(
[
dcc.Dropdown(
id="Temp_dropdown",
options=Temp_list,
value=[],
placeholder="All",
multi=True,
clearable=True,
),
],
style={
"width": "100%",
"display": "inline-block",
},
),
]
),
dbc.Col(
[
html.P("Prec"),
html.Div(
[
dcc.Dropdown(
id="Prec_dropdown",
options=Prec_list,
value=[],
placeholder="All",
multi=True,
clearable=True,
),
],
style={
"width": "100%",
"display": "inline-block",
},
),
]
),
],
align="center",
),
]
),
color="dark",
),
dbc.Card(
dbc.CardBody(
[
dbc.Row(
[html.Div([html.Div(id="dd-output-container")])],
align="center",
),
]
),
color="dark",
),
dbc.Card(
dbc.CardBody(
[
dbc.Row(
[
html.Div(
[
dash_table.DataTable(
id="table_container", data=df.to_dict("records")
)
]
)
],
align="center",
),
]
),
color="dark",
),
]
)
# Function to construct the query for filtering
def construct_query(filter_values):
conditions = []
for col_name, filter_value in zip(
["Year", "Season", "Month", "Temp", "Prec"], filter_values
):
if filter_value and filter_value != "All":
if isinstance(filter_value, list):
condition = f"{col_name} in @filter_value"
else:
condition = f"{col_name} == @filter_value"
conditions.append(condition)
return " and ".join(conditions) if conditions else None
# Callback to update the options of Year, Season, and Month dropdowns based on Temp and Prec selections
@app.callback(
[
Output("Year_dropdown", "options"),
Output("Season_dropdown", "options"),
Output("Month_dropdown", "options"),
],
[Input("Temp_dropdown", "value"), Input("Prec_dropdown", "value")],
)
def update_year_season_month_options(temp_value, prec_value):
# Apply filtering based on selected Temp and Prec
query = construct_query(filter_values=[None, None, None, temp_value, prec_value])
filtered_df = df.query(query, engine='python') if query else df
# Update options for Year, Season, and Month based on filtered data
return (
sorted(filtered_df["Year"].unique().tolist()),
filtered_df["Season"].unique().tolist(),
filtered_df["Month"].unique().tolist(),
)
# Callback to update the options of Temp and Prec dropdowns based on Year, Season, and Month selections
@app.callback(
[Output("Temp_dropdown", "options"), Output("Prec_dropdown", "options")],
[
Input("Year_dropdown", "value"),
Input("Season_dropdown", "value"),
Input("Month_dropdown", "value"),
],
)
def update_temp_prec_options(year_value, season_value, month_value):
# Apply filtering based on selected Year, Season, and Month
query = construct_query(filter_values=[year_value, season_value, month_value, None, None])
filtered_df = df.query(query, engine='python') if query else df
# Update options for Temp and Prec based on filtered data
return (
sorted(filtered_df["Temp"].unique().tolist()),
sorted(filtered_df["Prec"].unique().tolist()),
)
# Callback to update the table based on selections from all dropdowns
@app.callback(
Output("table_container", "data"),
[
Input("Year_dropdown", "value"),
Input("Season_dropdown", "value"),
Input("Month_dropdown", "value"),
Input("Temp_dropdown", "value"),
Input("Prec_dropdown", "value"),
],
)
def update_table(year_value, season_value, month_value, temp_value, prec_value):
# Construct the query based on all filter selections
query = construct_query(
filter_values=[year_value, season_value, month_value, temp_value, prec_value]
)
# Apply filtering and update the table data
filtered_df = df.query(query, engine='python') if query else df
return filtered_df.to_dict("records")
# Callback for debugging (display selected values)
@app.callback(
Output("dd-output-container", "children"),
[
Input("Year_dropdown", "value"),
Input("Season_dropdown", "value"),
Input("Month_dropdown", "value"),
Input("Temp_dropdown", "value"),
Input("Prec_dropdown", "value"),
],
)
def selection(value1, value2, value3, value4, value5):
return html.Div(
[
html.P(f"Year: {value1}"),
html.P(f"Season: {value2}"),
html.P(f"Month: {value3}"),
html.P(f"Temp: {value4}"),
html.P(f"Prec: {value5}"),
]
)
if __name__ == "__main__":
app.run_server(debug=True, dev_tools_hot_reload=False)
Explanation:
-
Data Loading and Initialization: The code loads sample data into a pandas DataFrame (
df
) with columns for "Year", "Season", "Month", "Temp", and "Prec". It also creates lists of unique values for each column for initial dropdown options. -
Layout: The Dash app layout consists of five dropdown menus for the filters and a
dash_table.DataTable
to display the filtered data. -
construct_query
Function: This function dynamically builds a query string based on the selected values in the dropdown menus. It iterates through the filter values and corresponding column names, constructing conditions for the query. -
update_year_season_month_options
Callback: This callback is triggered when the "Temp" or "Prec" dropdown value changes. It filters the DataFrame based on the selected "Temp" and "Prec" values and updates the options of "Year," "Season," and "Month" dropdowns with the values that exist within the filtered DataFrame. -
update_temp_prec_options
Callback: Similar to the previous callback, this one is triggered when "Year," "Season," or "Month" dropdown values change. It filters the DataFrame and updates the "Temp" and "Prec" dropdown options accordingly. -
update_table
Callback: This callback is triggered when any of the dropdown values change. It constructs a query based on all filter selections, filters the DataFrame using the query, and updates the table data with the filtered results. -
selection
Callback (Debugging): This callback is for debugging purposes. It displays the selected values from all dropdown menus.
How it achieves the desired behavior:
-
Independent Filtering (First 3 Dropdowns): The first three dropdowns ("Year," "Season," "Month") filter the data independently because their corresponding callback functions only update their respective dropdown options based on selections in the "Temp" and "Prec" dropdowns, not each other.
-
Dependent Filtering (Last 2 Dropdowns): The last two dropdowns ("Temp," "Prec") are dependent on the selections in the first three dropdowns. The
update_temp_prec_options
callback ensures that their options are updated whenever the values in "Year," "Season," or "Month" dropdowns change. -
Bidirectional Linking: The bidirectional linking is achieved by having two separate callbacks: one to update "Year," "Season," and "Month" options based on "Temp" and "Prec" selections, and another to update "Temp" and "Prec" options based on "Year," "Season," and "Month" selections.
This setup ensures that the dropdowns are linked and update each other's options accordingly, providing a dynamic filtering experience in the Dash app.
标签:python,pandas,callback,plotly,chained From: 78650025