news 2026/9/23 11:21:50

Python疫情数据可视化项目:从CSV到HTML的完整分析链路

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python疫情数据可视化项目:从CSV到HTML的完整分析链路

简介:这套基于Python的中美疫情数据可视化分析与展示源码,面向需要快速上手数据分析与可视化项目的学习者、竞赛备赛者以及对疫情趋势感兴趣的研究者,完整展示了从读取Excel/CSV数据、用Python进行数据处理与预测,到生成HTML交互页面的全链路过程。压缩包共19个文件,核心包括6个Python脚本、7个HTML页面、4个Excel数据源以及CSV与txt说明文件,整体仅145KB,结构清晰且便于按模块研读。脚本覆盖国内分省疫情分析、中美疫情对比和未来14天新增趋势预测等典型场景;HTML页面则呈现全球/国内疫情总览、中美对比与预测结果,读者可直接运行源码、复现图表,并在此基础上替换数据或调整算法开展二次开发。已有296人学习,适合想通过完整项目案例提升Python数据分析和可视化能力的人群。

1. 疫情数据可视化项目:20个文件把Python分析和HTML展示串成了一条线

假设你手上有一份疫情CSV,不光想画折线图,还要输出一份带预测、可以传给别人的网页报告,这时候单靠Excel透视表是撑不住的。这个基于Python的中美疫情数据可视化项目就是一个完整的源码包:6个Python脚本负责数据清洗、分析和预测,7个HTML页面负责展示,中间用CSV和Excel文件衔接。它解决了“数据从哪来、怎么算、怎么展示”三个问题,输出的每一个HTML都能单独用浏览器打开,也适合拿去跟同伴讲解数据趋势。适合正在学Python数据分析、看完教程想动手做一个完整项目的人,也适合手里已有数据、想快速跑通可视化链路并做二次开发的人。下面我从文件结构开始,逐个把脚本逻辑和踩坑点拆开讲。

2. 项目全景:20个文件的分工与数据从CSV到Excel的流转

2.1 四类文件的分工:Python脚本是发动机,HTML是仪表盘

这20个文件乍一看很杂,但归类后只有四类,各管一段。先把文件清单捋出来,后续脚本分析才不会迷路。

类别文件职责
原始数据history.csv全球疫情历史序列,包含日期、国家/地区、累计确诊等字段
中间数据China.xlsx、America.xlsx、China_province.xlsx、world.xlsx按国家或省份拆好的结构化数据
Python脚本World.py、China——province.py、Compare.py、China_xz_predict.py、America_xz_predict.py、pr.py读取、清洗、聚合、对比、预测、输出HTML
展示页面index.html、全球疫情情况.html、国内疫情情况.html、中美疫情对比.html、中国未来14天新增预测.html、美国未来14天新增预测.html、疫情预测分析.html可视化终端,直接供阅读
辅助文件readme.txt、upload.zip使用说明和打包备份

Python脚本是发动机,负责从CSV和Excel读入数据、算累计或新增指标、再用模型预测未来14天;HTML是仪表盘,所有分析结果最终都落到独立的网页文件里。这个项目最值得学习的点在于:脚本跑完不是打印几行数字就结束,而是生成一份能发给别人的静态报告,这也是企业级数据可视化项目的常规思路。

2.2 清洗路径:pr.py把history.csv拆成China.xlsx和America.xlsx

history.csv是原始数据源,里面通常包含全球所有国家和地区的每日记录。如果直接拿这个文件去画中美对比图,每次都要做筛选,既慢又容易出错。所以第一步应该把原始CSV处理成每个项目脚本都能直接读的中间Excel文件,这个任务正好由pr.py承担。

