You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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
错误效果2

问题原因及修复方案

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个不可见,第二个高亮图层可见)

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 19:05:55