Python+pyecharts 复刻 B 站爆款动态人口排行榜|1960-2024 世界各国人口动态轮播图
一、前言
刷 B 站经常看到各类动态排名轮播柱状图(Bar Chart Race),人口、GDP 历年变迁动态排行视频播放量动辄几十万。本文基于Pandas+pyecharts完整复刻 B 站同款深色风动态人口排行,数据集覆盖1960–2024 全球各国人口,从原始脏数据清洗→数据重塑→单图测试→全量时间线轮播→B 站风格精细化美化全流程落地,生成可交互 HTML 动态排行,悬停查看人口、自动轮播、手动切换年份全部实现,新手可一键复现全代码。
项目最终效果
- 深色暗黑 B 站主题背景,柱子随机循环渐变彩色 + 圆角样式;
- 每年自动按人口降序取 Top20,人口越多国家排在图表最上方;
- 时间轴自动 600ms 切换年份、循环播放,支持暂停 / 拖拽切换年份;
- 鼠标悬浮单个国家,弹窗展示国家名称 + 精准人口数值;
- 导出 HTML 文件,浏览器直接打开,无需额外部署环境。
二、技术栈与环境准备
1. 依赖库安装
打开 cmd 执行 pip 安装依赖:
bash
pip install pandas pyecharts
2. 技术选型说明
表格
| 工具 | 用途 |
|---|---|
| Pandas | 原始数据读取、黑名单过滤清洗、宽表转长表、类型转换、空值剔除 |
| pyecharts | Bar 横向柱状图绘制、Timeline 时间线实现逐年轮播、图表样式配置 |
| JsCode | JS 自定义动态柱子配色,实现不同排名柱子自动换色 |
| CDN 替换 | 替换 echarts 国内 CDN,解决 HTML 打开空白、资源加载失败问题 |
三、项目整体开发流程
整体分四大阶段:数据加载探查→黑名单精准清洗→数据格式重塑→可视化分步开发(单图→基础轮播→B 站美化完整版)
四、步骤 1:数据导入与全局配置(解决国内 HTML 空白坑)
4.1 全局导包 + 替换 CDN(关键!国内必写)
很多同学生成 HTML 打开空白,根源是 pyecharts 默认海外 CDN 无法访问,提前替换 jsdelivr 国内镜像:
python
# 1.导入核心工具
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
# 修复CDN,解决国内网络HTML空白(必加配置)
CurrentConfig.ONLINE_HOST = "https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/"
4.2 读取人口数据集
数据集:世界人口数据-中文版(1960-2024).csv,编码 gbk 避免中文乱码
python
# 读取中文版人口数据集
df = pd.read_csv('./data/世界人口数据-中文版(1960-2024).csv',encoding='gbk')
# 预览前5行
df.head()
4.3 原始数据探查
- 原始数据:266 行、70 列,4 列基础属性(国家名、国家编码、指标名、指标编码),剩余 66 列为 1960–2025 年份人口列;
- 2025 年全为空值 NaN,有效统计区间:
1960~2024; - 脏数据问题:包含全球、各大洲、收入分组、非主权地区(港澳台、海外领地)汇总数据,不能参与国家排行,需要黑名单过滤。
五、步骤 2:核心数据清洗(项目重难点:黑名单剔除无效数据)
5.1 定义黑名单,剔除非主权 / 汇总数据
黑名单包含:全球 / 大洲汇总、收入等级分类、世界银行分组、非主权领地 / 海外行政区,最终筛选出 195 个合法主权国家:
python
#黑名单:剔除大洲、收入等级、发展区域汇总、非主权地区
black_list = [
# 全球 & 大洲汇总
"世界", "北美", "东亚与太平洋地区", "欧洲与中亚地区",
"东亚与太平洋地区(不包括高收入)", "欧洲与中亚地区(不包括高收入)",
"拉丁美洲与加勒比海地区", "拉丁美洲与加勒比海地区(不包括高收入)",
"中东、北非、阿富汗与巴基斯坦", "中东与北非地区(不包括高收入)",
"撒哈拉以南非洲地区", "撒哈拉以南非洲地区(不包括高收入)",
"南亚", "小国", "加勒比小国", "太平洋岛国", "其他小国",
"未分类国家", "阿拉伯联盟国家", "欧洲联盟", "欧洲货币联盟",
"经合组织成员", "重债穷国 (HIPC)", "脆弱和受衝突影響的情況下",
# 收入等级
"高收入国家", "低收入国家", "中等收入国家",
"中高等收入国家", "中低等收入国家", "中低收入国家",
#人口红利阶段
"早人口紅利", "後期人口紅利", "預人口紅利", "人口紅利之後",
#发展水平分类
"最不发达国家:联合国分类",
# 世界银行分组
"IBRD与IDA", "只有IBRD", "只有IDA", "IDA總", "IDA混合",
"东亚与太平洋地区 (IBRD与IDA)", "欧洲与中亚地区 (IBRD与IDA)",
"拉丁美洲与加勒比海地区 (IBRD与IDA)", "中东与北非地区 (IBRD与IDA)",
"南亚 (IBRD与IDA)", "撒哈拉以南非洲地区 (IBRD与IDA)",
# 地区/领地/非主权地区
"阿鲁巴", "美属萨摩亚", "百慕大", "库拉索", "开曼群岛",
"海峡群岛", "法罗群岛", "直布罗陀", "格陵兰", "关岛",
"中国香港特别行政区", "中国澳门特别行政区", "圣马丁(法属)",
"圣马丁(荷属)", "北马里亚纳群岛", "新喀里多尼亚", "波多黎各",
"约旦河西岸和加沙", "法属波利尼西亚", "特克斯科斯群岛",
"英屬維爾京群島", "美属维京群岛", "科索沃"
]
#反向过滤:不在黑名单的数据保留
df = df[~df["Country Name"].isin(black_list)].reset_index(drop=True)
print("过滤后剩余主权国家数量:",df["Country Name"].nunique())
5.2 宽表转长表(melt 重塑数据格式)
原始是宽格式:一行国家、多列年份;绘图需要长格式:一行 = 某国某一年人口,使用pd.melt拆分行:
python
#筛选属性列(固定字段)和年份列(纯数字列)
attr_cols = ["Country Name","Country Code","Indicator Name","Indicator Code"]
year_cols = [col for col in df.columns if col.isdigit()]
# melt:宽表转为长表
df_long = pd.melt(
df,
id_vars=attr_cols, # 不变字段:国家信息
value_vars=year_cols, # 需要拆分的所有年份列
var_name="Year", # 拆分后新列:年份
value_name="Population" # 拆分后新列:人口数值
)
5.3 数据类型转换 + 空值清理
python
# 只保留绘图需要三列
df_clean=df_long[["Country Name","Year","Population"]]
#年份转为整数
df_clean["Year"]=df_clean["Year"].astype(int)
#人口转为数值类型
df_clean["Population"]=pd.to_numeric(df_clean["Population"])
#删除人口空值(剔除2025无效空数据)
df_clean.dropna(inplace=True)
#查看清洗后数据
df_clean.head()
清洗后:有效数据 12675 条,仅保留 195 个主权国家 1960–2024 人口数据。
六、步骤 3:可视化开发(分 3 个版本迭代)
版本 1:单年份静态横向柱状测试(1990 年 Top20 人口排行)
先单年绘图验证逻辑,reversal_axis()实现横向柱状,深色主题:
python
# 筛选1990年数据
test_df=df_clean[df_clean["Year"]==1990]
#人口降序取前20
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())
.add_yaxis("人口",test_df["Population"].tolist())
.reversal_axis() #坐标轴反转→横向柱状
.set_global_opts(
title_opts=opts.TitleOpts(title="1990年世界人口排名",pos_left="center"),
legend_opts=opts.LegendOpts(is_show=False), #隐藏图例
)
.set_series_opts(label_opts=opts.LabelOpts(position="right")) #数值在柱子右侧
)
bar_test.render_notebook() #jupyter预览
# bar_test.render("1990人口排行.html") #导出html
版本 2:基础版 TimeLine 全年份自动轮播
遍历所有年份,逐年生成柱状图加入时间轴,实现自动轮播:
python
year_list=df_clean["Year"].unique().tolist()
#初始化时间线
timeline = Timeline(init_opts=opts.InitOpts(width="1500px",height="820px",theme=ThemeType.DARK,bg_color="#0a0a0a"))
#循环每一年绘图
for year in year_list:
data_df=df_clean[df_clean["Year"]==year]
#降序取top20,再升序排序(配合反转坐标轴,大数在上)
data_df=data_df.sort_values(by="Population",ascending=False).head(20)
data_df=data_df.sort_values(by="Population",ascending=True)
country=data_df["Country Name"].tolist()
population=data_df["Population"].tolist()
bar=(
Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
.add_xaxis(country)
.add_yaxis("人口",population)
.reversal_axis()
.set_global_opts(
title_opts=opts.TitleOpts(title=f"{year}年世界人口排名",pos_left="center"),
legend_opts=opts.LegendOpts(is_show=False),
)
.set_series_opts(label_opts=opts.LabelOpts(position="right"))
)
timeline.add(bar,str(year))
#设置自动播放、循环切换
timeline.add_schema(is_auto_play=True,play_interval=600,is_loop_play=True)
timeline.render_notebook()
# timeline.render("基础版人口轮播.html")
排序关键知识点: 先降序取 Top20,再升序 +
reversal_axis(),人口最多的国家会固定在图表最上方,符合观看习惯。
版本 3:B 站高级美化完整版(最终成品代码)
增加JS 动态变色、圆角柱子、自定义时间轴样式、标签格式化,对标 B 站视频可视化风格:
python
# 初始化最终时间线画布
timeline_final = Timeline(init_opts=opts.InitOpts(
width="1600px",
height="850px",
theme=ThemeType.DARK,
bg_color="#080808" #极深黑B站背景
))
# JS代码:实现柱子循环随机配色
color_js = JsCode("""
function(params){
let c = ['#ff4757','#ffa502','#fffa65','#2ed573','#1e90ff','#3742fa','#a55eea','#48dbfb'];
return c[params.dataIndex % c.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=data_df["Country Name"].tolist()
population=data_df["Population"].tolist()
bar=(
Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK))
.add_xaxis(country)
.add_yaxis("人口",population,
#圆角、透明度、动态颜色
itemstyle_opts=opts.ItemStyleOpts(color=color_js,opacity=0.85,border_radius=7),
#标签格式化:数字+人
label_opts=opts.LabelOpts(position="right",formatter="{c}人",font_size=11)
)
.reversal_axis()
.set_global_opts(
title_opts=opts.TitleOpts(title=f"{year}年世界人口排名",pos_left="center"),
legend_opts=opts.LegendOpts(is_show=False),
)
)
timeline_final.add(bar,str(year))
#精细化配置时间轴样式(蓝色进度条、白色节点、加粗年份文字)
timeline_final.add_schema(
is_auto_play=True,
is_loop_play=True,
play_interval=600, #600ms切换一年
is_timeline_show=True,
pos_left="center",
width="95%",
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),
)
#导出最终HTML文件
timeline_final.render("B站同款人口动态排行.html")
timeline_final.render_notebook()
七、项目成果总结
✅ 数据层面:剔除全球汇总、地区、非主权地区脏数据,精准保留 195 个主权国家 1960–2024 人口数据; ✅ 交互层面:自动轮播、暂停播放、手动拖拽年份、悬浮查看人口全部实现; ✅ 视觉层面:深色 B 站暗黑风格、圆角渐变彩色柱子、精细化时间轴,对标 B 站数据视频; ✅ 落地成果:生成独立 HTML 文件,脱离 Python 环境,任意浏览器打开即可运行。
八、后续优化拓展方向
- 国旗优化:X 轴国家名称前嵌入各国国旗 Base64 图标,视觉效果更强;
- 多指标切换:增加下拉框,一键切换人口总数 / 人口增长率 / GDP 排行;
- 性能优化:百万级大数据提前预计算各年份 Top20 缓存,减少前端渲染压力;
- 导出视频:通过 selenium 自动截图 HTML 轮播,拼接生成 MP4 排行视频。
九、踩坑总结(避坑指南)
- HTML 空白:必须替换
CurrentConfig.ONLINE_HOST国内 CDN,否则 echarts 资源加载失败; - 排序颠倒:排行榜必须「降序取 TOP→升序 + 反转坐标轴」两步,否则排名倒置;
- 中文乱码:csv 读取指定
encoding="gbk",国内中文版数据集通用; - 空值报错:原始数据 2025 全为空,
dropna()提前剔除无效数据。
更多推荐

所有评论(0)