如何在Dash中仅选择Hexbin时添加专属图表参数?
问题
我开发了一个Dash回调函数,可切换展示Scatter、Heatmap、Hexbin等不同空间地图。当选中Hexbin选项时,希望添加nx_hexagon、min count等专属参数来修改图表,能否仅在选中Hexbin时启用这些参数?
解决方案
可以通过Dash的回调控制组件显隐来实现,核心是监听地图类型选择,动态切换Hexbin专属参数组件的可见性,同时在回调中接收参数并应用到图表生成:
- 修正组件ID冲突:原代码中多个Slider共用
my-sliderID,需给每个Slider分配唯一ID,例如opacity-slider、nx-hexagon-slider、min-count-slider。 - 封装Hexbin专属控件:将nx_hexagon和min count的Slider包裹在一个单独的
html.Div中,设置初始隐藏(style={'display': 'none'}),并给容器分配IDhexbin-controls。 - 添加显隐控制回调:监听
maps的输入值,当选中Hexbin时,设置容器样式为display: block,否则保持隐藏。 - 更新图表生成逻辑:在图表回调中新增两个Slider的输入,生成Hexbin图表时将参数传入
ff.create_hexbin_mapbox。
修改后的完整代码
import dash from dash import dcc, html, Input, Output import dash_bootstrap_components as dbc import plotly.express as px import plotly.graph_objs as go import pandas as pd import numpy as np import plotly.figure_factory as ff data = pd.DataFrame({ 'Cat': ['t','y','y','y','f','f','j','k','k','k','s','s','s','s'], 'LAT': [5,6,4,5,4,7,8,9,5,6,18,17,15,16], 'LON': [10,11,9,11,10,8,8,5,8,7,18,16,16,17], }) N = 30 data = pd.concat([data] * N, ignore_index=True) data['Color'] = data['Cat'].map(dict(zip(data['Cat'].unique(), px.colors.qualitative.Plotly[:len(data['Cat'].unique())]))) Type_Category = data['Cat'].unique() Type_cats = dict(zip(Type_Category, data['Color'].unique())) external_stylesheets = [dbc.themes.SPACELAB, dbc.icons.BOOTSTRAP] app = dash.Dash(__name__, external_stylesheets=external_stylesheets) filtering = html.Div([ html.Div([ html.Label('Cats', style={'paddingTop': '2rem', 'display': 'inline-block'}), dcc.Checklist( id='Cats', options=[{'label': cat, 'value': cat} for cat in Type_Category], value=list(Type_Category), ), html.Label('Type', style={'paddingTop': '2rem', 'display': 'inline-block'}), dcc.RadioItems(['Scatter', 'Heatmap', 'Hexbin'], 'Scatter', inline=True, id='maps'), html.Label('Opacity', style={'paddingTop': '2rem', 'display': 'inline-block'}), dcc.Slider(0, 1, 0.1, value=0.5, id='opacity-slider'), # Hexbin专属控件容器,初始隐藏 html.Div(id='hexbin-controls', style={'display': 'none'}, children=[ html.Label('nx_hexagon', style={'paddingTop': '2rem', 'display': 'inline-block'}), dcc.Slider(5, 40, 5, value=20, id='nx-hexagon-slider'), html.Label('min count', style={'paddingTop': '2rem', 'display': 'inline-block'}), dcc.Slider(0, 5, 1, value=0, id='min-count-slider') ]), ]) ]) app.layout = dbc.Container([ dbc.Row([ dbc.Col([filtering], width=2), dbc.Col([dcc.Graph()]), dbc.Col([dcc.Graph(id='chart')]) ]) ], fluid=True) df = data # 控制Hexbin控件显隐的回调 @app.callback( Output('hexbin-controls', 'style'), Input('maps', 'value') ) def toggle_hexbin_controls(map_type): if map_type == 'Hexbin': return {'display': 'block'} return {'display': 'none'} # 图表生成回调 @app.callback( Output('chart', 'figure'), [Input('Cats', 'value'), Input('maps', 'value'), Input('opacity-slider', 'value'), Input('nx-hexagon-slider', 'value'), Input('min-count-slider', 'value')] ) def update_chart(cats, map_type, opacity, nx_hex, min_count): dff = df[df['Cat'].isin(cats)] if map_type == 'Scatter': fig = px.scatter_mapbox( data_frame=dff, lat='LAT', lon='LON', color='Cat', color_discrete_map=Type_cats, zoom=3, mapbox_style='carto-positron', ) fig.update_traces(opacity=opacity) elif map_type == 'Heatmap': [X, Y] = np.meshgrid(dff['LAT'], dff['LON']) Z = np.cos(X / 2) + np.sin(Y / 4) fig = go.Figure(data=go.Densitymapbox( lat=dff['LAT'], lon=dff['LON'], z=Z, )) fig.update_layout(mapbox_style="carto-positron") else: fig = ff.create_hexbin_mapbox( data_frame=dff, lat="LAT", lon="LON", nx_hexagon=nx_hex, min_count=min_count, opacity=opacity ) fig.update_layout(mapbox_style="carto-positron") return fig if __name__ == '__main__': app.run_server(debug=True, port=8051)
预期效果
选中Hexbin时的界面效果:
内容的提问来源于stack exchange,提问作者jonboy
相关产品推荐
相关产品推荐