# pr.py 数据清洗核心逻辑 import pandas as pd df = pd.read_csv('history.csv') # 先摸清列名,防止大小写或空格不一致 print(df.columns.tolist()) # 统一列名:去掉首尾空格,统一英文小写 df.columns = [col.strip().lower() for col in df.columns] # 如果CSV里按省/州拆行,需要先按国家聚合 # 假设关键列是 country、date、confirmed daily = (df.groupby(['date', 'country'], as_index=False)['confirmed'] .sum() .sort_values('date'))

这里有两个关键操作:columns.tolist()把原CSV的字段名打出来看一眼,这一步能节约后面大量的排查时间;groupby(['date', 'country'])把同一国家多个省份的记录合并成国家维度,as_index=False保证分组后country仍然是列而不是索引。聚合完之后,再用条件筛选拆出中美两国存成单独文件。

# 接上面,拆出中美数据并落地 cn = daily[daily['country'] == 'China'].copy() us = daily[daily['country'] == 'US'].copy() # 写回Excel,显式指定openpyxl引擎 cn.to_excel('China.xlsx', index=False, engine='openpyxl') us.to_excel('America.xlsx', index=False, engine='openpyxl') # 整体数据也存一份,给World.py用 daily.to_excel('world.xlsx', index=False, engine='openpyxl')

注意to_excel里我用engine='openpyxl'显式指定了写xlsx文件的引擎。pandas默认行为在不同版本里不一致,不写这个参数,有时会静默降级到旧版xlwt引擎,生成的文件实际上是损坏的。等你再read_excel读回来,报错信息会指向文件格式,根本猜不到是写的时候出了问题。

China_province.xlsx是省级粒度数据,由China——province.py读取。这个脚本的文件名里有个中文全角破折号“——”,这是和Windows、Linux文件系统都能兼容的命名,但在代码里引用路径时极容易打错,后续第5章我会专门讲这个坑。

2.3 index.html的入口作用:页面之间的导航关系

index.html在整个项目里是目录页,作用是把其他六个HTML页面串起来。它的内容不复杂,核心就是一组超链接。

<!-- index.html 目录导航示意 --> <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>新冠数据可视化分析</title> </head> <body> <h1>新冠疫情数据可视化分析</h1> <ul> <li><a href="全球疫情情况.html">全球疫情情况</a></li> <li><a href="国内疫情情况.html">国内疫情情况</a></li> <li><a href="中美疫情对比.html">中美疫情对比</a></li> <li><a href="中国未来14天新增预测.html">中国未来14天新增预测</a></li> <li><a href="美国未来14天新增预测.html">美国未来14天新增预测</a></li> <li><a href="疫情预测分析.html">疫情预测分析</a></li> </ul> </body> </html>

这些页面文件名都是中文,你本地双击index.html用file://协议打开,部分浏览器可能会因为编码差异导致链接找不到文件。我的习惯是把整个项目文件夹丢进VS Code,然后用Live Server插件起一个本地服务再访问,或者用命令行python -m http.server 8080,这样中文路径问题基本不会出现。

3. 核心脚本拆解:14天预测与中美对比的算法逻辑

3.1 China_xz_predict.py:线性回归预测未来14天新增

预测脚本是这堆文件里技术含量最高的。疫情数据本质是时间序列,但这里用的并不是LSTM这类复杂模型,而是线性回归——把日期转换成连续整数天数,再用“天数”去拟合“新增确诊”。为什么选这么简单的模型?因为疫情数据波动大、样本量有限,复杂模型在短序列上很容易过拟合,线性回归反而稳定、可解释,出图也自然。

# China_xz_predict.py 核心推理逻辑 import pandas as pd import numpy as np from sklearn.linear_model import LinearRegression # 读取已清洗好的中国数据 df = pd.read_excel('China.xlsx', engine='openpyxl') df['date'] = pd.to_datetime(df['date']) df = df.sort_values('date') # 日期转成距起始日的整数天数,作为回归特征 df['day'] = (df['date'] - df['date'].min()).dt.days X = df['day'].values.reshape(-1, 1) y = df['new_cases'].values # 训练线性回归模型 model = LinearRegression() model.fit(X, y) # 构造未来14天的天数序列 last_day = df['day'].max() future_days = np.arange(last_day + 1, last_day + 15).reshape(-1, 1) pred = model.predict(future_days) # 生成对应日期,带格式输出 future_dates = pd.date_range( start=df['date'].max() + pd.Timedelta(days=1), periods=14 ) result = pd.DataFrame({ 'date': future_dates.strftime('%Y-%m-%d'), 'pred_new_cases': np.round(pred, 1) }) print(result)

