ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Django+PM2.5数据可视化:从环境监测到毕业设计实战

Django+PM2.5数据可视化:从环境监测到毕业设计实战 简介这套毕业设计项目围绕城市PM2.5空气质量数据可视化展开采用Python与Django框架搭建覆盖数据采集、存储、分析与展示完整流程兼顾后端逻辑与前端页面适合环境数据分析、Web应用开发方向的课程设计或毕业设计参考。压缩包内含64个文件整体大小约12.38MB主要文件包括Python源码、CSV数据、SQL数据库脚本、HTML模板及配置文件并附带依赖说明与使用文档源码目录划分清晰便于直接导入开发工具运行。数据资料覆盖北京、上海、广州、成都、沈阳五座城市六年间的PM2.5监测记录已按时间序列、不同季度、各个月份等维度进行整理并梳理了PM2.5与温度、相对湿度、大气压、露点、风向等气象因素的关系此外还提供通用数据导入脚本便于扩展其他城市数据。后端使用Django配合MySQL数据库页面提供登录注册与可视化展示能力可展示趋势图和相关性分析结果支撑完整毕设演示和二次开发。当前已有406人学习下载适合需要快速搭建空气质量分析项目的同学参考。1. 毕业设计里的数据可视化这套DjangoPM2.5源码能拿来干什么每年到毕设季总有一批人被“选题”卡住要做管理系统吧太烂大街要搞算法吧数学底子又顶不住。如果你是这类情况又对Web开发有点基础那“PythonDjango城市PM2.5空气质量数据可视化分析”这类课题几乎是为答辩量身定做的——技术栈主流数据真实演示效果直观。这套源码的核心是一个完整的Django 2.x工程配MySQL数据库和北上广成沈五个城市六年的PM2.5数据前端用ECharts渲染把月度变化、一天中不同时段、季度趋势以及与温度、湿度、露点、气压、风向的关系全部画成图表。登录、注册、数据看板都是现成的直接跑起来就能演示。它适合两类人一是想把这个课题当底子做二开的毕设党二是刚开始学Django、想完整看一遍“请求→取数→渲染→出图”链路的入门者。2. 先看清家底zip包里的Django工程和数据文件是怎么分工的2.1 untitled 和 app01一个Django工程的标配分工打开zip包第一眼会看到一个叫untitled的目录和一个叫app01的目录这名字是Django创建项目时的默认命名说白了就是当时没改。untitled是整个Django工程的“总开关”里面是settings.py、urls.py、wsgi.py、asgi.py这一组标准配置app01才是真正写业务逻辑的地方模板文件、数据库模型、视图函数都在这。这个结构对应的是Django最标准的“项目-应用”模式项目负责环境配置和路由分发应用负责具体功能落地。从学习的角度讲这种默认结构反而比刻意改名的工程更容易对照教科书理解。models.py里定义了和数据库表对应的模型类views.py里写的是每个页面怎么取数据、怎么处理、怎么交给模板templates目录下的reg.html注册、login.html登录、index.html可视化看板构成了一条完整的用户流程。这套流程在答辩时很好讲不是零散地贴一堆图而是有一条“用户登录→进入看板→按维度查看分析结果”的主线。2.2 数据文件五城市六年PM2.5九张分析维度CSV数据是这套源码的底气。get_data目录下按城市和按分析维度各放了一套CSV五座城市分别是北京、上海、广州、成都、沈阳时间跨度是六年。原始汇总文件“北上广成沈五城市六年PM2.5数据汇总 1.csv”是所有数据的源头数据导入.py负责把这张汇总表拆开、清洗、再按维度导出成独立CSV最后通过通用脚本.py批量写入MySQL。从文件清单能看出设计者的分析思路分析维度对应文件能回答什么问题月度规律一年中各个月份变化.csv哪几个月污染最重是不是冬季供暖期日内规律一天中不同时段.csv早晚高峰时段PM2.5是不是明显升高年际趋势时间序列逐年数据.csv六年下来空气质量整体是变好还是变差季度对比不同季度逐年数据.csv季度之间的差异和逐年演变气象相关性pm2.5与温度/湿度/露点/气压/风向.csv哪个气象因子和PM2.5关系最密切这套文件结构本身就是一份现成的毕设论文提纲先做时间维度的整体趋势分析再做气象因子相关性分析最后落到“不同城市、不同季节的污染特征对比”。做毕业设计答辩PPT时把这几张图一摆研究思路就立住了。2.3 数据库脚本 db129.sql 与 models.py 的对应关系数据库文件名叫db129.sql是MySQL的Dump文件不是SQLite。这一点要特别提醒很多第一次接触毕设源码的同学默认Django用的是SQLite结果配完环境直接报数据库连接错误。这套工程在settings.py里已经写好了MySQL的数据库配置只要建好库导进SQL脚本就能用。数据库里的表结构对应的是Django ORM模型业务表主要围绕用户信息和PM2.5数据记录两类。用户表支撑登录注册功能PM2.5数据表则按时间、城市、浓度值、气象因子这些字段组织。如果你打开models.py发现字段和CSV列对不上别急着改代码——先导入SQL用python manage.py inspectdb反向生成模型文件一般就能对齐。这个技巧后面避坑章节会细说。3. 把系统跑起来从requirements.txt到浏览器看到图3.1 环境准备Python版本与依赖安装这套工程是标准的Python 3 Django项目建议直接用Python 3.8到3.10之间。在工程根目录能看到requirements.txt这就是依赖清单一行命令装完所有包cd 项目目录 pip install -r requirements.txt装完核心依赖后这里有一个毕设源码常见的大坑requirements.txt里往往只写了Django、PyMySQL这类主包没写ECharts。但前端图表完全是靠ECharts渲染的通常是通过static文件或CDN引用的跟Python依赖无关。如果你内网环境加载不了CDN就去下载ECharts的echarts.min.js放到app01/static目录下自己改模板里的引用路径。依赖装完验证一下python -m django --version能正常输出版本号说明Django装好了。此时别急着跑项目数据库还没准备好直接runserver大概率是在“数据库连接报错”里打转。3.2 创建数据库并导入db129.sql先打开MySQL创建一个空库再导入SQL文件。推荐在MySQL命令行里操作比用Navicat这类图形工具更直接还能看到编码相关的警告信息mysql -u root -p -e CREATE DATABASE db129 CHARACTER SET utf8mb4 mysql -u root -p db129 db129.sql第一条命令创建数据库第二条把db129.sql导入进去。这里有个关键细节建库时一定要显式指定utf8mb4否则默认编码在导入中文数据时会出现乱码或直接中断。导入完成后进MySQL验证一下表是否齐全mysql -u root -p db129 -e SHOW TABLES;看到表列表正常输出数据库这关就过了。如果你习惯用Navicat执行SQL文件时把“遇到错误继续执行”选项关掉方便第一时间发现卡在哪条语句上。3.3 修改settings.py里的三处配置数据库建好了接下来改Django配置。打开untitled/settings.py重点看三处。第一处是DATABASES把数据库名、账号、密码改成你自己的。第二处是ALLOWED_HOSTS如果以后要用IP地址访问这里要写星号或具体IP。第三处是TIME_ZONE建议改成Asia/Shanghai否则后面分析“一天中不同时段”时会发现时间整体偏移8个小时。# untitled/settings.py 中需要重点确认的配置 DATABASES { default: { ENGINE: django.db.backends.mysql, # 使用MySQL引擎 NAME: db129, # 数据库名建库时定的 USER: root, # 换成你的MySQL账号 PASSWORD: 你的密码, # 换成你的MySQL密码 HOST: 127.0.0.1, PORT: 3306, } } ALLOWED_HOSTS [*] # 开发阶段先放开方便用IP访问 TIME_ZONE Asia/Shanghai改完配置后要检查一个隐藏项目app01/和untitled/下有没有__init__.py文件里写pymysql.install_as_MySQLdb()。Django默认使用的MySQL驱动是MySQLdb但Python 3环境一般装的是PyMySQL如果不做这个兼容处理一启动就会报ModuleNotFoundError: No module named MySQLdb。发现没有的话在untitled/__init__.py里补上# untitled/__init__.py import pymysql pymysql.install_as_MySQLdb()3.4 迁移表结构并启动服务确认配置无误后先跑一次迁移。虽然SQL脚本里已经建好了业务表但Django自带的session、auth这些表还需要生成同时迁移也能检查模型代码和数据库之间有没有语法级错误python manage.py migrate这一步如果报Table already exists之类的冲突错误说明SQL导出时把Django自带的表也导进去了别慌去项目要求的数据库里把对应冲突表清空再迁移即可。迁移完成后启动开发服务器python manage.py runserver 0.0.0.0:8000浏览器访问http://127.0.0.1:8000会先跳到登录页。用源码里预置的账号登录或者先走一遍注册流程就能进入可视化看板。走到这一步系统就算真正跑通了——数据是从MySQL里读出来的图表是前端渲染的整个链路没有中断。4. 可视化是怎么实现的从views.py取数到ECharts出图4.1 后端取数views.py里的数据装配逻辑这套看板最核心的代码在app01/views.py里。它做的事情可以概括成一句话把SQL查询结果转成JSON格式再交给前端图表。用Django的ORM语法去查MySQL里的PM2.5数据表再按月份分组、按城市过滤、按均值聚合。典型的写法长这样# app01/views.py 中的核心取数逻辑以月度变化为例 import json from django.shortcuts import render from django.db.models import Avg from .models import Pm25Record # 数据库表对应的模型 def get_monthly_data(request): 查询各个月份的PM2.5均值返回JSON给前端图表 # 按月份字段分组取浓度平均值降序排列 results ( Pm25Record.objects .values(month) # 按月份分组 .annotate(avg_concAvg(pm25_value)) # 计算每组的平均浓度 .order_by(month) ) # 业务数据放到payload里统计信息放到meta里 payload { data: list(results), meta: {status: ok, count: results.count()} } return JsonResponse(payload)这段代码能跑通的前提是Pm25Record模型里的字段名和数据库表列对应得上。如果跑起来报字段不存在的错去app01/models.py里过一遍模型定义常见问题是从CSV导入数据时字段名带空格或括号导致模型和表结构错位。调试阶段可以直接在浏览器访问这个函数对应的URL比如http://127.0.0.1:8000/api/monthly/看JSON返回是否正常——能输出数据就说明后端没问题问题在前端。4.2 前端渲染templates/index.html里的ECharts装配打开templates/index.html能看到这个看板是怎么组织多张图表的。核心思路是页面加载完成后用JavaScript异步请求后端API拿到数据后再初始化ECharts实例。这套“前后端分离”的写法在答辩演示时很加分不是每次刷新页面都整体重新加载而是局部图表异步刷新交互性好也好扩展。// templates/index.html 中的ECharts初始化示例 // 第一步按id找到放图表的div容器要先在HTML里定义 var monthChart echarts.init(document.getElementById(monthChart)); // 第二步使用fetch向后端API请求数据 fetch(/api/monthly/) .then(res res.json()) // 因为后端返回的是JsonResponse .then(resp { // 第三步把JSON里的字段映射成ECharts需要的格式 var xData resp.data.map(item item.month); var yData resp.data.map(item item.avg_conc); // 第四步setOption设置图表的坐标轴和序列 monthChart.setOption({ xAxis: { type: category, data: xData }, yAxis: { type: value, name: PM2.5浓度(μg/m³) }, series: [{ type: bar, data: yData, name: 月均浓度 }] }); });如果图表加载不出来优先按这四个环节排查一是div容器有没有放在当前页面里二是echarts.init在DOM加载完成后才执行三是fetch的URL和views.py里配置的路由是否一致四是返回的JSON字段名和resp.data.map(...)里写的是否一样。从经验看第四种问题最多——Python字典里的键名和JavaScript里取的名称差一个字母图表就空在那。4.3 五个核心图表参数与页面控件的对应关系这套看板里的图表不是随便画的每张图都在回答一个具体的环境问题。做毕设答辩时把这张对应关系讲清楚比单纯演示系统更能体现你对课题的理解。图表位置对应问题推荐图表类型关键参数与观察重点月度变化全年污染有什么规律柱状图 折线图观察冬季月份是否明显抬升北方城市和南方城市差异时段变化一天中什么时段浓度最高折线图看早晚高峰时段有没有双峰结构季度逐年环境污染在改善还是恶化多系列折线图对比不同年份同季度看年际变化气象关系哪个气象因子影响最大散点图 趋势线看相关系数正负方向和散点聚集程度城市对比五城污染水平差异横向柱状图排序后直接看城市间差距4.4 数据导入脚本与CSV清洗逻辑复盘做好可视化后回来看get_data下的通用脚本.py和数据导入.py能理解这套数据的标准化过程。两个脚本解决的关键问题是原始CSV文件名和列名不一致有叫“相对湿度”的有叫“相对温度”的维度分散在不同文件里需要统一成数据库能写进去的格式。常见做法是先用pandas读多个CSV进行横向拼接统一列名和数据类型再按城市和时间字段纵向合并成一张宽表最后批量插入MySQL。这块逻辑对答辩来说是个很好的“工作量展示点”——不是简单地把现成数据放进数据库而是经历了清洗、合并、入库的完整流程。5. 避坑记录跑这套毕业设计源码经常翻车的五个地方5.1 报错ModuleNotFoundError: No module named MySQLdb现象启动服务或执行迁移时报缺少MySQLdb模块。原因Python 3环境默认用PyMySQL但Django的MySQL后端找的是MySQLdb项目里没有做兼容处理。解决在untitled/__init__.py里加两行代码——import pymysql、pymysql.install_as_MySQLdb()然后重启服务。这个坑可以说是Django MySQL组合的必踩项跑任何Django毕设源码都可能遇到。5.2 导入SQL后中文乱码现象数据库表里中文显示成乱码或者图表坐标轴中文变成问号。原因建库时没指定utf8mb4或导入时客户端连接用的编码和文件本身不一致。解决按下面的方式重建mysql -u root -p -e DROP DATABASE db129 mysql -u root -p -e CREATE DATABASE db129 CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci mysql -u root -p --default-character-setutf8mb4 db129 db129.sql重点在最后一条命令的--default-character-setutf8mb4它会强制客户端按这个编码读取SQL文件从源头上杜绝中文乱码。5.3 图表白屏或只显示灰块现象页面能打开但放图表的位置是空白或灰块。原因一是ECharts的JS文件没加载成功可能是模板里引用的CDN地址被屏蔽二是图表容器div设置了固定高度但值为0三是图表初始化时后端还没返回数据就开始setOption。解决先把ECharts的JS文件下载到本地放到static目录模板里改成相对路径引用再给放图表的div设置一个明确高度——height: 400px这种。调试时打开浏览器F12控制台看网络请求里有没有JS文件加载失败这是定位问题最快的路。5.4 数据对不上图表显示的值和CSV里不一致现象页面上的数据和原始CSV文件对不上比如最大值少了或均值变了。原因可能views.py里做了过滤条件比如只查了某个城市或某一年份也可能是数据库导入时数据截断尤其浓度字段原数据类型不够用。解决先定位这张图调用了哪个API直接在URL里看返回值再用SQL查询对比-- 用SQL验证数据库里的真实数据 SELECT MONTH(record_date) AS m, AVG(pm25) AS avg_conc FROM pm25_record WHERE city 北京 GROUP BY MONTH(record_date) ORDER BY m;前后端都能对上了再判断是代码问题还是数据问题别一上来就改代码。5.5 登录后跳转报CSRF token错误现象注册能成功但登录后一提交表单就报CSRF verification failed。原因Django默认开启了CSRF防护而模板表单里没有加{% csrf_token %}。这是最基础也是最常见的Django翻车点。解决在templates/login.html和reg.html的form标签里加上这个模板标签保存后刷新页面再提交。6. 拿到源码后怎么扩展把单机可视化升级成能写进简历的课题这套源码的默认形态是“登录后查看静态图表”数据是预先算好存进数据库的。如果你不想让它停留在“照着PPT演示”的程度有几个投入产出比很高的扩展方向。第一个方向是做成城市对比分析。源码数据里已经包含五个城市DB里也有气象相关字段但首页看板通常没有把城市对比做成独立模块。可以用横向柱状图或雷达图把五年均值、年度变化幅度、冬季均值这三个指标做一张对比图再配一两段文字说明城市间差异的原因——沈阳和成都是典型的内陆城市冬季静稳天气多PM2.5容易堆积广州靠海扩散条件好均值明显低于北方城市。这个扩展不需要动数据库只加一个视图函数加一张图但答辩时能体现横向对比分析能力。第二个方向是把图表改成“可筛选”。现在图表是固定维度的你可以加筛选控件让用户选城市、选年份、选月份图表跟着变。Django里实现这个逻辑不复杂前端把筛选条件通过GET参数传给views.py后端在查询时动态加过滤条件返回JSON后前端重新setOption。这种做法在简历上可以写“实现了交互式数据探索仪表盘”比“数据可视化”四个字有分量得多。实现时注意筛选参数要写默认值否则用户没选任何条件时接口会报错。第三个方向是重新启用数据更新脚本。原始设计里get_data下的脚本是一次性把CSV导入数据库但如果数据源能更新你可以写一个定时任务每三天拉取一次最新PM2.5数据清洗后增量更新数据库看板上的时间序列图就会实时延长。这一步会把系统从“毕业设计演示品”推向“可持续运行的数据系统”面试讲项目时完全不一样。我自己的习惯是拿到任何毕设源码第一遍先追求“跑通原样”把登录、注册、看板全部点一遍确认哪些功能是好的哪些是坏的第二遍才开始动手改代码做扩展。很多同学一上来就改数据库表结构结果代码和表对不上陷入漫长的排错。从这套 PM2.5 源码的实际结构看最有价值的扩展点全在“数据筛选”和“城市对比”上而不是重构登录逻辑。先把图表动态筛选做出来再考虑自动化更新一步步来简历上的项目描述会扎实很多。希望这些拆解和避坑记录对你有用也祝答辩顺利。本文还有配套的精品资源点击获取
返回列表