【左手Python右手R】如何绘制“你追我赶”的动态条形图?

文摘   2025-02-04 05:52   山东  
动态条形图

如何在Python或R中制作那种动态的条形图,也就是随着时间的推移,条形图的各个条形会动态变化的那种。比如说,像那些展示不同国家GDP排名随时间变化的视频里常见的动态条形图?




首先,对于Python,有一个库叫做bar_chart_race,是专门用来做这种动态条形图的。不过需要先pip安装这个库。然后可能需要pandas来处理数据,确保数据格式正确。另外,需要matplotlib来调整一些图形设置,或者保存为视频的话需要ffmpeg的支持。所以代码的大致步骤应该是:安装必要的库,准备数据(数据可能需要是宽格式,每一列代表一个类别,每一行是时间点),然后调用bar_chart_race的函数生成动态图。不过需要注意数据是否需要排序,或者调整颜色等参数。

对于R语言,需要的包有gganimate,结合ggplot2来制作动画。此外,还需要gifski或者av来处理输出的动画文件。数据需要整理成长格式,每个时间点对应不同的观测值。然后使用ggplot创建条形图,再通过gganimate的transition_states或者transition_time函数来生成动画效果。可能需要设置视图跟随,保持坐标轴固定,这样在动画过程中条形的变化会更清晰。





例如我们已经已经有了一些时间序列的数据,每个时间点各个类别的值。如何将数据整理成适合的格式,比如Python中的宽格式或R中的长格式。可能还需要安装必要的依赖库,比如在Python中安装bar_chart_race的时候可能会遇到需要安装ffmpeg的问题,这时候需要安装ffmpeg并添加到系统路径中。另外,对动态条形图的细节有要求,比如颜色、标签、标题、速度控制等。在Python中,可以设置n_bars来限制显示的条形数量,设置sort='desc'来让条形按降序排列,调整steps_per_period来控制动画速度。在R中,可以使用view_follow来保持y轴的固定,使用ease_aes来控制动画的缓动效果。

我们先简单演示一下R语言中的操作:






#环境整理

rm(list=ls()) #移除所有变量数据

install.packages("") #安装包

library() #加载包

#安装并加载包

install.packages(c("ggplot2", "gganimate", "dplyr", "gifski"))

library(ggplot2)

library(gganimate)

library(dplyr)






# 1. 准备数据(长格式:time, name, value)

data <- data.frame(

  time = rep(2020:2023, each = 3),

  name = rep(c("A", "B", "C"), 4),

  value = c(100, 90, 80, 120, 110, 100, 150, 130, 120, 180, 160, 140)

)

# 2. 创建动画

anim <- data %>%

  ggplot(aes(x = value, y = reorder(name, value), fill = name)) +

  geom_col(width = 0.8) +

  geom_text(aes(label = value), hjust = -0.1) +

  labs(title = "Year: {frame_time}", x = "Value", y = "Category") +

  theme_minimal() +

  transition_time(time) +

  view_follow(fixed_y = TRUE) +  # 固定Y轴范围

  ease_aes("cubic-in-out")

# 3. 渲染动画

animate(anim, 

        nframes = 100,   # 总帧数

        fps = 10,        # 帧率

        width = 800, 

        height = 600,

        renderer = gifski_renderer("C:/Users/L/Desktop/race.gif"))  # 保存为GIF







或者使用我们自定义的数据,比如"天枢","天璇","天玑","天权","玉衡","开阳","瑶光"不同时间的变化。

# 1. 准备数据(长格式:time, name, value)

data <- data.frame(

  time = rep(2016:2025, each = 7),

  name = rep(c("天枢","天璇","天玑","天权","玉衡","开阳","瑶光"), 10),

  value = c(22,94,89,4,60,96,88,

            17,56,93,50,20,13,94,

            82,17,13,46,23,55,6,

            53,98,72,53,99,10,67,

            33,58,50,89,80,69,85,

            27,66,10,27,71,37,26,

            95,10,66,60,66,12,65,

            37,98,57,21,97,61,85,

            22,17,15,1,84,8,39,

            82,93,59,61,6,36,57)

            )