这里有两个参数要特别说明。第一是X.reshape(-1, 1),sklearn的线性回归要求特征矩阵是二维的,哪怕只有一列特征也必须显式变成行向量,很多人第一次跑就挂在shape不匹配上。第二是periods=14,这个数字直接控制预测窗口长度,改成7就是未来一周预测,改成30就是月度预测。

3.2 America_xz_predict.py与数据平滑处理

America_xz_predict.py的结构和中国版本几乎一致,只是读取America.xlsx、输出美国未来14天新增预测.html。但实际跑的时候,美国数据有一个典型问题:单日新增波动非常大,周末数据偏低、周一反弹是常态。直接用原始序列喂给线性回归,拟合出来的直线会被噪声带偏。

常见做法是在回归之前先做一次平滑,用7天移动平均把周末效应抹掉。

# America_xz_predict.py 数据平滑逻辑 df = pd.read_excel('America.xlsx', engine='openpyxl') df['date'] = pd.to_datetime(df['date']) df = df.sort_values('date') # 7天移动平均,min_periods=1保证前6天不出现NaN df['new_cases_smooth'] = ( df['new_cases'] .rolling(window=7, min_periods=1) .mean() ) df['day'] = (df['date'] - df['date'].min()).dt.days X = df['day'].values.reshape(-1, 1) y = df['new_cases_smooth'].values # 后续回归流程与China版一致

rolling(window=7)是移动平均的窗口大小,min_periods=1表示窗口内最少有1个有效值就算平均,否则前6天会全部变成NaN,回归就废了。如果你跑出来的预测线前段是断的,先检查这里有没有写min_periods

3.3 Compare.py与pr.py:中美对比的指标选择

Compare.py做的事情是把China.xlsx和America.xlsx按日期合并,然后算对比指标。中美两国人口基数差了四倍多,直接拿累计确诊绝对值画双线图,美国的线会高高在上,视觉上完全看不出中国的增长趋势。所以对比脚本里一定要做归一化。

# Compare.py 对比指标计算 import pandas as pd cn = pd.read_excel('China.xlsx', engine='openpyxl') us = pd.read_excel('America.xlsx', engine='openpyxl') cn = cn[['date', 'confirmed']].rename(columns={'confirmed': 'cn_confirmed'}) us = us[['date', 'confirmed']].rename(columns={'confirmed': 'us_confirmed'}) # 内连接,只保留两边都有数据的日期 merged = pd.merge(cn, us, on='date', how='inner') # 归一化:每百万人口确诊数 CN_POP = 1400000000 US_POP = 331000000 merged['cn_per_million'] = merged['cn_confirmed'] * 1000000 / CN_POP merged['us_per_million'] = merged['us_confirmed'] * 1000000 / US_POP

how='inner'这个参数决定了合并策略。内连接只保留双方共有的日期,如果某天只有中国数据没有美国数据,那一行会被丢弃。相比外连接,内连接不会产生NaN,但代价是样本量可能减少。美国疫情数据公布节奏不稳定,用内连接是更稳的选择。人口常量我直接写死在脚本里,如果你要改成别的国家对比,记得同步替换这两个常量。

pr.py在项目里承担的是数据预处理职责,除了前面拆CSV的操作,它还会对日期格式做统一处理。原始CSV里日期可能有2020-1-52020/1/520200105三种格式混着,统一用pd.to_datetimeformat参数解析最省心。

