Python+pandas+pyecharts 复刻 B 站风格世界人口动态排序轮播图(1960-2024)
前言
动态排序轮播图(Bar Chart Race)是当下 B 站、抖音等平台非常热门的数据可视化形式,凭借流畅的动画、直观的数据排名变化,能生动展现长时间维度下的数据变迁。本文将完整分享一套从数据清洗到商业级可视化的实战项目:使用pandas完成人口数据预处理,结合pyecharts打造 1960-2024 年世界各国人口动态排名轮播图,复刻 B 站主流深色风格交互图表,全程代码可直接运行,附踩坑解决方案与细节优化思路。
一、项目整体介绍
1.1 项目背景
本项目基于全球人口数据集,聚焦1960-2024 年世界主权国家人口变化,采用经典的动态排序轮播条形图形式,直观展示六十余年间各国人口排名、数量的动态演变。区别于基础可视化案例,本次项目对标 B 站专业数据视频的视觉风格与交互体验,兼顾实用性、美观性与交互性。
1.2 项目核心目标
- 数据纯净:剔除大洲、收入分组、非主权地区等无效数据,最终保留195 个真实主权国家数据;
- 动态排序:图表按年份自动轮播,每年依据人口总数降序排名,人口越多排名越靠前;
- 全交互功能:支持悬浮查看人口数值、播放 / 暂停、手动切换年份;
- 商业级美化:深色主题、动态配色、圆角柱状、丝滑轮播节奏,达到主流短视频平台可视化标准。
1.3 技术栈与运行环境
| 工具 / 库 | 作用 |
|---|---|
| Python 3.x | 主力编程语言 |
| pandas | 数据读取、清洗、宽表转长表、数据筛选 |
| pyecharts | 绘制柱状图、时间线轮播组件(Timeline) |
| JsCode | 实现柱子动态配色逻辑 |
| CDN 镜像配置 | 解决国内网络 ECharts 加载空白问题 |
前置依赖安装命令:
pip install pandas pyecharts
二、完整项目实现流程
2.1 环境初始化与库导入
首先导入项目所需全部依赖,重点配置国内 CDN 地址,这是解决 pyecharts 生成 HTML 页面空白的核心步骤(国内网络必加)。
python
运行
# 导入核心工具库
import pandas as pd
from pyecharts.charts import Bar, Timeline # 柱状图、时间线轮播
from pyecharts import options as opts # 图表配置项
from pyecharts.globals import ThemeType, CurrentConfig # 主题、全局配置
from pyecharts.commons.utils import JsCode # 动态JS配色工具
# 核心修复:配置国内CDN,解决HTML页面加载空白问题
CurrentConfig.ONLINE_HOST = "https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/"
print("环境初始化完成!")
2.2 数据加载与基础探查
2.2.1 数据集说明
- 数据源:本地 CSV 文件
世界人口数据-中文版(1960-2024).csv - 编码格式:
gbk(中文数据集专用编码,避免乱码) - 原始结构:宽表结构,一行对应一个地区,1960-2025 年年份作为独立列,总计 70 列、266 行。
2.2.2 数据读取与预览
python
运行
# 读取本地人口数据集,指定gbk编码防止中文乱码
df = pd.read_csv('./data/世界人口数据-中文版(1960-2024).csv', encoding='gbk')
# 查看前5行数据
print("数据前5行预览:")
print(df.head())
# 探查数据集整体结构、缺失值、数据类型
print("\n数据集基础信息:")
df.info()
数据解读:
- 特征列共 70 列:4 列基础属性(国家名称、国家代码、指标名称、指标代码)+ 66 列年份数据(1960-2025);
- 样本共 266 行:包含主权国家、大洲汇总、收入分组、海外领地等混合数据;
- 缺失值:2025 年所有人口数据均为
NaN,后续需直接剔除,有效年份区间为1960-2024; - 无效数据:
Country Name为空的行,多为非洲、美洲等大洲汇总数据,属于清洗重点。
2.3 核心数据清洗与预处理
原始数据混杂大量汇总数据、非主权地区,且宽表结构不适合动态排序绘图,需经过4 步清洗得到标准可用数据集。
2.3.1 拆分属性列与年份列
筛选出固定属性列和纯数字年份列,区分静态信息与时间序列数据:
python
运行
# 筛选所有列名为纯数字的列(年份列)
year_cols = [i for i in df.columns if i.isdigit()]
# 保留4个基础属性列
attr_cols = ['Country Name', 'Country Code', 'Indicator Name', 'Indicator Code']
print(f"有效年份数量:{len(year_cols)}")
print(f"年份范围:{year_cols[0]} - {year_cols[-1]}")
2.3.2 剔除无效数据(核心清洗)
分两步过滤:删除国家名称空值行 + 黑名单过滤汇总 / 非主权地区,最终保留 195 个主权国家。
python
运行
# 第一步:删除Country Name为空的行(大洲汇总类数据)
df = df.dropna(subset=['Country Name'])
# 第二步:定义黑名单,过滤大洲、收入分组、非主权领地、地区汇总
black_list = [
# 全球&大洲汇总
"世界","北美","东亚与太平洋地区","欧洲与中亚地区","拉丁美洲与加勒比海地区",
"中东、北非、阿富汗与巴基斯坦","撒哈拉以南非洲地区","南亚","欧洲联盟",
# 收入等级分类
"高收入国家","低收入国家","中等收入国家","中高等收入国家","中低等收入国家",
# 非主权地区/海外领地
"阿鲁巴","美属萨摩亚","中国香港特别行政区","中国澳门特别行政区","波多黎各",
"关岛","格陵兰岛","科索沃"
]
# 反向过滤:剔除黑名单内数据
df = df[~df["Country Name"].isin(black_list)].reset_index(drop=True)
print(f"清洗后剩余独立国家数量:{df['Country Name'].nunique()}")
运行结果输出:清洗后剩余独立国家数量:195,符合项目预期。
2.3.3 宽表转长表(数据重塑)
pyecharts 动态轮播图要求长表结构(一行 = 一个国家 + 一个年份 + 人口),使用pd.melt()完成宽表转长表:
python
运行
# 宽表转长表:拆分年份列,生成Year(年份)、Population(人口)新列
df_long = pd.melt(
df,
id_vars=attr_cols, # 固定不变的属性列
value_vars=year_cols, # 需要拆分的年份列
var_name="Year", # 拆分后年份列名
value_name="Population"# 拆分后人口数值列名
)
# 预览转换后数据
print("长表结构数据预览:")
print(df_long.head())
2.3.4 数据类型转换与最终去重
修正字段类型,剔除 2025 年无效空值,生成最终干净数据集:
python
运行
# 仅保留绘图所需三列:国家名称、年份、人口
df_clean = df_long[["Country Name", "Year", "Population"]].copy()
# 类型转换:年份转为整数,人口转为数值型
df_clean["Year"] = df_clean["Year"].astype(int)
df_clean["Population"] = pd.to_numeric(df_clean["Population"])
# 剔除2025年空值数据
df_clean.dropna(inplace=True)
print("最终清洗完成数据预览:")
print(df_clean.head())
print(f"有效数据总条数:{len(df_clean)}")
至此,数据预处理全部完成,数据集格式完全适配动态排序图表。
2.4 可视化分步实现
可视化分为三个阶段:单年份图表测试 → 基础轮播图 → B 站风格美化完整版,循序渐进排查问题。
2.4.1 阶段 1:单年份横向条形图测试
以 1990 年数据为例,测试横向柱状图渲染、排序、主题样式,验证基础逻辑:
python
运行
# 筛选1990年数据,按人口降序取前20名
test_df = df_clean[df_clean["Year"] == 1990]
test_df = test_df.sort_values(by="Population", ascending=False).head(20)
# 绘制横向条形图(深色主题)
bar_test = (
Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK)) # 深色主题
.add_xaxis(test_df["Country Name"].tolist()) # X轴:国家名称
.add_yaxis("人口", test_df["Population"].tolist()) # Y轴:人口数值
.reversal_axis() # 坐标轴反转 → 横向条形图
.set_global_opts(
title_opts=opts.TitleOpts(title="1990年世界人口TOP20排名", pos_left="center"),
legend_opts=opts.LegendOpts(is_show=False) # 隐藏图例,精简界面
)
.set_series_opts(label_opts=opts.LabelOpts(position="right")) # 数值标签置于柱子右侧
)
# 渲染为HTML文件,浏览器打开查看
bar_test.render("单年份测试图.html")
print("单年份测试图生成完成!")
常见报错解决:代码缩进错误IndentationError,Python 严格区分缩进,统一使用 4 个空格缩进即可修复。
2.4.2 阶段 2:基础版时间线轮播图
基于Timeline时间线组件,遍历所有年份,实现自动轮播、循环播放的动态排名图:
python
运行
# 获取所有唯一年份列表
year_list = df_clean["Year"].unique().tolist()
# 初始化时间线组件,设置画布尺寸
timeline = Timeline(init_opts=opts.InitOpts(width="1500px", height="820px", theme=ThemeType.DARK))
# 遍历每一个年份,逐个生成条形图并添加到时间线
for year in year_list:
# 筛选当年数据,人口降序取TOP20
data_df = df_clean[df_clean["Year"] == year]
data_df = data_df.sort_values(by="Population", ascending=False).head(20)
# 二次升序排序:配合reversal_axis,保证人口最多的国家显示在图表最上方
data_df = data_df.sort_values(by="Population", ascending=True)
# 提取绘图数据
country_list = data_df["Country Name"].tolist()
pop_list = data_df["Population"].tolist()
# 构建单年份条形图
bar = (
Bar()
.add_xaxis(country_list)
.add_yaxis("人口", pop_list)
.reversal_axis()
.set_global_opts(
title_opts=opts.TitleOpts(title=f"{year}年世界人口TOP20排名", pos_left="center"),
legend_opts=opts.LegendOpts(is_show=False)
)
.set_series_opts(label_opts=opts.LabelOpts(position="right"))
)
# 将当年图表加入时间线
timeline.add(bar, str(year))
# 配置轮播规则:自动播放、播放间隔600ms、循环播放
timeline.add_schema(
is_auto_play=True,
play_interval=600,
is_loop_play=True
)
# 生成基础轮播图
timeline.render("基础人口轮播图.html")
print("基础版动态轮播图生成完成!")
关键排序逻辑解释: 先降序取 TOP20 → 再升序排列 + .reversal_axis()反转坐标轴,最终实现人口越多,条形图越靠上,符合大众阅读习惯。
2.4.3 阶段 3:B 站风格完整版(深度美化)
在基础版之上完成全维度美化,实现动态配色、圆角柱子、定制提示框、高亮时间轴,达到 B 站专业可视化效果,也是本项目最终成品代码:
python
运行
# 初始化时间线,设置超大画布+极深灰背景(B站经典深色)
timeline = Timeline(
init_opts=opts.InitOpts(
width="1600px",
height="850px",
theme=ThemeType.DARK,
bg_color="#080808" # 极致深色背景,提升沉浸感
)
)
# 定义JS动态配色规则:8种高饱和颜色循环切换
color_js = JsCode("""
function (params){
let colorArr = ['#ff4757','#ffa502','#fffa65','#2ed573','#1e90ff','#3742fa','#a55eea','#22d2d0'];
return colorArr[params.dataIndex % colorArr.length];
}
""")
# 遍历所有年份生成图表
year_list = df_clean["Year"].unique().tolist()
for year in year_list:
data_df = df_clean[df_clean["Year"] == year]
data_df = data_df.sort_values(by="Population", ascending=False).head(20)
data_df = data_df.sort_values(by="Population", ascending=True)
country_list = data_df["Country Name"].tolist()
pop_list = data_df["Population"].tolist()
# 构建美化版条形图
bar = (
Bar()
.add_xaxis(country_list)
.add_yaxis(
"人口",
pop_list,
# 柱子样式:动态颜色、透明度、圆角(核心美化)
itemstyle_opts=opts.ItemStyleOpts(
color=color_js,
opacity=0.85,
border_radius=7 # 圆角柱子
),
# 数值标签样式:白色字体、格式化显示
label_opts=opts.LabelOpts(
position="right",
formatter="{c} 人",
font_size=11,
color="#ffffff"
)
)
.reversal_axis()
.set_global_opts(
title_opts=opts.TitleOpts(
title=f"{year}年世界人口TOP20排名",
pos_left="center",
title_textstyle_opts=opts.TextStyleOpts(color="#ffffff", font_size=18)
),
legend_opts=opts.LegendOpts(is_show=False),
# 定制悬浮提示框
tooltip_opts=opts.TooltipOpts(
trigger="axis",
formatter="<b>{b}</b><br/>人口:{c} 人"
)
)
)
timeline.add(bar, str(year))
# 时间轴专属美化:亮蓝色进度条、白色边框节点、加粗字体
timeline.add_schema(
is_auto_play=True,
play_interval=600,
is_loop_play=True,
# 时间轴文字:白色加粗
label_opts=opts.LabelOpts(color="#ffffff", font_size=11, font_weight="bold"),
# 时间轴线:亮蓝色、加粗
linestyle_opts=opts.LineStyleOpts(color="#00a1ff", width=4),
# 时间轴节点:蓝色圆点+白色边框
itemstyle_opts=opts.ItemStyleOpts(color="#00a1ff", border_color="#ffffff", border_width=2)
)
# 生成最终成品图表
timeline.render("B站风格_世界人口动态轮播图.html")
print("【最终版】B站风格人口动态排序轮播图生成完毕!")
三、项目亮点与核心优化点
3.1 数据层面亮点
- 精准数据过滤:通过「空值删除 + 黑名单」双重过滤,彻底剔除大洲、地区、海外领地等无效数据,保证数据严谨性;
- 宽表转长表:使用
melt完成数据重塑,是时序动态图表的通用数据处理思路,可复用在 GDP、销量等同类项目中; - 异常值处理:自动剔除 2025 年全空数据,避免图表出现空白条目。
3.2 可视化美化亮点(对标 B 站风格)
- CDN 适配:配置国内 JSdelivr 镜像,彻底解决 pyecharts 国内加载空白的经典问题;
- 动态配色:通过
JsCode实现柱子颜色循环切换,视觉效果更丰富; - 细节打磨:圆角柱状、半透明效果、定制悬浮提示框、高亮时间轴节点,贴合短视频平台审美;
- 交互完善:支持自动播放、暂停、手动切年份、悬浮看数据,满足全交互需求。
3.3 踩坑总结(新手必看)
- 中文乱码:CSV 文件读取必须指定
encoding='gbk',中文数据集通用方案; - HTML 空白:必须手动修改
CurrentConfig.ONLINE_HOST为国内 CDN,否则 ECharts 资源加载失败; - 排序颠倒:横向条形图需「先降序取 TOP,再升序排列」,配合
reversal_axis才能保证排名正常; - 缩进报错:Python 代码严格缩进,所有链式调用代码保持统一缩进格式;
- SettingWithCopyWarning:数据切片时使用
.copy()生成新 DataFrame,消除警告。
四、项目拓展方向
基于本项目框架,可快速拓展出更多同类可视化案例:
- 替换数据集:改为各国 GDP、城市房价、影视票房,复刻同款动态排名图;
- 功能升级:增加人口增长率计算,在图表中附加增长率标签;
- 样式拓展:切换 pyecharts 内置主题,制作复古风、科技风等不同风格图表;
- 数据筛选:单独筛选亚洲 / 欧洲国家,制作区域人口排名轮播图。
五、完整项目总结
本项目完整走完数据探查→清洗重塑→可视化测试→美化上线全流程,是 Python 数据分析 + 可视化的经典练手项目。核心知识点总结:
- pandas:数据读取、空值处理、黑名单过滤、宽长表转换;
- pyecharts:横向条形图、Timeline 时间线轮播、主题 / 样式 / 交互配置;
- 实战技巧:国内 CDN 适配、动态 JS 配色、排序逻辑优化、前端可视化细节打磨。
更多推荐



所有评论(0)