Plotly地图显示异常:图例乱序重复、地图变形问题求助
Plotly地图图例混乱重复、地图变形问题排查
问题描述
使用Plotly展示地图时出现以下问题:
- 图例顺序混乱且重复
- 切换下拉选项后地图变形,仅初始地图显示正常
代码实现
import pandas as pd import json import plotly.graph_objects as go from urllib.request import urlopen def generate_health_fig(): skc = pd.DataFrame( ['20001', '20003', '20011', '20015', '20019', '20021', '20031', '20035', '20037', '20049', '20059', '20073', '20077', '20079', '20095', '20099', '20107', '20113', '20115', '20121', '20125', '20133', '20155', '20173', '20191', '20205', '20207'], columns=['fips'] ) token = 'A' with urlopen('https://raw.githubusercontent.com/plotly/datasets/master/geojson-counties-fips.json') as response: counties = json.load(response) df = pd.read_csv('data/healthy-wealthy-wise-data.csv', dtype={'fips':'str'}) df = df.sort_values(by=['healthy_quartile', 'fair_poor_quartile']) colorscales = [ [(0.0, 'rgba(22,74,88,1.0)'), (1.0, 'rgba(22,74,88,1.0)')], [(0.0, 'rgba(22,74,88,0.75)'), (1.0, 'rgba(22,74,88,0.75)')], [(0.0, 'rgba(22,74,88,0.5)'), (1.0, 'rgba(22,74,88,0.5)')], [(0.0, 'rgba(22,74,88,0.25)'), (1.0, 'rgba(22,74,88,0.25)')] ] fig = go.Figure() health_quartile_to_z = {quartile: i for i, quartile in enumerate(df['healthy_quartile'].unique())} fair_poor_quartile_to_z = {quartile: i for i, quartile in enumerate(df['fair_poor_quartile'].unique())} # Add the first choropleth map (Health Indicator) for i, indicator in enumerate(['healthy_quartile', 'fair_poor_quartile']): for quartile in df[indicator].unique(): dfp = df[df[indicator] == quartile] if indicator == 'healthy_quartile': z_vals = [health_quartile_to_z[quartile]] * len(dfp) # Use health_quartile_to_z for health indicator else: z_vals = [fair_poor_quartile_to_z[quartile]] * len(dfp) # Use fair_poor_quartile_to_z for fair/poor health fig.add_choroplethmapbox( geojson=counties, locations=dfp['fips'], z=z_vals, featureidkey='id', showlegend=True, name='Quartile ' + str(quartile), colorscale=colorscales[health_quartile_to_z[quartile]], # Use health colorscale for health indicator showscale=False, text='County: ' + dfp['county'].str.title() + '<br>Quartile: ' + dfp[indicator].str.split(' ').str[0], hoverinfo='text', visible=(i == 0), ) # Rest of the code remains the same... choropleth = go.Choroplethmapbox( geojson=counties, locations=df[df.fips.isin(skc['fips'].tolist())]['fips'], z=df[df.fips.isin(skc['fips'].tolist())]['healthy_index'], zmin=df['healthy_index'].min(), zmax=df['healthy_index'].max(), colorscale=[[0, 'rgba(0, 0, 0, 0)'], [1, 'rgba(0, 0, 0, 0)']], marker_line_color='rgb(255,193,0)', marker_line_width=2, showscale=False, text='County: ' + df[df.fips.isin(skc['fips'].tolist())]['county'].str.title() + '<br>Quartile: ' + df[df.fips.isin(skc['fips'].tolist())]['healthy_quartile'].str.split(' ').str[0], hoverinfo='text', visible=True ) choropleth1 = go.Choroplethmapbox( geojson=counties, locations=df[df.fips.isin(skc['fips'].tolist())]['fips'], z=df[df.fips.isin(skc['fips'].tolist())]['fair_poor_ind'], zmin=df['fair_poor_ind'].min(), zmax=df['fair_poor_ind'].max(), colorscale=colorscales[0], # Use the same color scale as the first map (changed this line) marker_line_color='rgb(255,0,0)', marker_line_width=2, showscale=False, text='County: ' + df[df.fips.isin(skc['fips'].tolist())]['county'].str.title() + '<br>Quartile: ' + df[df.fips.isin(skc['fips'].tolist())]['fair_poor_quartile'].str.split(' ').str[0], hoverinfo='text', visible=False # Set the first map as hidden initially ) fig.add_trace(choropleth) fig.add_trace(choropleth1) fig.update_layout( legend_title='Index Performance', margin={'r': 0, 't': 0, 'l': 0, 'b': 0}, mapbox_accesstoken=token, mapbox=dict(style='carto-positron', zoom=6, center={'lat': 38.4937, 'lon': -98.3804}) ) # Add Restyle Dropdown dropdown_options = [ {'label': 'Health Indicator', 'value': 'health_indicator'}, {'label': '% Fair or Poor Health', 'value': 'fair_poor_quartile'} ] button_args = [ dict( args=[{'visible': [True]*4 + [False]}], # Show the first map (Health Indicator) and hide the second label='Health Indicator', method='update' ), dict( args=[{'visible': [False] + [True]*4}], # Show the second map (% Fair or Poor Health) and hide the first label='% Fair or Poor Health', method='update' ) ] fig.update_layout( updatemenus=[ go.layout.Updatemenu( buttons=button_args, direction='down', pad={'r': 10, 't': 10}, showactive=True, x=0.99, xanchor='right', y=1.1, yanchor='top' ) ], annotations=[ dict(text='Health Indicator', showarrow=False, x=0.5, y=1.05, xref='paper', yref='paper', align='center') ] ) return fig # Generate the health_fig health_fig = generate_health_fig() # Display the figure health_fig.show()
效果对比
正确效果