4. 可视化输出:从DataFrame到ECharts的HTML渲染

4.1 全球、国内、中美三个维度页面怎么生成

7个HTML页面覆盖三个维度:全球、国内、中美对比。生成方式本质上都是同一个套路——脚本里先准备好数据,再拼HTML模板,最后渲染出图表。

World.py读取world.xlsx,按国家聚合算Top排行榜,输出到全球疫情情况.html;China——province.py读取China_province.xlsx,渲染国内省级分布,输出到国内疫情情况.html;Compare.py读两国数据,输出中美疫情对比.html。模板里用到的图表库是ECharts,这也是目前数据可视化项目里最主流的选型。

# 通用HTML模板渲染文件 def render_html(title, chart_div_id, option_json, output_file): html_content = f""" <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <title>{title}</title> <script src="./static/echarts.min.js"></script> </head> <body> <div id="{chart_div_id}" style="width: 900px; height: 600px;"></div> <script> var chart = echarts.init(document.getElementById('{chart_div_id}')); chart.setOption({option_json}); </script> </body> </html> """ with open(output_file, 'w', encoding='utf-8') as f: f.write(html_content) print(f"已生成 {output_file}")

这个模板的核心是把ECharts的option配置以JSON字符串形式嵌入script标签。chart.setOption是ECharts的入口方法,所有配置都放在这个对象里。注意script的src我写的是./static/echarts.min.js,意味着你需要在项目下建一个static目录并放一份ECharts库文件,这样才能离线打开页面。

4.2 预测结果在HTML里如何区分实际值与预测值

中国未来14天新增预测.html和美国未来14天新增预测.html这两个页面,图表上同时有两条线:历史实际值和未来预测值。前端要区分它们,靠的不只是颜色,而是数据里带一个标记字段。

# 构造带标记的历史+预测拼接数据 import pandas as pd df = pd.read_excel('China.xlsx', engine='openpyxl') # 取最近30天实际新增 history = df.tail(30)[['date', 'new_cases']].copy() history.rename(columns={'new_cases': 'value'}, inplace=True) history['is_predict'] = False # 预测结果构造为DataFrame future = pd.DataFrame({ 'date': future_dates, 'value': pred, 'is_predict': True }) # 拼接并转JSON combined = pd.concat([history, future], ignore_index=True) data_for_chart = { 'dates': combined['date'].astype(str).tolist(), 'values': combined['value'].round(0).tolist(), 'isPredict': combined['is_predict'].tolist() }

is_predict这个布尔字段是关键,前端拿到它之后,可以给预测线段设置成虚线、浅色,和实际值形成视觉区分。pd.concat按行拼接两个结构相同的DataFrame,ignore_index=True保证行号重新从0开始,否则图表数据会被旧索引打乱。

4.3 JSON注入:ensure_ascii和编码相关的坑

按上面的方式把data_for_chart变成JSON字符串时,有一个容易被忽视的细节:Python的json.dumps默认会把中文转成\uXXXX转义序列,HTML源码里看起来全是反斜杠,虽然也能运行,但可读性很差,排查问题的时候非常痛苦。

import json # ensure_ascii=False让中文原样输出,HTML里直接可读 option_json = json.dumps(data_for_chart, ensure_ascii=False)

这样生成的HTML里日期和中文标题都保留原始字符,浏览器解析毫无压力。另一个点是写HTML文件时open(output_file, 'w', encoding='utf-8')必须带上encoding参数,否则Windows默认的gbk编码会把中文字符写坏,页面打开就是一堆乱码。这两个编码问题我建议养成固定习惯,写文件永远指定utf-8。

5. 避坑指南:跑通这个项目最容易翻车的五个地方

5.1 现象:FileNotFoundError,文件明明就在脚本同目录

原因:China——province.py这个文件名里是中文全角破折号“——”,代码里如果引用的是半角“--”或直接复制路径时混入全角字符,Python会把文件路径当成另一个字符串去查找,自然找不到。

