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

如何用Matplotlib FuncAnimation实现Pandas年度数据的GeoPandas动态可视化

美国各州百分比变化动态地图实现问题

问题说明

已将美国各州百分比变化数据集与美国州界shapefile合并,希望通过Matplotlib的FuncAnimation按年份循环展示动态地图,但遇到以下问题:

  • 将shape.plot()放入animate函数或循环时,会丢失shape.boundary.plot()设置的边界样式
  • 不清楚如何动态切换shape.plot()的column参数实现年份数据更新
  • 想了解是否可通过getter/setter修改属性,或让边界持久化后叠加年份数据

数据样例

df.head()

Year        2017    2018    2019    2020    2021    2022    2023
State                           
Alabama     0.00    0.00     0.00   0.00    0.00    0.00    0.00
Arizona     0.24    0.00     0.03  -0.15    0.56   -0.36    0.21
Arkansas    0.35   -0.06    -0.03   0.03   -0.00   -0.13   -0.02
California  0.13    0.07    -0.03   0.04    0.21   -0.10    0.03
Colorado    0.81   -0.18    -0.01  -0.05    0.10   -0.03   -0.51

尝试代码

shape = gpd.read_file(shapefile)
years = dfc.columns  # dfc = % change df
tspan = len(dfc.columns)

""" merge map with dataframe on state name column """ 
shape = pd.merge(
    left=shape,
    right=dfc,
    left_on='NAME',
    right_on='State',
    how='right'
)
""" init pyplot 'OO method' """
fig, ax = plt.subplots(figsize=(10, 5))

""" draw shape boundary """
ax = shape.boundary.plot(
    ax=ax,
    edgecolor='black', 
    linewidth=0.3, 
    )

""" plot shape """
ax = shape.plot(
    ax=ax,
    column=year, # what I need access to
    legend=True, cmap='RdBu_r', 
    legend_kwds={'shrink': 0.3, 'orientation': 'horizontal', 'format': '%.0f'})

""" cycle through columns -- not operable yet """ 
def animate(year):
    ax.clear()
    ax.shape.column(year)

animation = FuncAnimation(states, animate, frames=(dfc.columns[0], dfc.columns[tspan] + 1, 1), repeat=True, interval=1000)

可行解决方案

核心思路

  • 提前绘制州界并持久化,避免每次动画更新时清除边界
  • 在animate函数中仅更新年份对应的填充图层,不清除整个坐标轴
  • 固定颜色映射范围,避免图例随年份数据波动

完整实现代码

import geopandas as gpd
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import pandas as pd

# 读取并合并数据
shapefile = "cb_2018_us_state_500k.shp"  # 替换为你的文件路径
shape = gpd.read_file(shapefile)
dfc = pd.read_csv("your_percent_change_data.csv", index_col="State")  # 替换为你的数据路径

shape = pd.merge(
    left=shape,
    right=dfc,
    left_on='NAME',
    right_on='State',
    how='right'
)

# 初始化画布和坐标轴
fig, ax = plt.subplots(figsize=(12, 6))
ax.set_aspect('equal')

# 提前绘制州界(持久化)
shape.boundary.plot(ax=ax, edgecolor='black', linewidth=0.3)

# 固定颜色映射范围(基于所有年份数据的极值)
vmin = dfc.min().min()
vmax = dfc.max().max()

# 初始化颜色条(仅创建一次)
sm = plt.cm.ScalarMappable(cmap='RdBu_r', norm=plt.Normalize(vmin=vmin, vmax=vmax))
sm.set_array([])
cbar = fig.colorbar(sm, ax=ax, shrink=0.3, orientation='horizontal', format='%.2f')
cbar.set_label('百分比变化')

# 定义动画函数
def animate(year):
    # 清除之前的填充图层(保留边界和颜色条)
    for artist in ax.collections:
        artist.remove()
    
    # 绘制当前年份的填充数据
    shape.plot(
        ax=ax,
        column=year,
        cmap='RdBu_r',
        vmin=vmin,
        vmax=vmax,
        legend=False  # 已提前创建颜色条,无需重复生成
    )
    
    # 更新标题显示当前年份
    ax.set_title(f"美国各州百分比变化 - {year}")

# 创建动画
animation = FuncAnimation(
    fig,
    animate,
    frames=dfc.columns,
    repeat=True,
    interval=1000  # 每帧间隔1秒
)

# 可选:保存动画为MP4(需要ffmpeg支持)
# animation.save('state_percent_change.mp4', writer='ffmpeg', dpi=150)

plt.show()

关键说明

  1. 边界持久化:先绘制州界,之后在animate中仅清除ax.collections中的填充图层,保留边界线条(边界属于ax.lines,不会被移除)
  2. 颜色映射固定:通过vmin和vmax基于所有年份数据的极值设置颜色范围,确保不同年份的颜色刻度一致,避免图例跳动
  3. 高效更新:直接移除旧的填充集合再绘制新的,比清除整个坐标轴更高效,且保留了边界和颜色条
  4. 图例优化:提前创建颜色条,避免每次动画帧都重新生成图例,提升流畅度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 11:32:05