错误效果


问题原因及修复方案
1. 图例混乱重复
- 原因:循环添加两个指标的所有四分位数图层时,每个图层都设置
showlegend=True,导致图例条目重复;未对图例名称做区分,且后续添加的高亮图层未隐藏图例,进一步干扰显示。 - 修复:
- 为不同指标的图例名称添加前缀(如
Health Quartile X、Fair/Poor Quartile X),避免名称重叠; - 仅让每个指标的第一个四分位数图层显示图例,其余设为
showlegend=False; - 将
choropleth和choropleth1的showlegend设为False,移除高亮图层的图例条目。
- 为不同指标的图例名称添加前缀(如
2. 地图变形
- 原因:下拉按钮的
visible参数长度与实际图层数不匹配。代码中实际添加了10个图层(2个指标×4个四分位数 + 2个高亮图层),但按钮的visible数组仅设置了5个元素,导致部分图层可见性未被正确控制,多图层叠加造成变形。 - 修复:
- 调整按钮的
visible数组长度匹配总图层数:- 显示Health Indicator时:
[True]*4 + [False]*4 + [True, False](前4个四分位数图层可见,后4个不可见,第一个高亮图层可见) - 显示% Fair or Poor Health时:
[False]*4 + [True]*4 + [False, True](后4个四分位数图层可见,前4个不可见,第二个高亮图层可见)
- 显示Health Indicator时:
- 调整按钮的
3. 颜色映射错误
- 原因:添加
fair_poor_quartile图层时,仍使用health_quartile_to_z[quartile]获取颜色刻度索引,导致颜色与四分位数不匹配。 - 修复:根据当前指标选择对应的索引,当
indicator == 'fair_poor_quartile'时,使用fair_poor_quartile_to_z[quartile]获取颜色刻度。
修复后的关键代码片段
# 修改图层添加循环 for i, indicator in enumerate(['healthy_quartile', 'fair_poor_quartile']): for quartile in df[indicator].unique(): dfp = df[df[indicator] == quartile] if indicator == 'healthy_quartile': z_vals = [health_quartile_to_z[quartile]] * len(dfp) color_idx = health_quartile_to_z[quartile] legend_name = f'Health Quartile {quartile.split(" ")[0]}' else: z_vals = [fair_poor_quartile_to_z[quartile]] * len(dfp) color_idx = fair_poor_quartile_to_z[quartile] legend_name = f'Fair/Poor Quartile {quartile.split(" ")[0]}' # 仅显示每个指标的第一个图例条目 show_legend = (quartile == df[indicator].unique()[0]) fig.add_choroplethmapbox( geojson=counties, locations=dfp['fips'], z=z_vals, featureidkey='id', showlegend=show_legend, name=legend_name, colorscale=colorscales[color_idx], showscale=False, text='County: ' + dfp['county'].str.title() + '<br>Quartile: ' + dfp[indicator].str.split(' ').str[0], hoverinfo='text', visible=(i == 0), ) # 修改高亮图层的showlegend参数 choropleth = go.Choroplethmapbox( # 其他参数不变 showlegend=False, visible=True ) choropleth1 = go.Choroplethmapbox( # 其他参数不变 showlegend=False, visible=False ) # 修改下拉按钮的visible参数 button_args = [ dict( args=[{'visible': [True]*4 + [False]*4 + [True, False]}], label='Health Indicator', method='update' ), dict( args=[{'visible': [False]*4 + [True]*4 + [False, True]}], label='% Fair or Poor Health', method='update' ) ]
内容的提问来源于stack exchange,提问作者raph mwanza
相关产品推荐
相关产品推荐