解决:进入项目目录执行lsdir命令,先确认文件实际名字,再复制粘贴进代码。更彻底的做法是改文件名为ASCII安全的China_province.py,然后全局替换所有引用。从那以后我接手的每个项目,文件名一律不用中文和全角符号。

5.2 现象:read_excel报错“Missing optional dependency 'openpyxl'”

原因:pandas读.xlsx文件需要安装openpyxl库,你的虚拟环境里只装了pandas,缺了底层依赖。另一个关联场景是写Excel时没指定engine,pandas偷偷用旧引擎生成损坏文件。

解决:在项目根目录执行pip install openpyxl,然后代码中统一写成pd.read_excel('China.xlsx', engine='openpyxl')to_excel(..., engine='openpyxl')。显式声明引擎虽然啰嗦,但避免了版本行为差异导致的各种玄学报错。

5.3 现象:HTML页面打开后图表空白,控制台报ECharts加载失败

原因:页面模板里script标签引用的是远程CDN路径,比如https://cdn.jsdelivr.net/npm/echarts,别忘了有些内网环境或者本机没有外网,加载就会超时失败,图表区域自然空白。

解决:把ECharts库下载后放到项目的static目录,script标签改成相对路径./static/echarts.min.js。用离线文件虽然会占用一点项目体积,但保证在任何网络环境下打开都秒出图。这也是从“自己机器能跑”到“交付到别人机器也能跑”的一道分水岭。

5.4 现象:预测曲线在某个点突然断崖式下跌或跳变

原因:原始CSV里有缺失日期,比如某一天中国数据没更新,groupby聚合之后那一整天就消失了。回归模型的X是连续整数天数,y却是跳跃的,中间空缺一天就会让拟合线产生巨大偏移。

解决:读取后做一次日期补全,把缺失日期自动填充为零值。

df['date'] = pd.to_datetime(df['date']) df = df.set_index('date').resample('D').sum().reset_index() # resample('D')按天重采样,缺失日期的所有列自动补0

resample('D')是pandas时间重采样的核心方法,sum()决定缺失期怎么聚合。这个操作放在读文件和构造day列之间,预测结果会平滑很多。

5.5 现象:脚本跑完了、HTML文件也更新了,浏览器打开还是旧数据

原因:浏览器缓存了上一次的HTML文件,服务器返回的是缓存内容,你的新文件根本没被加载。

解决:开发阶段在浏览器按Ctrl+F5强制刷新,或者在HTML的head区域加入一行禁用缓存的meta标签,发布时再删掉。

<meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache">

这组标签只对浏览器本地缓存生效,不会影响服务器端配置,适合开发调试阶段快速验证效果。

6. 把预测脚本改成常用工具:数据源替换与图表演进技巧

6.1 替换成实时数据源

项目里用的history.csv是静态文件,但实际使用中数据每天都会更新。改动最小的方法是用Python直接去公开接口拉数据,再落成本地CSV,替代原来的读文件逻辑。

# 从接口拉数并更新本地缓存 import requests import pandas as pd resp = requests.get('https://your-data-api.example.com/covid') data = resp.json() df = pd.DataFrame(data) df.to_csv('history.csv', index=False, encoding='utf-8') print(f"数据已更新,共 {len(df)} 行")

requests.get默认会阻塞直到响应返回,接口如果比较慢,建议加超时参数timeout=30,避免脚本长期卡住。拿到JSON之后转DataFrame这步是通用的,不管接口返回什么结构,先用normalizejson_normalize展平嵌套字段再落盘。

6.2 改图表类型的技巧

如果不想用折线图,想换成柱状图或者面积图,只需要改ECharts的option配置。ECharts的series类型字段type决定图表形态,从line改成bar即可。

// 图表配置中的series部分 series: [{ name: '中国新增', type: 'bar', // line改成bar就是柱状图 data: [120, 200, 150, 80, 70] }]

