我有一个下拉菜单,可以让我过滤分类图。单独的回调允许用户将该图从条形图更改为饼图。这部分按预期工作。
我有单独的滑块组件,可以调整条形图或饼图的设置。问题是滑块固定到位。 是否可以根据单选项目中的选择添加/删除相关滑块?
如果选择条形图(见下文),则只有两个条形滑块应该可见。另外两个应该被丢弃或移除。相反,如果选择了馅饼,就会发生相反的情况。条形滑块被移除以代替饼图滑块。
过滤 div 上的布局应保持不变。
import dash
from dash import dcc
from dash import html
from dash.dependencies import Input, Output
import dash_bootstrap_components as dbc
import plotly.express as px
import plotly.graph_objs as go
import pandas as pd
df = pd.DataFrame({
'Fruit': ['Apple','Banana','Orange','Kiwi','Lemon'],
'Value': [1,2,4,8,6],
})
external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP]
app = dash.Dash(__name__, external_stylesheets = external_stylesheets)
filter_box = html.Div(children=[
html.Div(children=[
html.Label('Fruit', style = {}),
dcc.Dropdown(
id = 'value_type',
options = [
{'label': x, 'value': x} for x in df['Fruit'].unique()
],
value = df['Fruit'].unique(),
multi = True,
clearable = True
),
html.Label('Cat Chart', style = {'display': 'inline','paddingTop': '0rem', "justifyContent": "center"}),
dcc.RadioItems(['Bar','Pie'],'Bar',
id = 'catmap',
),
html.Label('Bar Transp', style = {'display': 'inline-block', 'paddingTop': '0.1rem',}),
dcc.Slider(0, 1, 0.2,
value = 0.6,
id = 'bar_transp'),
html.Label('Bar Width', style = {'display': 'inline-block'}),
dcc.Slider(200, 1000, 200,
value = 600,
id = 'bar_width'),
html.Label('Pie Transp', style = {'display': 'inline-block', 'paddingTop': '0.1rem',}),
dcc.Slider(0, 1, 0.2,
value = 0.6,
id = 'pie_transp'),
html.Label('Pie Hole', style = {'display': 'inline-block'}),
dcc.Slider(0, 1, 0.2,
value = 0.4,
id = 'pie_hole'),
], className = "vstack",
)
])
app.layout = dbc.Container([
dbc.Row([
dbc.Col([
dbc.Row([
dbc.Col(html.Div(filter_box),
),
]),
]),
dbc.Col([
dbc.Row([
dcc.Graph(id = 'type-chart'),
]),
])
])
], fluid = True)
@app.callback(
Output('type-chart', 'figure'),
[Input('value_type', 'value'),
Input('catmap', 'value'),
Input('bar_transp', 'value'),
Input('bar_width', 'value'),
Input('pie_transp', 'value'),
Input('pie_hole', 'value'),
])
def chart(value_type, catmap, bar_transp, bar_width, pie_transp, pie_hole):
dff = df[df['Fruit'].isin(value_type)]
if catmap == 'Bar':
df_count = dff.groupby(['Fruit'])['Value'].count().reset_index(name = 'counts')
if df_count.empty == True:
type_fig = go.Figure()
else:
df_count = df_count
type_fig = px.bar(x = df_count['Fruit'],
y = df_count['counts'],
color = df_count['Fruit'],
opacity = bar_transp,
width = bar_width
)
elif catmap == 'Pie':
df_count = dff.groupby(['Fruit'])['Value'].count().reset_index(name = 'counts')
if df_count.empty == True:
type_fig = go.Figure()
else:
df_count = df_count
type_fig = px.pie(df_count,
values = df_count['counts'],
opacity = pie_transp,
hole = pie_hole
)
return type_fig
if __name__ == '__main__':
app.run_server(debug = True)
在这种情况下不需要模式匹配回调,但如果要动态创建过滤器则可能需要。相反,为了根据所选图形类型添加/删除相关滑块,您可以将它们包装在组件中(如
children
)并使用回调来更新该组件的 children
属性。
但是,我建议您只显示/隐藏滑块,而不是添加/删除它们,以便在图形类型更新中保留它们的状态:
为每种类型使用一个包装组件(此处为“filter_bar”和“filter_pie”):
filter_box = html.Div(children=[
html.Div(children=[
html.Label('Fruit', style = {}),
dcc.Dropdown(
id = 'value_type',
options = [
{'label': x, 'value': x} for x in df['Fruit'].unique()
],
value = df['Fruit'].unique(),
multi = True,
clearable = True
),
html.Label('Cat Chart', style = {'display': 'inline','paddingTop': '0rem', "justifyContent": "center"}),
dcc.RadioItems(['Bar','Pie'],'Bar',
id = 'catmap',
),
html.Div(id='filter_bar', children=[
html.Label('Bar Transp', style = {'display': 'inline-block', 'paddingTop': '0.1rem',}),
dcc.Slider(0, 1, 0.2,
value = 0.6,
id = 'bar_transp'),
html.Label('Bar Width', style = {'display': 'inline-block'}),
dcc.Slider(200, 1000, 200,
value = 600,
id = 'bar_width'),
]),
html.Div(id='filter_pie', children=[
html.Label('Pie Transp', style = {'display': 'inline-block', 'paddingTop': '0.1rem',}),
dcc.Slider(0, 1, 0.2,
value = 0.6,
id = 'pie_transp'),
html.Label('Pie Hole', style = {'display': 'inline-block'}),
dcc.Slider(0, 1, 0.2,
value = 0.4,
id = 'pie_hole'),
])
], className = "vstack",
)
])
并在回调中更新其
style
属性:
@app.callback(
Output('filter_bar', 'style'),
Output('filter_pie', 'style'),
Input('catmap', 'value')
)
def display_sliders(catmap):
if catmap == 'Bar':
return {}, {'display': 'none'}
if catmap == 'Pie':
return {'display': 'none'}, {}
return {'display': 'none'}, {'display': 'none'}