# 2. 创建动画

anim <- data %>%

  ggplot(aes(x = value, y = reorder(name, value), fill = name)) +

  geom_col(width = 0.8) +

  geom_text(aes(label = value), hjust = -0.1) +

  labs(title = "Year: {frame_time}", x = "Value", y = "Category") +

  theme_minimal() +

  transition_time(time) +

  view_follow(fixed_y = TRUE) +  # 固定Y轴范围

  ease_aes("cubic-in-out")

# 3. 渲染动画

animate(anim, 

        nframes = 100,   # 总帧数

        fps = 10,        # 帧率

        width = 800, 

        height = 600,

        renderer = gifski_renderer("C:/Users/L/Desktop/race2.gif"))  # 保存为GIF








那么在Python中的操作如下:

#安装调用加载库

import pandas as pd

import bar_chart_race as bcr

import matplotlib.pyplot as plt

import matplotlib.animation as animation

# 设置matplotlib支持中文显示

plt.rcParams['font.sans-serif'] = ['SimHei']  # 指定默认字体为黑体

plt.rcParams['axes.unicode_minus'] = False  # 解决负号'-'显示为方块的问题






# 1.生成示例数据

data = {

    '天枢': [22,94,89,4,60,96,88],

    '天璇': [17,56,93,50,20,13,94],

    '天玑': [82,17,13,46,23,55,6],

    '天权': [53,98,72,53,99,10,67],

    '玉衡': [33,58,50,89,80,69,85],

    '开阳': [27,66,10,27,71,37,26],

    '瑶光': [95,10,66,60,66,12,65]

    }

df = pd.DataFrame(data, index=[2018, 2019, 2020, 2021, 2022, 2023, 2024])






# 2. 生成动态条形图

bcr.bar_chart_race(

    df=df,

    filename=r'C:\Users\L\Desktop\race.mp4',  # 保存为MP4文件

    title='动态条形图示例',

    n_bars=5,            # 显示前5个分类

    sort='desc',         # 降序排列

    steps_per_period=30, # 每时间段动画帧数

    period_length=1000   # 每时间段显示时长(毫秒)

)

#或者可以将生成的视频文件转换为GIF格式

#ffmpeg -i race.mp4 -vf "fps=10,scale=640:-1:flags=lanczos" -loop 0 race.gif










# 3.直接生成交互式 HTML(无需 FFmpeg)

bcr.bar_chart_race(

    df=df,

    filename=None,  # 不保存文件

    n_bars=3,

    title='动态条形图示例',

    steps_per_period=10,

    period_length=2000,  # 每帧停留时间(毫秒)

    writer='html'  # 输出为 HTML 动画

)





# 3.生成GIF版本的操作

# 初始化画布

fig, ax = plt.subplots(figsize=(8, 5))

ax.set_xlim(0, df.values.max() * 1.1)

# 动态更新函数

def update(year):

    ax.clear()

    row = df.loc[year].sort_values(ascending=False)

    ax.barh(row.index, row.values, color=['#1f77b4', '#ff7f0e', '#2ca02c'])

    ax.set_title(f'Year: {year}')

    ax.set_xlabel('Value')

# 创建动画

ani = animation.FuncAnimation(

    fig,

    update,

    frames=df.index,  # 按时间顺序传递年份

    interval=1000,    # 每帧间隔(毫秒)

    repeat=True

    )

# 保存为 GIF(需安装 ImageMagick)

ani.save(r'C:\Users\L\Desktop\animation.gif', writer='imagemagick')

# 直接显示动画

plt.show()








医学统计数据分析
分享交流SPSS、R语言、Python、ArcGis、Geoda、GraphPad、数据分析图表制作等心得。承接数据分析,论文修回,医学统计,空间分析,问卷分析业务。若有投稿和数据分析代做需求,可以直接联系我,谢谢!
 最新文章