改图表类型时,颜色、坐标轴、图例这些配置都不用动,ECharts会自动适配。如果你要做大屏展示,series里再加一个smooth: true,折线会变成平滑曲线,视觉上专业很多。

6.3 用本地服务器固定访问方式

以前我总喜欢双击HTML文件直接看,后来发现文件协议下ECharts的字体加载和异步请求经常出问题,就改成固定起一个本地服务器。

# 在项目根目录起服务,端口8080 python -m http.server 8080

这个命令会把当前目录作为根目录开启HTTP服务,局域网内其他电脑可以访问你的IP加端口直接看到所有HTML页面,比U盘拷贝给同事方便得多。从那以后我每次交付可视化项目都会顺带在readme里写一句最简单的启动命令,希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/23 11:21:50

面试总挂?手写实现超弦算法的3种技术栈对比与避坑指南

面试总挂?手写实现超弦算法的3种技术栈对比与避坑指南 面试被问原理答不上来,那种尴尬你懂吗?面试官盯着你,你脑子里全是 import 和 return ,却连个像样的手写实现都掏不出来。别慌,今天咱不聊虚的,直接拆解“超弦”这个在特定物理计算或高阶模拟场景中常被拿来“压测”底层逻辑的伪命题(注:此处…

作者头像 李华
网站建设 2026/9/23 11:21:48

东软集团怎么样?图解原理拆解转岗避坑指南

东软集团怎么样?图解原理拆解转岗避坑指南 刚拿到东软集团的 Offer,或者准备转岗进去的朋友,最头疼的往往不是业务逻辑,而是开发环境配置。很多人卡在 node_modules 依赖冲突、内网 Maven 仓库拉包超时、或者老项目里的 Ant…

作者头像 李华
网站建设 2026/9/23 11:21:40

淘宝优惠券公众号选型 5个方案源码解析 避坑指南

淘宝优惠券公众号选型 5个方案源码解析 避坑指南 版本升级后 API 全变了,这是很多接手“淘宝优惠券公众号”项目的开发者最头疼的噩梦。上周刚跑通的逻辑,今天一重启就报 401 或参数错误,文档还是旧的,源码里全是硬编码的 token…

作者头像 李华
网站建设 2026/9/23 11:21:30

ps字体免费下载入门到精通

3步搞定PS字体下载卡壳问题 手写脚本实现自动配置 刚接手项目,想给设计稿换个高级字体,结果PS打开就卡半天。下载字体文件解压安装,重启软件还是显示“未找到字体”,系统属性里字体文件夹里明明有文件。这种配置环境就卡半天的情况,90%的新手都遇到过。别急着重装PS,问题往往出在权限注册和缓存冲突上。今…

作者头像 李华
网站建设 2026/9/23 11:21:24

2026最新卡农简谱钢琴版面试突击:别再被环境配置坑

2026最新卡农简谱钢琴版面试突击:别再被环境配置坑 配置环境就卡半天,是不是让你抓狂?明明照着教程敲代码,依赖装不上、版本冲突、端口占用,折腾三小时还没跑通一行代码。这种绝望感,在2026最新的技术栈里反而更严重了,因为框架迭代太快,文档滞后,旧教程全是坑。今天这篇《2026最新卡农简谱钢琴版》不…

作者头像 李华
网站建设 2026/9/23 11:21:02

3个核心模块搭建Imperva WAF实战项目,告别纸上谈兵

3个核心模块搭建Imperva WAF实战项目,告别纸上谈兵 看了一堆教程还是不会写项目?这是很多应届生和初级工程师的痛点。你背熟了WAF的原理,却在面试或实际工作中被问“怎么部署一个高防系统”时卡壳。今天不聊虚的,直接上手。我们要搭建一个基于Imperva理念的高可用Web应用防火墙实战项目。这不…

作者头像 李华