Python+pyecharts 制作 B 站同款世界人口动态排序柱状轮播图(1960-2024 完整版)
前言
经常在 B 站刷到各国人口、GDP 动态排名 Bar Chart Race 动图,本文手把手使用Pandas+pyecharts实现1960~2024 全球各国人口动态轮播排行榜,完整包含数据清洗、黑名单剔除汇总数据、深色 B 站美化风格、自动轮播、悬浮提示、圆角渐变柱状、动态配色,最终生成可直接浏览器打开的 HTML 交互式图表,课程设计、数据分析毕设均可直接复用。
技术栈:Python3 + Pandas + Pyecharts5.x 数据源:世界银行人口 CSV 数据集(1960-2024 各国总人口)
一、项目整体思路
- 数据读取:读取中文版人口 csv 原始数据,原始为宽表格式(国家一行,年份多列)
- 数据清洗
- 剔除国家名称为空的大洲汇总行
- 自定义黑名单,过滤全球、各大洲、收入分组、海外属地 / 非主权地区,仅保留 195 个主权国家
- 宽表转长表(melt),适配时序绘图格式
- 剔除空值、规范年份与人口数据类型
- 单图测试:单年份横向柱状图调试,反转坐标轴实现从上到下人口降序
- Timeline 时间轴实现逐年轮播,自动播放 + 循环切换年份
- 深度美化:深色黑底、动态随机配色、圆角柱状、自定义标签格式、时间轴样式优化,复刻 B 站可视化风格
二、完整代码实现
1. 环境安装
bash
运行
pip install pandas pyecharts2. 完整源码
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 # 修复国内echarts CDN,解决html空白不显示图表 CurrentConfig.ONLINE_HOST = "https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/" # ==========1.读取原始数据========== df = pd.read_csv('世界人口数据-中文版(1960-2024).csv', encoding="gbk") # 筛选年份列(列名全为数字)、属性列 year_cols = [i for i in df.columns if i.isdigit()] attr_cols = ['Country Name','Country Code','Indicator Name','Indicator Code'] # ==========2.数据清洗:剔除汇总、非主权国家数据========== # 第一步:删除国家名称为空的汇总行 df = df.dropna(subset=['Country Name']) # 黑名单:大洲、收入分组、海外领地、非主权区域 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()) # ==========3.宽表转长表========== df_long = pd.melt( df, id_vars=attr_cols, value_vars=year_cols, var_name="Year", value_name="Population" ) # 只保留绘图需要三列 df_clean = df_long[['Country Name','Year','Population']].copy() # 数据类型转换 df_clean["Year"] = df_clean["Year"].astype(float) df_clean["Population"] = pd.to_numeric(df_clean["Population"]) # 剔除空值(2025年全空数据) df_clean.dropna(inplace=True) # ==========4.定义柱子动态配色JS代码========== color_js = JsCode(""" function(params){ let c = ['#ff4757','#ffa502','#fffa65','#2ed573','#1e90ff','#3742fa','#a55eea','#48dbfb']; return c[params.dataIndex % c.length]; } """) # ==========5.初始化时间轴,B站深色黑底风格========== timeline_final = 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: # 筛选当年数据、取人口前20 data_df = df_clean[df_clean["Year"] == year] data_df = data_df.sort_values("Population", ascending=False).head(20) # 升序排序:配合反转坐标轴,人口最大在图表最上方 data_df = data_df.sort_values("Population", ascending=True) country = data_df["Country Name"].tolist() pop = data_df["Population"].tolist() # 构建横向柱状图 bar = ( Bar(init_opts=opts.InitOpts(theme=ThemeType.DARK)) .add_xaxis(country) .add_yaxis( "人口", pop, 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="#fff") ) .reversal_axis() #坐标轴反转,横向柱状 .set_global_opts( title_opts=opts.TitleOpts(title=f"{int(year)}年全球各国人口TOP20排名", pos_left="center", title_textstyle_opts=opts.TextStyleOpts(color='white')), legend_opts=opts.LegendOpts(is_show=False), tooltip_opts=opts.TooltipOpts(formatter="{b}<br>人口:{c:,}人") ) ) timeline_final.add(bar, str(int(year))) # ==========6.配置时间轴播放参数========== timeline_final.add_schema( is_auto_play=True, is_loop_play=True, play_interval=600, #切换速度600ms 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") print("图表生成完成!打开【B站同款人口动态排行.html】即可查看")三、关键步骤讲解
3.1 数据清洗核心:黑名单过滤
原始数据包含世界、各大洲、收入等级汇总数据,直接绘图数据错乱。通过手动构建黑名单列表,使用isin()反向剔除,最终保留195 个合法主权国家,是项目最关键步骤。
3.2 宽表转长表 melt
原始数据:一行一个国家,1960~2024 每一年单独一列(宽数据) 经过pd.melt转化为:国家 - 年份 - 人口三列标准长数据,方便按年份分组筛选。
3.3 排序 + 坐标轴反转逻辑
python
运行
#先降序取前20 → 再升序排列 data_df.sort_values("Population",asc=False).head(20).sort_values("Population",asc=True) #配合 reversal_axis()升序数据 + 坐标轴反转,实现人口越多,图表位置越靠上,符合排行榜阅读习惯。
3.4 动态柱子配色
借助JsCode编写前端 JS,根据柱子索引循环取用 8 种高饱和配色,实现每个国家每年柱子颜色固定、不同排名颜色区分,B 站图表标配效果。
四、成品功能亮点
- 自动轮播:600ms 自动切换年份、循环播放,暂停 / 播放按钮手动控制
- 交互悬浮:鼠标悬浮柱子,显示国家 + 格式化人口数值(千分位)
- UI 美化:纯黑背景、圆角柱状、蓝色高亮时间轴、白色标签字体,B 站同款深色可视化
- 数据严谨:剔除全部汇总 / 地区数据,仅主权国家参与排名
五、效果拓展优化方向
- 国旗展示:x 轴国家名称前拼接国旗 base64 图片,进一步提升视觉效果
- 多指标切换:扩展 GDP、出生率数据,下拉框切换不同指标动态排行
- 性能优化:提前预存每年 TOP20 数据,减少循环排序耗时
- 导出 GIF:借助 selenium 截取 HTML 动态画面,一键生成动图
六、项目总结
本项目完整走完原始数据→数据清洗→结构化处理→可视化美化数据分析全链路,是 Pandas+Pyecharts 练手优质项目,适合 Python 数据分析初学者、课程设计、毕业设计直接套用。代码注释齐全,替换对应 csv 数据源即可快速改成 GDP、进出口数据动态排行榜。
