Plotly下拉切换选项时Choropleth地图无数据显示求助
解决Plotly Choropleth地图切换Description分类无数据的问题
问题背景
我正在尝试创建一张国际Choropleth地图,鼠标悬停在各国时可查看对应病例数与死亡数,并添加基于Description列的下拉框以切换不同分类。目前仅“All Descriptions”能正常显示数据,切换至其他选项时地图无任何数据。
数据信息
数据列:
Index(['Case#', 'Year', 'Date', 'Country', 'State', 'Description', 'deaths', 'Tesladriver', 'Teslaoccupant', 'Othervehicle', 'CyclistsPedsivolved', 'TSLAcyclpedsinvolved', 'Autopilotclaimed', 'VerifiedTeslaAutopilotDeaths', 'VerifiedTeslaAutopilotDeathsAllDeathsReportedtoNHTSASGO'], dtype='object')
数据示例:
array([[294, 2022, '1/17/2023', 'USA', 'CA', 'Collisions', 1, '1', '-', '-', 0, 1, 0, 0, 0], [293, 2022, '45108', 'Canada', '-', 'Other Causes', 1, '1', '-', '-', 0, 1, 0, 0, 0], [292, 2022, '45108', 'USA', 'WA', 'Other Causes', 1, '-', '1', '-', 0, 1, 0, 0, 0], [291, 2022, '12/22/2022', 'USA', 'GA', 'Other Causes', 1, '1', '-', '-', 0, 1, 0, 0, 0], [290, 2022, '12/19/2022', 'Canada', '-', 'Collisions', 1, '-', '-', '-', 1, 1, 0, 0, 0]], dtype=object)
原问题代码
import plotly.graph_objects as go from plotly.subplots import make_subplots import pandas as pd fig = make_subplots(rows=1, cols=1) unique_descriptions = data['Description'].unique() filtered_data = {description: data[data['Description'] == description] for description in unique_descriptions} country_counts = {country: {desc: {'count': 0, 'deaths': 0} for desc in unique_descriptions} for country in data['Country'].unique()} fig.add_trace( go.Choropleth( locations=data['Country'], z=[country_counts[country][desc]['count'] for country, desc in zip(data['Country'], data['Description'])], locationmode='country names', colorscale='YlOrRd', colorbar_title='Count', hovertemplate='<b>%{location}</b><br>Count: %{z}<br>Total Deaths: %{customdata}', customdata=[country_counts[country][desc]['deaths'] for country, desc in zip(data['Country'], data['Description'])], text=[country_counts[country][desc]['count'] for country, desc in zip(data['Country'], data['Description'])], textsrc='inside', visible=True # Set the initial trace as visible ) ) dropdown_options = [ dict( label='All Descriptions', method='update', args=[{'visible': [True] * len(fig.data)}], # Show all traces args2=[{'title': 'Cases and Deaths by Country (Description: All Descriptions)'}] ) ] for description in unique_descriptions: for country in filtered_data[description]['Country'].unique(): count = len(filtered_data[description][(filtered_data[description]['Country'] == country) & (filtered_data[description]['Description'] == description)]) deaths = filtered_data[description][(filtered_data[description]['Country'] == country) & (filtered_data[description]['Description'] == description)]['deaths'].sum() country_counts[country][description]['count'] = count country_counts[country][description]['deaths'] = deaths fig.add_trace( go.Choropleth( locations=data['Country'], z=[country_counts[country][desc]['count'] for country, desc in zip(data['Country'], data['Description'])], locationmode='country names', colorscale='YlOrRd', colorbar_title='Count', hovertemplate='<b>%{location}</b><br>Count: %{z}<br>Total Deaths: %{customdata}', customdata=[country_counts[country][desc]['deaths'] for country, desc in zip(data['Country'], data['Description'])], text=[country_counts[country][desc]['count'] for country, desc in zip(data['Country'], data['Description'])], textsrc='inside', visible=False # Set the trace as invisible initially ) ) dropdown_options.append( dict( label=description, method='update', args=[{'visible': [True if desc == description else False for desc in fig.data]}], # Show only the corresponding trace args2=[{'title': f'Cases and Deaths by Country (Description: {description})'}] ) ) fig.update_layout( title='Cases and Deaths by Country', updatemenus=[ dict( type='dropdown', buttons=dropdown_options, direction='down', showactive=True, x=0.1, y=1.1 ) ], geo=dict(showframe=False, showcoastlines=True, projection_type='natural earth') ) fig.update_layout(height=600) fig.show()
问题根源
- Trace数据逻辑错误:每个Description对应的trace使用全量数据的
locations,但z值仅匹配对应Description的行,其余行z为0,导致地图无法正确渲染。 - 下拉框可见性判断错误:将trace对象直接与Description字符串对比,筛选逻辑完全失效,无法正确显示对应trace。
- 数据初始化顺序颠倒:第一个"All Descriptions"的trace使用未计算的空统计值,后续循环才填充数据,逻辑顺序错误。
修正方案
- 提前聚合数据:按国家和Description分组计算病例数与死亡数,单独处理"All Descriptions"的全局统计。
- 每个Trace对应独立聚合数据:每个Description的trace仅使用该分类下的国家统计数据,确保
locations与z值一一对应。 - 修正下拉框可见性逻辑:根据trace的索引控制显示,第一个trace对应全局数据,后续依次对应各Description。
修正后的代码
import plotly.graph_objects as go import pandas as pd # 1. 聚合全局数据(All Descriptions) all_agg = data.groupby('Country').agg( count=('Case#', 'count'), deaths=('deaths', 'sum') ).reset_index() # 2. 按Description分组聚合数据 unique_descriptions = data['Description'].unique() desc_agg = {} for desc in unique_descriptions: filtered_data = data[data['Description'] == desc] agg_result = filtered_data.groupby('Country').agg( count=('Case#', 'count'), deaths=('deaths', 'sum') ).reset_index() desc_agg[desc] = agg_result # 3. 创建图表并添加Trace fig = go.Figure() # 添加全局数据Trace fig.add_trace(go.Choropleth( locations=all_agg['Country'], z=all_agg['count'], locationmode='country names', colorscale='YlOrRd', colorbar_title='Case Count', hovertemplate='<b>%{location}</b><br>Case Count: %{z}<br>Total Deaths: %{customdata}', customdata=all_agg['deaths'], visible=True )) # 添加各Description的Trace for desc in unique_descriptions: agg_data = desc_agg[desc] fig.add_trace(go.Choropleth( locations=agg_data['Country'], z=agg_data['count'], locationmode='country names', colorscale='YlOrRd', colorbar_title='Case Count', hovertemplate='<b>%{location}</b><br>Case Count: %{z}<br>Total Deaths: %{customdata}', customdata=agg_data['deaths'], visible=False )) # 4. 构建下拉框选项 dropdown_options = [ dict( label='All Descriptions', method='update', args=[ {'visible': [True] + [False]*len(unique_descriptions)}, {'title': 'Cases and Deaths by Country (All Descriptions)'} ] ) ] for idx, desc in enumerate(unique_descriptions): # 生成可见性列表:仅对应索引的Trace显示 visible_list = [False]*(len(unique_descriptions)+1) visible_list[idx+1] = True dropdown_options.append( dict( label=desc, method='update', args=[ {'visible': visible_list}, {'title': f'Cases and Deaths by Country (Description: {desc})'} ] ) ) # 5. 更新布局 fig.update_layout( title='Cases and Deaths by Country', updatemenus=[ dict( type='dropdown', buttons=dropdown_options, direction='down', showactive=True, x=0.1, y=1.1 ) ], geo=dict(showframe=False, showcoastlines=True, projection_type='natural earth'), height=600 ) fig.show()
内容的提问来源于stack exchange,提问作者Lior Broide
相关产品推荐
相关产品推荐

