【Python 数据分析 + 可视化】基于 PandasPyecharts 制作 B 站风格世界人口动态排序轮播图(1960-2024)
一、项目前言 效果展示动态排序轮播图Bar Chart Race是当下短视频、数据分析平台非常热门的可视化形式B 站上大量人口、GDP、榜单类动态排名视频均采用该样式。本次项目完整复刻 B 站深色风格动态人口排名轮播图基于世界银行 1960-2024 年全球人口数据集使用Pandas完成数据清洗、宽表转长表结合pyecharts的Timeline时间轴组件 Bar柱状图实现自动轮播、动态换色、圆角柱状图、自定义时间轴样式等商业级可视化效果同时解决国内网络 Echarts 加载空白、数据格式错乱、无效汇总数据干扰等常见问题。最终实现效果亮点数据纯净剔除大洲、收入分组、非主权地区仅保留 195 个真实主权国家动态轮播1960-2024 年自动循环播放播放间隔 600ms支持手动切换年份、暂停 / 播放B 站风格美化深色背景、渐变动态配色、圆角柱子、白色文字标签视觉体验拉满交互完善鼠标悬浮查看详细人口数值时间轴节点、轴线自定义配色环境兼容配置国内 CDN解决 HTML 文件打开空白、加载失败问题。二、技术栈与环境准备1. 核心技术栈表格工具库作用Pandas数据读取、缺失值清洗、黑名单过滤、宽表转长表、数据类型转换pyecharts绘制横向柱状图、Timeline 时间轴轮播、图表样式全局配置JsCode嵌入原生 JS 代码实现柱子动态循环配色CurrentConfig配置国内 Echarts CDN适配国内网络环境2. 环境安装打开终端 / CMD执行以下命令安装依赖库bash运行# 安装数据处理库 可视化库 pip install pandas pyecharts -i https://pypi.tuna.tsinghua.edu.cn/simple镜像源加速避免国外源下载缓慢 / 超时推荐 Python 3.8 及以上版本。三、数据集介绍1. 数据源数据集名称世界人口数据-中文版(1960-2024).csv数据来源世界银行公开数据统计1960-2024 年全球各国总人口共 266 行、70 列。2. 数据结构探查固定属性列4 列Country Name国家名称、Country Code国家代码、Indicator Name指标名称、Indicator Code指标代码时间序列列66 列1960、1961……2024每一年单独为一列宽格式数据2025 年数据全部为空直接剔除脏数据说明原始数据包含大洲汇总亚洲、非洲、收入分组高收入国家、低收入国家、海外领地中国香港、阿鲁巴等这类非主权国家数据需要手动过滤。3. 原始数据样例表格Country NameCountry CodeIndicator NameIndicator Code19601961阿鲁巴ABW人口总数SP.POP.TOTL54922.055578.0NaNAFE人口总数SP.POP.TOTL130075728.0133534923.0阿富汗AFG人口总数SP.POP.TOTL9035043.09214083.0四、完整代码分步解析可直接复制运行整体流程导入库 配置 CDN → 读取数据 → 数据清洗空值 黑名单→ 宽表转长表 → 数据类型转换 → 初始化时间轴 → 动态配色 JS 配置 → 循环绘制每年柱状图 → 时间轴样式配置 → 渲染输出。步骤 1导入依赖库 修复国内 CDN必加国内网络直接运行 pyecharts 生成的 HTML 会出现图表空白核心原因是默认加载国外 Echarts CDN这里手动替换为国内稳定镜像。python运行# 1. 导入核心工具库 import pandas as pd from pyecharts.charts import Bar, Timeline # 柱状图、时间线轮播组件 from pyecharts import options as opts # 图表全局配置项 from pyecharts.globals import ThemeType, CurrentConfig # 内置主题、CDN配置 from pyecharts.commons.utils import JsCode # 嵌入JS实现动态配色 # 关键修复国内网络HTML空白问题指定国内Echarts CDN CurrentConfig.ONLINE_HOST https://cdn.jsdelivr.net/npm/echarts5.4.3/dist/步骤 2读取 CSV 数据集数据集包含中文指定编码gbk路径使用原始字符串r避免转义报错。python运行# 2. 读取本地人口数据集根据自己文件路径修改 df pd.read_csv(rD:\zyx\code\data\世界人口数据-中文版(1960-2024).csv, encodinggbk) # 可选查看数据前5行验证读取是否成功 print(原始数据预览) print(df.head()) # 查看数据集基本信息行列数、缺失值、数据类型 print(\n数据集基本信息) df.info()步骤 3核心数据清洗剔除脏数据这是本项目最关键的一步分为 3 层清洗删除国家名称空值、黑名单过滤非主权国家、筛选有效年份列。python运行# 3.1 筛选属性列 和 年份列自动识别纯数字年份列 attr_cols [Country Name, Country Code, Indicator Name, Indicator Code] # 固定属性列 year_cols [col for col in df.columns if col.isdigit()] # 自动提取1960-2024所有年份列 # 3.2 第一层清洗删除国家名称为空的行大洲汇总类数据 df df.dropna(subset[Country Name]) # 3.3 第二层清洗黑名单过滤剔除大洲、收入分组、海外领地等无效数据 black_list [ # 全球 各大洲汇总 世界, 北美, 东亚与太平洋地区, 欧洲与中亚地区, 拉丁美洲与加勒比海地区, 中东、北非、阿富汗与巴基斯坦, 撒哈拉以南非洲地区, 南亚, # 收入等级、世界银行分组 高收入国家, 中高等收入国家, 中低等收入国家, 低收入国家, 中等收入国家, 欧洲联盟, 经合组织成员, 重债穷国 (HIPC), # 非主权地区、海外领地 阿鲁巴, 美属萨摩亚, 百慕大, 中国香港特别行政区, 中国澳门特别行政区, 波多黎各, 格陵兰, 关岛, 科索沃, 法罗群岛 ] # 反向过滤保留不在黑名单内的数据 df df[~df[Country Name].isin(black_list)].reset_index(dropTrue) print(f\n清洗后剩余国家数量{df[Country Name].nunique()}) # 最终保留195个主权国家步骤 4宽表转长表数据重塑原始数据是宽格式一行 一个国家多年份多列无法直接循环绘图使用pd.melt()转为长格式一行 一个国家 一个年份 人口适配时序可视化场景。python运行# 4. 宽表转长表拆分年份列生成 Year(年份)、Population(人口) 新列 df_long pd.melt( df, id_varsattr_cols, # 保持不变的基础字段 value_varsyear_cols, # 需要拆分的所有年份列 var_nameYear, # 拆分后新列名年份 value_namePopulation # 拆分后新列名人口数值 ) # 预览转换后的数据 print(\n宽表转长表后数据预览) print(df_long.head())步骤 5数据类型转换 最终清洗统一字段类型删除 2025 年空数据、人口为空的无效行仅保留绘图所需 3 列。python运行# 5.1 仅保留绘图核心三列国家名称、年份、人口 df_clean df_long[[Country Name, Year, Population]] # 5.2 类型转换年份转为整数人口转为数值型 df_clean[Year] df_clean[Year].astype(int) df_clean[Population] pd.to_numeric(df_clean[Population], errorscoerce) # 5.3 删除缺失值剔除2025年全空数据、人口空值 df_clean df_clean.dropna() # 过滤人口大于0的有效数据 df_clean df_clean[df_clean[Population] 0] print(\n最终清洗完成数据预览) print(df_clean.head())步骤 6初始化时间轴 配置动态配色 JSTimeline时间轴容器统一管理所有年份的柱状图设置画布大小、B 站深色主题、纯黑背景JsCode编写 JS 代码实现排名不同、柱子颜色不同颜色循环切换提升动态视觉效果。python运行# 6.1 初始化时间轴轮播图B站深色风格自定义画布大小背景 timeline Timeline(init_optsopts.InitOpts( width1600px, # 图表整体宽度 height850px, # 图表整体高度 themeThemeType.DARK, # 内置深色主题B站同款 bg_color#080808 # 极深黑色背景 )) # 6.2 JS代码实现柱子动态循环配色 color_js JsCode( function(params){ // 自定义8种高饱和度配色红、橙、黄、绿、蓝、靛、紫、青 let colorList [#ff4757,#ffa502,#fffa65,#2ed573,#1e90ff,#3742fa,#a55eea,#48dbfb]; // 根据柱子索引循环取色实现排名变色 return colorList[params.dataIndex % colorList.length]; } )步骤 7循环绘制每年横向柱状图核心绘图逻辑遍历所有年份每年生成一张横向柱状图按人口降序取 TOP20排序逻辑适配横向柱状图展示规则。python运行# 7. 获取所有唯一年份列表1960-2024 year_list df_clean[Year].unique().tolist() # 遍历每一个年份生成对应柱状图并添加到时间轴 for year in year_list: # 筛选当前年份的全部数据 data_df df_clean[df_clean[Year] year] # 按人口降序排序取前20名国家 data_df data_df.sort_values(byPopulation, ascendingFalse).head(20) # 再次升序排序配合reversal_axis()实现人口越多越靠上符合阅读习惯 data_df data_df.sort_values(byPopulation, ascendingTrue) # 提取绘图数据国家名称、人口数量 country_list data_df[Country Name].tolist() population_list data_df[Population].tolist() # 绘制单年份横向柱状图 bar ( Bar(init_optsopts.InitOpts(themeThemeType.DARK)) .add_xaxis(country_list) # X轴国家名称 .add_yaxis( series_name人口, y_axispopulation_list, # 柱子样式动态配色、透明度、7px圆角 itemstyle_optsopts.ItemStyleOpts( colorcolor_js, opacity0.85, border_radius7 ), # 标签样式柱子右侧显示格式为「数字人」字号11 label_optsopts.LabelOpts( positionright, formatter{c}人, font_size11 ) ) .reversal_axis() # 关键柱状图横向展示 .set_global_opts( # 图表标题 title_optsopts.TitleOpts(titlef{year}年世界人口排名TOP20, pos_leftcenter), legend_optsopts.LegendOpts(is_showFalse), # 隐藏多余图例 ) ) # 将当前年份柱状图添加到时间轴中 timeline.add(bar, str(year))步骤 8时间轴样式 轮播规则配置自定义轮播参数、时间轴轴线、节点、文字样式打造完整交互体验。python运行# 8. 配置时间轴轮播规则 视觉样式 timeline.add_schema( is_auto_playTrue, # 开启自动播放 play_interval600, # 播放间隔600毫秒丝滑轮播 is_loop_playTrue, # 开启循环播放 # 时间轴文字样式白色、加粗、字号11 label_optsopts.LabelOpts(color#ffffff, font_size11, font_weightbold), # 时间轴轴线亮蓝色、线宽4px linestyle_optsopts.LineStyleOpts(color#00a1ff, width4), # 时间轴节点蓝色底色白色边框 itemstyle_optsopts.ItemStyleOpts( color#00a1ff, border_color#ffffff, border_width2 ) )步骤 9渲染输出两种方式适配不同环境python运行# 9. 渲染生成HTML文件所有Python环境通用打开即可查看 timeline.render(世界人口轮播排名图.html) print(\n图表已生成世界人口轮播排名图.html请打开文件查看效果) # 可选Jupyter Notebook/JupyterLab 专属渲染网页内直接展示 # timeline.render_notebook()五、常见报错 解决方案避坑指南结合实操中高频问题整理对应的解决办法1. 问题 1UnicodeDecodeError编码错误原因CSV 中文编码不匹配Pandas 默认utf-8无法读取中文 CSV。解决读取文件时指定编码encodinggbk如本文代码所示。2. 问题 2生成 HTML 文件打开空白无图表原因国内网络无法加载国外 Echarts CDN。解决添加 CDN 配置代码python运行from pyecharts.globals import CurrentConfig CurrentConfig.ONLINE_HOST https://cdn.jsdelivr.net/npm/echarts5.4.3/dist/3. 问题 3KeyError: xxx列名不存在原因表格为宽格式直接使用Year/Population列名报错。解决必须执行宽表转长表pd.melt()转换后再使用对应列名。4. 问题 4数据包含大量大洲 / 地区汇总排名异常原因原始数据集自带汇总脏数据。解决使用黑名单过滤剔除非主权国家数据本文已封装完整黑名单。5. 问题 5人口数字显示科学计数法解决在数据清洗后添加一行代码关闭科学计数法python运行pd.set_option(display.float_format, lambda x: %.0f % x)六、项目总结 拓展方向1. 项目总结本项目完整实现了从原始数据→数据清洗→数据重塑→动态可视化的全流程数据分析案例核心知识点总结Pandas 实战空值删除、黑名单过滤、melt()宽表转长表、数据类型转换是时序数据处理的经典用法pyecharts 进阶Timeline时间轴组件搭配Bar实现动态轮播JsCode嵌入 JS 实现自定义样式全局样式精细化配置工程化细节适配国内 CDN、路径转义、脏数据过滤代码可直接落地复用。2. 功能拓展进阶玩法增加数据标注给 Top3 国家添加特殊颜色标记突出头部国家切换图表类型将柱状图改为面积图、折线图实现人口趋势轮播数据筛选单独筛选亚洲 / 欧洲国家制作区域人口排名参数优化调整轮播速度、柱子尺寸、配色方案适配不同展示场景导出视频结合selenium 剪辑工具将 HTML 动态图转为短视频直接发布至短视频平台。七、完整项目源码整合版将以上所有代码整合复制即可直接运行仅需修改 CSV 文件路径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/echarts5.4.3/dist/ # 1. 读取数据修改为你的文件路径 df pd.read_csv(rD:\zyx\code\data\世界人口数据-中文版(1960-2024).csv, encodinggbk) # 2. 筛选列 attr_cols [Country Name, Country Code, Indicator Name, Indicator Code] year_cols [col for col in df.columns if col.isdigit()] # 3. 数据清洗 df df.dropna(subset[Country Name]) # 黑名单过滤 black_list [ 世界, 北美, 东亚与太平洋地区, 欧洲与中亚地区, 拉丁美洲与加勒比海地区, 中东、北非、阿富汗与巴基斯坦, 撒哈拉以南非洲地区, 南亚, 高收入国家, 中高等收入国家, 中低等收入国家, 低收入国家, 中等收入国家, 欧洲联盟, 经合组织成员, 重债穷国 (HIPC), 阿鲁巴, 美属萨摩亚, 百慕大, 中国香港特别行政区, 中国澳门特别行政区, 波多黎各, 格陵兰, 关岛, 科索沃, 法罗群岛 ] df df[~df[Country Name].isin(black_list)].reset_index(dropTrue) # 4. 宽表转长表 df_long pd.melt( df, id_varsattr_cols, value_varsyear_cols, var_nameYear, value_namePopulation ) # 5. 最终数据清洗类型转换 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], errorscoerce) df_clean df_clean.dropna() df_clean df_clean[df_clean[Population] 0] # 6. 初始化时间轴 timeline Timeline(init_optsopts.InitOpts( width1600px, height850px, themeThemeType.DARK, bg_color#080808 )) # 动态配色JS color_js JsCode( function(params){ let colorList [#ff4757,#ffa502,#fffa65,#2ed573,#1e90ff,#3742fa,#a55eea,#48dbfb]; return colorList[params.dataIndex % colorList.length]; } ) # 7. 循环绘图 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(byPopulation, ascendingFalse).head(20) data_df data_df.sort_values(byPopulation, ascendingTrue) country_list data_df[Country Name].tolist() population_list data_df[Population].tolist() bar ( Bar(init_optsopts.InitOpts(themeThemeType.DARK)) .add_xaxis(country_list) .add_yaxis( 人口, population_list, itemstyle_optsopts.ItemStyleOpts(colorcolor_js, opacity0.85, border_radius7), label_optsopts.LabelOpts(positionright, formatter{c}人, font_size11) ) .reversal_axis() .set_global_opts( title_optsopts.TitleOpts(titlef{year}年世界人口排名TOP20, pos_leftcenter), legend_optsopts.LegendOpts(is_showFalse) ) ) timeline.add(bar, str(year)) # 8. 时间轴配置 timeline.add_schema( is_auto_playTrue, play_interval600, is_loop_playTrue, label_optsopts.LabelOpts(color#ffffff, font_size11, font_weightbold), linestyle_optsopts.LineStyleOpts(color#00a1ff, width4), itemstyle_optsopts.ItemStyleOpts(color#00a1ff, border_color#ffffff, border_width2) ) # 9. 渲染输出 timeline.render(世界人口轮播排名图.html) print(图表生成完成)本文基于真实世界人口数据集完成动态轮播图可视化代码全开源、可直接复现。大家可以尝试修改配色、轮播速度、筛选区域数据打造属于自己的可视化作品如果运行代码遇到问题欢迎评论区留言交流