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

如何用Matplotlib创建保留元素的动画堆叠条形图

解决Matplotlib动画堆叠条形图保留已显示元素的问题

你当前的代码没法保留已显示的元素,问题出在ArtistAnimation的用法错了——它需要传入的是每一帧对应的艺术家列表,不是所有元素堆在一起的扁平列表;而且它默认会清掉上一帧的内容。下面给两种可行的解决办法,分别用FuncAnimation和修正后的ArtistAnimation实现。

方案一:用FuncAnimation逐步显示元素

这种方法更直白,先把所有堆叠条形元素都创建好但隐藏,然后每一帧只把下一个元素设为可见,之前的元素保持显示。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import pandas as pd

def bstack(df, title, ylabel, xlabel):
    fig, ax = plt.subplots()
    ax.set_title(title)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    ax.set_xticks(range(df.shape[0]))
    ax.set_xticklabels(df.index)  # 自定义x轴标签,不需要可以删掉
    
    # 提前生成所有堆叠条形,记录每个条形的参数
    all_bars = []
    for x_idx in range(df.shape[0]):
        row = df.iloc[x_idx]
        bottom = 0
        for col_name, val in row.items():
            # 画每个堆叠块,第一行的块才加标签(避免图例重复)
            bar = ax.bar(x_idx, val, bottom=bottom, label=col_name if x_idx == 0 else "")
            all_bars.append(bar[0])  # 取BarContainer里的单个条形元素
            bottom += val
    
    # 整理图例,只保留唯一的标签和对应样式
    handles, labels = ax.get_legend_handles_labels()
    unique_legend = dict(zip(labels, handles))
    ax.legend(unique_legend.values(), unique_legend.keys())
    
    # 初始状态:所有条形都隐藏
    for bar in all_bars:
        bar.set_visible(False)
    
    def animate(i):
        # 第i帧显示前i+1个条形
        if i < len(all_bars):
            all_bars[i].set_visible(True)
        return all_bars[:i+1]
    
    # 创建动画:总帧数是堆叠元素总数,interval是每帧间隔毫秒,blit=True提升效率
    anim = animation.FuncAnimation(fig, animate, frames=len(all_bars), interval=300, blit=True)
    anim.save("stack.gif", writer='ffmpeg')

# 测试数据
df = pd.DataFrame({'col1':[1,2,3,4], 'col2':[4,3,2,1], 'col3':[5,6,7,8]})
bstack(df, "动态堆叠条形图", "数值", "X轴")

关键说明:

  • 先一次性生成所有堆叠块,初始隐藏,避免重复创建图形元素
  • 动画帧只负责切换元素的可见性,不会清除已有内容
  • 处理图例时去重,避免每个堆叠块都生成重复的图例项

方案二:修正ArtistAnimation的使用

ArtistAnimation要求传入的是帧的列表,每个帧是该帧需要显示的所有艺术家元素。我们需要把每一步已显示的所有元素打包成一个帧,这样播放时就会保留之前的内容。

import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import pandas as pd

def bstack(df, title, ylabel, xlabel):
    fig, ax = plt.subplots()
    ax.set_title(title)
    ax.set_xlabel(xlabel)
    ax.set_ylabel(ylabel)
    ax.set_xticks(range(df.shape[0]))
    
    frames_artists = []  # 存储每帧的艺术家列表
    displayed_bars = []  # 记录当前已显示的所有条形
    added_legend = False
    
    for x_idx in range(df.shape[0]):
        row = df.iloc[x_idx]
        bottom = 0
        for col_name, val in row.items():
            # 画当前堆叠块,只在第一次加标签
            bar = ax.bar(x_idx, val, bottom=bottom, label=col_name if not added_legend else "")
            displayed_bars.append(bar[0])
            # 把当前所有已显示的条形作为新的一帧
            frames_artists.append(list(displayed_bars))
            bottom += val
        added_legend = True  # 标记图例已添加,避免重复
    
    ax.legend()
    
    # 创建动画,repeat=False防止循环播放
    anim = animation.ArtistAnimation(fig, frames_artists, interval=300, repeat=False)
    anim.save("stack_artist.gif", writer='ffmpeg')

# 测试数据
df = pd.DataFrame({'col1':[1,2,3,4], 'col2':[4,3,2,1], 'col3':[5,6,7,8]})
bstack(df, "动态堆叠条形图", "数值", "X轴")

关键说明:

  • frames_artists里每个元素都是当前帧要显示的所有条形的列表,比如第3帧包含前3个堆叠元素
  • 每添加一个新元素就生成一个新帧,这样ArtistAnimation播放时会保留之前的元素
  • 控制图例只添加一次,避免图例重复堆积

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 17:57:14