如何在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()