Python+pandas+pyecharts 复刻 B 站爆款世界人口动态排序轮播图(1960-2024)
一、项目前言 & 开发背景
Bar Chart Race(动态条形竞赛轮播图)是 B 站数据区爆款可视化形式,人口变迁排行更是常年热门选题。市面上大多使用在线 Flourish 工具一键生成,但不利于学习数据清洗 + Python 可视化底层逻辑。
本项目基于世界银行 1960-2024 全球人口 CSV 数据集,使用Pandas做全量数据清洗,Pyecharts+Timeline实现逐年自动轮播排行,最终落地深色 B 站商业级美化成品:支持暂停 / 播放、悬浮查看人口、年份手动切换、柱子动态换色、圆角柱状样式,完美复刻 B 站同款动态人口排行榜效果。
项目开发目标
- 数据纯净:剔除大洲、收入分组、港澳台及海外领地等非主权国家数据,最终筛选 195 个合法主权国家;
- 动态排行:每年按人口降序 TOP20 自动排序,配合反转坐标轴实现 “人口越多越靠上”;
- 全交互:时间轴可手动跳转年份、自动循环播放、悬浮 tooltip 展示详细人口;
- 美化落地:深色极黑背景、循环渐变配色、圆角柱子、白色标签,对标 B 站专业数据视频画质。
二、环境与依赖安装
2.1 所需技术栈
表格
| 工具库 | 作用 |
|---|---|
| pandas | 数据读取、筛选、清洗、宽表转长表重塑 |
| pyecharts | 柱状图 + Timeline 时间轮播核心可视化 |
| JsCode | 实现柱子动态循环配色(JS 内嵌) |
2.2 一键安装依赖
bash
运行
pip install pandas pyecharts
注意:国内网络 pyecharts 默认 CDN 容易白屏,项目中手动替换 jsdelivr CDN 地址解决空白问题。
三、数据集探查与原始数据说明
3.1 数据源说明
数据源:世界人口数据-中文版(1960-2024).csv,原始数据 266 行、70 列:
- 4 列属性字段:
Country Name(国家名)、Country Code(国家编码)、Indicator Name、Indicator Code; - 66 列年份字段:1960~2025,其中2025 年全为空 NaN,有效统计区间 1960-2024;
- 脏数据问题:原始包含全球汇总、各大洲、收入分级(高 / 低收入国家)、非主权领地(中国香港、阿鲁巴、关岛等),必须黑名单过滤。
3.2 数据加载代码(编码 GBK 适配中文)
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
# 关键:替换国内可用CDN,解决HTML打开空白
CurrentConfig.ONLINE_HOST = "https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/"
# 读取CSV,中文gbk编码
df = pd.read_csv('./data/世界人口数据-中文版(1960-2024).csv',encoding='gbk')
print(df.head())
print(df.info())
原始数据样例:部分行
Country Name为空(AFE/AFW 大洲汇总编码),这是后续要删除的无效数据。
四、核心:数据清洗全流程(项目重难点)
原始数据是宽格式(一行一国,年份横向平铺),无法直接做时序轮播,清洗分 4 大步骤:空值删除→黑名单过滤→宽表转长表→数据类型规整,最终精简为国家-年份-人口三列标准长数据。
4.1 步骤 1:删除国家名为空的汇总行
python
运行
# 删除Country Name为空的大洲汇总数据
df = df.dropna(subset=['Country Name'])
4.2 步骤 2:黑名单剔除非主权数据(核心过滤)
自定义黑名单,一次性剔除:全球 / 大洲汇总、收入等级分类、非主权地区 / 海外领地,最终保留 195 个主权国家:
python
运行
# 黑名单:汇总区、收入分类、非主权领地全过滤
black_list = [
# 全球&各大洲汇总
"世界","北美","东亚与太平洋地区","欧洲与中亚地区","拉丁美洲与加勒比海地区","撒哈拉以南非洲地区","南亚","欧洲联盟",
# 收入等级
"高收入国家","低收入国家","中等收入国家","中高等收入国家","中低等收入国家",
# 非主权领地/特别行政区
"阿鲁巴","中国香港特别行政区","中国澳门特别行政区","关岛","波多黎各","格陵兰","法罗群岛"
]
# 反向筛选,不在黑名单的数据保留
df = df[~df["Country Name"].isin(black_list)].reset_index(drop=True)
print("过滤后主权国家数量:",df["Country Name"].nunique()) # 输出195
4.3 步骤 3:宽表转长表(melt 重塑,时序必备)
原始年份横向铺开,使用pd.melt拆分出Year、Population字段,由宽→长:
python
运行
# 筛选年份列(列名全为数字)、属性列
year_cols = [i for i in df.columns if i.isdigit()]
attr_cols = ['Country Name','Country Code','Indicator Name','Indicator Code']
# 宽转长
df_long = pd.melt(
df,
id_vars=attr_cols,
value_vars=year_cols,
var_name="Year",
value_name="Population"
)
4.4 步骤 4:数据类型转换 + 空值剔除
python
运行
# 只保留绘图需要三列
df_clean = df_long[["Country Name","Year","Population"]].copy()
# 年份转int、人口转数值
df_clean["Year"] = df_clean["Year"].astype(int)
df_clean["Population"] = pd.to_numeric(df_clean["Population"])
# 删除空值(2025无效数据被清理)
df_clean.dropna(inplace=True)
# 最终干净数据
print(df_clean.head())
解决
SettingWithCopyWarning:使用.copy()生成新 DataFrame 规避副本告警。
五、可视化分步实现:从单图测试→基础轮播→B 站美化完整版
5.1 阶段 1:单年份静态柱状测试(以 1990 年 TOP20 为例)
先验证单年绘图逻辑,横向柱状 + 深色主题,标签放柱子右侧:
python
运行
# 筛选1990年数据,人口降序取TOP20
test_df = df_clean[df_clean["Year"]==1990].sort_values("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() # 反转XY→横向柱状
.set_global_opts(title_opts=opts.TitleOpts(title="1990年世界人口TOP20"))
.set_series_opts(label_opts=opts.LabelOpts(position="right"))
)
bar_test.render("1990单年测试.html")
5.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,先降序取前20、再升序排列(反转后大数在上)
data_year = df_clean[df_clean["Year"]==year].sort_values("Population",ascending=False).head(20)
data_year = data_year.sort_values("Population",ascending=True)
bar = (
Bar()
.add_xaxis(data_year["Country Name"].tolist())
.add_yaxis("人口",data_year["Population"].tolist())
.reversal_axis()
.set_global_opts(title_opts=opts.TitleOpts(title=f"{year}年全球人口TOP20排行"),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")
关键排序逻辑:先降序取 TOP20→再升序,配合
reversal_axis()实现人口越多、图表位置越靠上,符合观看习惯。
5.3 阶段 3:B 站深色商业美化完整版(最终成品代码)
实现动态循环配色、圆角柱子、极黑背景、蓝色高亮时间轴、自定义标签格式,对标 B 站可视化风格:
python
运行
# JS定义多色数组,柱子循环变色
color_js = JsCode("""
function(params){
let c = ['#ff4757','#ffa502','#fffa65','#2ed573','#1e90ff','#3742fa','#a55eea'];
return c[params.dataIndex%c.length];
}
""")
# 初始化时间线,深色黑底
timeline = Timeline(init_opts=opts.InitOpts(width="1600px",height="850px",theme=ThemeType.DARK,bg_color="#080808"))
year_list = df_clean["Year"].unique().tolist()
for year in year_list:
data_year = df_clean[df_clean["Year"]==year].sort_values("Population",ascending=False).head(20).sort_values("Population",ascending=True)
bar = (
Bar()
.add_xaxis(data_year["Country Name"].tolist())
.add_yaxis(
"人口",data_year["Population"].tolist(),
itemstyle_opts=opts.ItemStyleOpts(color=color_js,opacity=0.85,border_radius=7) # 圆角+透明度+动态色
)
.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",formatter="{c}人",font_size=11,color="#ffffff"))
)
timeline.add(bar,str(year))
# 美化时间轴:蓝线+白边节点+白色加粗年份文字
timeline.add_schema(
is_auto_play=True,play_interval=600,is_loop_play=True,
label_opts=opts.LabelOpts(color="#fff",font_size=11,font_weight="bold"),
linestyle_opts=opts.LineStyleOpts(color="#00a1ff",width=4),
itemstyle_opts=opts.ItemStyleOpts(color="#00a1ff",border_color="#ffffff")
)
# 生成最终成品HTML
timeline.render("B站风格_世界人口动态排行.html")
五、项目成果 & 数据洞察
- 产出文件:
B站风格_世界人口动态排行.html,直接浏览器打开即可交互,无需额外环境; - 历史人口变化看点
- 1960 年:中、印、美稳居前三,印尼、俄罗斯紧随其后,欧美老牌强国人口体量领先;
- 2000 年后:尼日利亚、巴基斯坦、孟加拉国人口增速爆发,逐步挤进全球 TOP10;
- 近 10 年:印度人口持续高速增长,逐步赶超中国成为全球人口第一大国;
- 技术收获:熟练掌握 pandas 宽长表转换、黑名单数据过滤、pyecharts Timeline 动态图表、JS 内嵌动态配色方案。
六、常见踩坑总结(避坑指南)
- HTML 打开空白:必须手动替换
CurrentConfig.ONLINE_HOST为 jsdelivr 国内 CDN,默认国外 CDN 国内加载失败; - 中文乱码:读取 csv 指定
encoding="gbk"(中文版数据源通用编码); - 排序颠倒:牢记
降序取TOP20→升序+reversal_axis三步组合,否则排行上下颠倒; - SettingWithCopy 警告:数据切片后修改字段,用
.copy()新建 DataFrame。
更多推荐
所有评论(0)