如何用Dropdown/RadioItems在单个Dash图表中切换不同密度图类型
当然可以实现,核心思路是通过单个回调函数根据选择的可视化类型动态生成对应图表,挂载到同一个dcc.Graph组件上。以下是具体实现方案:
实现步骤与代码示例
1. 核心逻辑
- 用
RadioItems或Dropdown做可视化类型选择器 - 所有空间坐标筛选组件(如范围滑块、输入框)与选择器共同作为回调输入
- 回调内先执行数据筛选,再根据选择的类型生成对应图表并返回
2. 完整代码
import dash from dash import dcc, html, Input, Output import plotly.express as px import pandas as pd # 替换为你的真实空间数据集 df = pd.DataFrame({ 'lon': [116.3, 116.4, 116.5, 116.3, 116.4, 116.5, 116.3, 116.4, 116.5], 'lat': [39.9, 39.9, 39.9, 40.0, 40.0, 40.0, 40.1, 40.1, 40.1], 'population': [1200, 1500, 900, 2100, 1800, 1300, 800, 1000, 700] }) app = dash.Dash(__name__) app.layout = html.Div([ # 可视化类型选择器(RadioItems 或 Dropdown 二选一即可) dcc.RadioItems( id='viz-type-select', options=[ {'label': '散点图', 'value': 'scatter'}, {'label': '热力图', 'value': 'heatmap'}, {'label': '六边形分箱图', 'value': 'hexbin'} ], value='scatter', inline=True, style={'margin-bottom': '20px'} ), # 空间坐标筛选组件(示例用范围滑块,可替换为你的筛选逻辑) html.Div([ html.Div([ html.Label('经度范围'), dcc.RangeSlider( id='lon-range', min=df['lon'].min(), max=df['lon'].max(), value=[df['lon'].min(), df['lon'].max()], step=0.1 ) ], style={'width': '48%', 'display': 'inline-block'}), html.Div([ html.Label('纬度范围'), dcc.RangeSlider( id='lat-range', min=df['lat'].min(), max=df['lat'].max(), value=[df['lat'].min(), df['lat'].max()], step=0.1 ) ], style={'width': '48%', 'display': 'inline-block', 'margin-left': '4%'}) ], style={'margin-bottom': '20px'}), # 动态展示图表的容器 dcc.Graph(id='spatial-viz-container') ]) @app.callback( Output('spatial-viz-container', 'figure'), Input('viz-type-select', 'value'), Input('lon-range', 'value'), Input('lat-range', 'value') ) def update_spatial_viz(viz_type, lon_range, lat_range): # 第一步:执行空间坐标筛选 filtered_df = df[ (df['lon'] >= lon_range[0]) & (df['lon'] <= lon_range[1]) & (df['lat'] >= lat_range[0]) & (df['lat'] <= lat_range[1]) ] # 第二步:根据选择的类型生成对应图表 if viz_type == 'scatter': fig = px.scatter( filtered_df, x='lon', y='lat', size='population', color='population', title='空间分布散点图' ) elif viz_type == 'heatmap': fig = px.density_heatmap( filtered_df, x='lon', y='lat', z='population', title='人口热力图' ) elif viz_type == 'hexbin': fig = px.density_mapbox( filtered_df, lat='lat', lon='lon', z='population', radius=20, mapbox_style='carto-positron', title='六边形分箱人口分布图' ) else: # 默认返回散点图作为兜底 fig = px.scatter(filtered_df, x='lon', y='lat', size='population') # 统一调整图表布局(可选) fig.update_layout(height=600) return fig if __name__ == '__main__': app.run_server(debug=True)
扩展说明
- 新增可视化类型:只需在
RadioItems的options中添加新选项,然后在回调内新增对应的elif分支,写入该类型的图表生成代码即可(比如等高线图、3D散点图) - 复用筛选逻辑:所有图表共享同一套空间筛选代码,避免重复开发
- 自定义筛选组件:可将示例中的范围滑块替换为输入框、下拉框等,只需调整回调的输入参数和筛选逻辑即可
内容的提问来源于stack exchange,提问作者jonboy
相关产品推荐
相关产品推荐

