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

如何用Plotly Express绘制带独立时间滑块的并排Choropleth地图

实现并排带独立时间滑块的Plotly Choropleth地图

需求说明

  • 两张Choropleth地图并排展示
  • 每张地图配备独立的时间滑块(支持动画切换)
  • 仅保留一个共享的侧边颜色条
  • 已提供示例数据及基础绘图函数,但无法完成目标布局

解决方案

由于Plotly Express的分面功能不支持动画,需通过Plotly原生Figure对象手动组合子图并配置动画:

核心步骤

  1. 合并数据集并添加分组标识:将2019和2020的数据合并,新增year字段区分两个子图的数据源
  2. 创建子图框架:使用make_subplots生成2列的地理子图布局
  3. 添加动画图层:为每个年份的数据集创建独立的动画帧,分别添加到对应子图
  4. 共享颜色条:隐藏其中一个子图的颜色条,调整另一个的位置实现共享
  5. 调整动画控件:配置两个时间滑块的位置,避免重叠并对应各自子图
  6. 美化布局:移除边框、海岸线,调整边距和整体尺寸

完整实现代码

import pandas as pd
import plotly.express as px
from plotly.subplots import make_subplots
import plotly.graph_objects as go

# 合并数据并添加年份标识
data_2019 = {
    'region': ['Germany', 'Denmark', 'Japan'],
    'date': ['2019-01-01', '2019-02-01', '2019-02-01'],
    'valence': [0.3, 0.21, 0.1],
    'year': ['2019']*3
}
data_2020 = {
    'region': ['Germany', 'Denmark', 'Japan'],
    'date': ['2020-01-01', '2020-02-01', '2020-02-01'],
    'valence': [0.94, 0.71, 0.81],
    'year': ['2020']*3
}
df = pd.concat([pd.DataFrame(data_2019), pd.DataFrame(data_2020)], ignore_index=True)

# 创建2列子图布局
fig = make_subplots(
    rows=1, cols=2,
    specs=[[{"type": "choropleth"}, {"type": "choropleth"}]],
    subplot_titles=("2019 Data", "2020 Data")
)

# 创建动画帧
frames = []
dates_2019 = sorted(df[df['year']=='2019']['date'].unique())
dates_2020 = sorted(df[df['year']=='2020']['date'].unique())

# 为每个日期组合创建动画帧
for i, (date19, date20) in enumerate(zip(dates_2019, dates_2020)):
    frame = go.Frame(
        data=[
            # 2019子图对应帧
            go.Choropleth(
                locations=df[(df['year']=='2019') & (df['date']==date19)]['region'],
                locationmode='country names',
                z=df[(df['year']=='2019') & (df['date']==date19)]['valence'],
                hovertext=df[(df['year']=='2019') & (df['date']==date19)]['valence'],
                marker_line_width=0,
                coloraxis='coloraxis'
            ),
            # 2020子图对应帧
            go.Choropleth(
                locations=df[(df['year']=='2020') & (df['date']==date20)]['region'],
                locationmode='country names',
                z=df[(df['year']=='2020') & (df['date']==date20)]['valence'],
                hovertext=df[(df['year']=='2020') & (df['date']==date20)]['valence'],
                marker_line_width=0,
                coloraxis='coloraxis'
            )
        ],
        name=f"frame{i}"
    )
    frames.append(frame)

# 更新布局和动画配置
fig.update_layout(
    updatemenus=[
        # 2019的播放/暂停按钮
        dict(
            type="buttons",
            showactive=False,
            buttons=[dict(label="Play", method="animate", args=[None, {"frame": {"duration": 1000, "redraw": True}, "fromcurrent": True}]),
                     dict(label="Pause", method="animate", args=[[None], {"frame": {"duration": 0, "redraw": True}, "mode": "immediate"}])],
            x=0.1, y=-0.15
        ),
        # 2020的播放/暂停按钮
        dict(
            type="buttons",
            showactive=False,
            buttons=[dict(label="Play", method="animate", args=[None, {"frame": {"duration": 1000, "redraw": True}, "fromcurrent": True}]),
                     dict(label="Pause", method="animate", args=[[None], {"frame": {"duration": 0, "redraw": True}, "mode": "immediate"}])],
            x=0.9, y=-0.15
        )
    ],
    sliders=[
        # 2019的时间滑块
        dict(
            active=0,
            steps=[dict(method="animate", args=[[f"frame{i}"], {"frame": {"duration": 0, "redraw": True}, "mode": "immediate"}], label=date) for i, date in enumerate(dates_2019)],
            x=0.05, y=-0.2,
            len=0.4
        ),
        # 2020的时间滑块
        dict(
            active=0,
            steps=[dict(method="animate", args=[[f"frame{i}"], {"frame": {"duration": 0, "redraw": True}, "mode": "immediate"}], label=date) for i, date in enumerate(dates_2020)],
            x=0.55, y=-0.2,
            len=0.4
        )
    ],
    coloraxis=dict(
        colorscale=px.colors.sequential.Aggrnyl,
        range=(0,1),
        colorbar=dict(
            x=1.05, y=0.5, orientation='v'
        )
    ),
    showlegend=False,
    margin=dict(l=0, r=50, b=100, t=30),
    width=1200,
    height=600
)

# 配置子图地理样式
fig.update_geos(
    showframe=False,
    showcoastlines=False,
    projection_type='natural earth',
    row=1, col=1
)
fig.update_geos(
    showframe=False,
    showcoastlines=False,
    projection_type='natural earth',
    row=1, col=2
)

# 绑定动画帧
fig.frames = frames

fig.show()

关键说明

  • 两个子图共享同一颜色轴,确保颜色刻度统一
  • 每张地图拥有独立的播放/暂停按钮和时间滑块,可单独控制动画进度
  • 调整控件位置避免布局重叠,优化交互体验
  • 移除冗余边框和海岸线,简化视觉呈现

内容的提问来源于stack exchange,提问作者phoebe_albeduddel

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 04:57:33