新闻详情

新闻详情

首页 / 资讯中心 / 详情

Python+pyecharts+Flask构建交互式数据可视化看板:结婚离婚数据分析实战

发布时间:2026/10/1 23:05:10来源:尧图网络
Python+pyecharts+Flask构建交互式数据可视化看板:结婚离婚数据分析实战
简介这是一套基于Python与pyecharts的交互式数据可视化期末大作业项目源码专为高校期末大作业或课程设计场景打造面向需要快速完成数据分析可视化任务的学生与初学者。压缩包共31个文件整体仅1.1MB包含HTML页面、PNG图表、XLSX原始数据、Python主程序及ipynb过程记录等目录结构清晰按模板、静态资源与数据处理模块分离便于定位与复用。已有268人学习该项目在功能完整度与界面美观度上均达到高分水准同时附带详细代码注释即使新手也能顺利部署运行。资源以结婚与离婚登记数据为分析对象覆盖数据清洗、图表生成与交互式页面展示全流程可直接替换数据完成个性化作图也可作为课程设计、期末答辩或简历项目的现成参考从下载到演示一气呵成。1. 基于Pythonpyecharts的结婚离婚数据分析期末大作业为什么选这个项目期末周拿到“Pythonpyecharts交互式数据可视化”题目最怕的不是写不出图表而是交上去一份静态图片、一堆复制来的报告答辩时没有任何可以演示的交互动作。这个项目用 Flask 做后端承载 pyecharts把结婚登记、离婚登记两份 Excel 数据变成可缩放、可悬停、可切换页面的网页看板——这才是“交互式”三个字的真正分量。它解决的是两类痛点一是数据分析有结论但不知道怎么在网页上呈现二是图表能画出来但没有任何交互事件翻开报告全是死图。项目适合课程设计、期末大作业直接复现也适合刚学完 Flask 基础、想找 pyecharts Flask 完整链路样例的新手。下面从目录结构开始一路拆到每个参数怎么调、坑在哪。2. 项目结构与数据准备解压后先分清哪些文件能跑、哪些是过程产物2.1 目录盘点源码包里的文件各是什么角色拿到压缩包第一件事不是立刻python app.py而是把文件分分类。这个项目解压后的顶层目录是Interactive_data_visualization_FinalProject-main里面既有源码、数据也有大量运行过程中生成的静态 HTML 文件混在一起容易看懵。路径文件类型角色说明app.pyPython 源码Flask 应用入口路由、数据读取、图表生成全在这一个文件里结婚登记(万对).xlsx / 离婚登记(万对).xlsxExcel 数据整个项目的可视化数据源两份时间序列表pyecharts过程.ipynbJupyter Notebook开发过程的中间产物每个图表的验证脚本都在这templates/index.html、home.htmlHTML 模板Flask 渲染用的页面模板一个是入口一个是图表容器static/home.css 等样式资源页面布局、颜色、导航样式a.html ~ e.html静态页面pyecharts 导出产物不开服务器也能直接双击看效果这里有一个容易误解的地方a.html、b.html 这些文件并不是 Flask 运行时生成的而是 Notebook 里调render()导出的快照相当于开发过程的“截图”。真正参与页面渲染的是 templates 目录下的 index.html 和 home.html。.idea、__pycache__、.gitattributes这类文件是 PyCharm 和 Git 的自动产物直接忽略即可。额外一个小习惯运行前看一眼__pycache__里的文件名比如发现app.cpython-37.pyc就能推断项目作者当时用的是 Python 3.7 环境。这个细节很有用——后面安装 pyecharts 版本时它决定了某些 API 是否兼容。2.2 Excel 预处理字段确认、类型转换与空值清理数据可视化项目翻车率最高的地方不是图表配置而是数据读到一半发现年份列变成浮点数、登记量列混进空值。先写一段探测代码把两张表的结构完整打印出来。import pandas as pd marriage_df pd.read_excel(结婚登记(万对).xlsx) divorce_df pd.read_excel(离婚登记(万对).xlsx) print(结婚数据 shape:, marriage_df.shape) print(列名:, marriage_df.columns.tolist()) print(marriage_df.head()) print(marriage_df.dtypes) print(空值统计:) print(marriage_df.isnull().sum()) print() print(离婚数据 shape:, divorce_df.shape) print(列名:, divorce_df.columns.tolist()) print(divorce_df.head()) print(divorce_df.dtypes) print(空值统计:) print(divorce_df.isnull().sum())这段代码没有做任何处理纯粹是探路。read_excel的文件名必须和资源包内完全一致包括中文全角括号否则直接FileNotFoundError。shape返回(行数, 列数)先看规模再决定后续怎么做columns.tolist()打出的列名是后面所有代码的依据。dtypes是最容易暴露问题的地方——公共统计类 Excel 里年份列经常被读成float64因为表尾可能混了一行说明文字或空行pandas 自动推断类型时就整体升级了。isnull().sum()能告诉你每个字段具体缺了几行。确认列名和空值情况后再做三层处理类型转换、数值清洗、转列表。# 以结婚数据为例离婚数据做同样的处理 marriage_df[年份] marriage_df[年份].astype(int) marriage_df[登记量] pd.to_numeric(marriage_df[登记量], errorscoerce) marriage_df marriage_df.dropna(subset[登记量]) # 按年份升序排一次序避免折线图来回折 marriage_df marriage_df.sort_values(年份) # 转成 pyecharts 需要的列表结构 years marriage_df[年份].astype(str).tolist() marriage_values marriage_df[登记量].tolist()参数说明astype(int)把浮点年份强制还原成整数否则 x 轴会出现2005.0这种刻度pd.to_numeric配errorscoerce是把非数字内容转成NaN比手动 replace 更稳健dropna(subset[登记量])则把清洗过程中产生的空行整行去掉。最后统一转list是因为 pyecharts 的add_xaxis和add_yaxis只接收 Python 列表直接塞 DataFrame 的 Series 对象会在渲染时报类型错误。如果要做结婚和离婚的同图对比建议在预处理阶段就左右合并成一张表后面所有图表都从这张合并表取值省得每个图表函数里都维护两份数据对齐逻辑。merged_df marriage_df[[年份, 登记量]].rename(columns{登记量: 结婚登记量}) merged_df merged_df.merge( divorce_df[[年份, 登记量]].rename(columns{登记量: 离婚登记量}), on年份, howinner ) years merged_df[年份].astype(str).tolist() marriage_values merged_df[结婚登记量].tolist() divorce_values merged_df[离婚登记量].tolist()注意merge的on年份必须保证两边年份列类型一致如果一边是 int 一边是 float要先统一再 merge否则会出现大量空匹配。这样合并之后趋势图、对比图、堆叠图都从同一个merged_df取数数据口径不会打架。3. Flask pyecharts 的核心实现从 DataFrame 到网页图表的完整链路3.1 app.py 的路由与函数分层为什么图表生成要独立打开 app.py核心结构一般是 Flask 初始化、Excel 读取、几个返回图表对象的函数、路由入口四段。很多学生版本会把图表生成直接堆在路由函数里一个路由几百行想复用一个图表只能复制粘贴。这个项目里更合理的写法是把「生成图表」和「渲染页面」拆成两层。from flask import Flask, render_template from pyecharts import options as opts from pyecharts.charts import Line, Bar, Pie import pandas as pd app Flask(__name__) marriage_df pd.read_excel(结婚登记(万对).xlsx) divorce_df pd.read_excel(离婚登记(万对).xlsx) # 预处理代码同上一节此处省略 # years ... # marriage_values ... # divorce_values ... def marriage_trend_chart(): c ( Line(init_optsopts.InitOpts(width900px, height500px)) .add_xaxis(years) .add_yaxis( 结婚登记对数万对, marriage_values, is_smoothTrue, symbolcircle, symbol_size8, label_optsopts.LabelOpts(is_showFalse), ) .set_global_opts( title_optsopts.TitleOpts(title结婚登记趋势, subtitle数据来源公开统计数据), tooltip_optsopts.TooltipOpts(triggeraxis), xaxis_optsopts.AxisOpts(name年份, axislabel_optsopts.LabelOpts(rotate45)), yaxis_optsopts.AxisOpts(name万对), ) ) return c app.route(/) def index(): return render_template(index.html) app.route(/trend) def trend(): chart marriage_trend_chart() return render_template(home.html, chart_optionchart.dump_options())路由函数里只做三件事调用图表函数拿到对象、调dump_options()序列化成 JSON、传给模板。图表函数独立后后面做对比图时可以同时调marriage_trend_chart()和divorce_trend_chart()也可以各自再组合出新图。参数层面init_opts控制图表尺寸和主题不写时默认 800x400is_smoothTrue让折线变成平滑曲线这类年度时序数据比硬折线更好看symbolcircle和symbol_size8指定数据点形状大小年份多时可以把 size 调到 6 避免点重叠。tooltip_opts的triggeraxis表示鼠标悬停时按整条 x 轴显示所有系列的值比默认的item更适合多系列对比。rotate45是年份标签防拥挤的关键参数超过 10 个年份基本都要旋转。app.py最后两行入口也值得注意if __name__ __main__: app.run(debugTrue, port5000)debugTrue打开调试模式改代码保存后 Flask 自动重启期末赶工阶段能省大量手动重启时间但注意 debug 模式的自动重载在读取 Excel 文件时偶尔会触发重复读取数据量大时稍微拖慢启动速度属正常现象。端口默认 5000被占用再换 5001。3.2 用 dump_options 对接模板页面渲染的最终一环pyecharts 集成 Flask 有两种主流方式新人经常在这踩坑。第一种是render_embed()把整段图表 JS 内联进 HTML单独打开没问题但两个图表放同一页面时 HTML 会膨胀到几百 KB浏览器明显卡顿。第二种是官方主推的dump_options()只导出配置 JSON前端用 echarts.min.js 解析页面体积小一个数量级。这个项目用的是第二种体现在 home.html 模板里就是下面这段。!-- templates/home.html -- !DOCTYPE html html langzh-CN head meta charsetUTF-8 title结婚离婚数据分析/title link relstylesheet href{{ url_for(static, filenamehome.css) }} /head body h1结婚离婚数据可视化/h1 div idchart stylewidth:900px;height:500px;/div script srchttps://cdn.jsdelivr.net/npm/echarts5/dist/echarts.min.js/script script var chartDom document.getElementById(chart); var myChart echarts.init(chartDom); var option {{ chart_option | safe }}; myChart.setOption(option); /script /body /html这里必须记住一个细节{{ chart_option | safe }}里的safe过滤器不能省。Jinja2 默认会对变量里的 HTML 特殊字符做转义JSON 配置里的{}、[]、引号一旦被转义echarts.init拿到的就是一段错乱的字符串图表区域直接白屏。加了safe是告诉 Jinja2“这段内容可信不要动它”。echarts.min.js的引入也有讲究。项目中 pyecharts 1.x 自带配套版本可以先从本地引入script src{{ url_for(static, filenameecharts.min.js) }}/script把 pyecharts 安装目录下pyecharts/static/里的 echarts.min.js 复制到项目 static 文件夹版本一定匹配。用 CDN 链接虽然方便但在答辩现场如果网络受限图表会加载失败这个翻车案例年年都有。4. 交互式可视化关键配置对比图、环形图与前端联动4.1 结婚离婚对比图多系列与数据缩放参数只画单条折线交互性撑不起“可视化大作业”的评分。对比图才是拉分项——把结婚登记量、离婚登记量放在同一张图里让老师直观看到趋势差。两组数据如果量级接近共用一个 y 轴就行但如果结婚登记是百万级、离婚是另一个数量级就需要考虑是否拆双轴。项目里数据单位统一是“万对”一般可以直接共用 y 轴。def compare_chart(): c ( Bar(init_optsopts.InitOpts(width1000px, height560px)) .add_xaxis(years) .add_yaxis(结婚登记, marriage_values, gap0%) .add_yaxis(离婚登记, divorce_values, gap0%) .set_global_opts( title_optsopts.TitleOpts(title结婚离婚登记量对比), legend_optsopts.LegendOpts(pos_top5%), yaxis_optsopts.AxisOpts(name登记量万对), datazoom_opts[ opts.DataZoomOpts(type_inside, range_start0, range_end100), opts.DataZoomOpts(type_slider, pos_bottom2%), ], ) .set_series_opts( label_optsopts.LabelOpts(is_showFalse), markpoint_optsopts.MarkPointOpts( data[opts.MarkPointItem(type_max, name最大值)] ), ) ) return cgap0%让两个系列的柱子紧挨着逐年份对比更直观。datazoom_opts是交互体验的分水岭type_inside支持鼠标滚轮缩放type_slider在底部生成一个可拖动的滑块条答辩时直接拖着滑块展示局部年份变化比静态图有说服力得多。range_start0, range_end100表示初始显示全部数据也可以设置成range_start40, range_end80让页面打开时默认聚焦中段制造一种“数据有重点”的讲解节奏。MarkPointItem(type_max)会自动标记最大值点不需要手写具体年份坐标pyecharts 根据数据计算这是答辩时的一个小亮点。label_opts(is_showFalse)关掉柱子上的数值标签避免多系列时数字叠在一起糊成一团如果想让关键数据裸露出来改成is_showTrue并配positiontop即可。4.2 环形图与页面导航把多个图表组装成完整看板对比图之外项目里还应该有占比类图表比如某一年离婚原因构成、近十年结婚/离婚总量占比用饼图或者环形图表现。pyecharts 里Pie的 data 格式是 (名称, 值) 的元组列表这个细节最容易出错。def pie_chart(): latest_marriage int(marriage_values[-1]) latest_divorce int(divorce_values[-1]) c ( Pie(init_optsopts.InitOpts(width800px, height500px, themelight)) .add( series_name登记占比, data_pair[ (结婚登记, latest_marriage), (离婚登记, latest_divorce), ], radius[40%, 65%], # 环形图内半径40%外半径65% label_optsopts.LabelOpts(formatter{b}: {c} ({d}%)), ) .set_global_opts(title_optsopts.TitleOpts(title最近年份登记量占比)) ) return cradius[40%, 65%]是环形图开关键——只传一个数字就是实心饼图传两个数就是环形图视觉上比饼图更现代。label_opts的formatter{b}: {c} ({d}%)里{b}是系列名{c}是数值{d}是百分比缺一个显示就不完整。themelight是 pyecharts 内置主题另一个常用值是dark配合首页深色 CSS 背景效果更好。页面导航方面项目用 index.html 做入口home.html 做图表容器多个图表页可以共用一个 home.html通过路由传入不同的chart_option和active_nav实现导航高亮。nav classnav-bar a href/trend class{{ active if active_nav trend else }}结婚趋势/a a href/compare class{{ active if active_nav compare else }}结婚离婚对比/a a href/pie class{{ active if active_nav pie else }}占比分析/a /navJinja2 的条件表达式动态设置activeclass导航条就能跟随路由变化高亮。共享模板的另一个好处是改 CSS 一处生效——如果想做成深色看板风格只要在 static/home.css 里改 body 背景色同时把每个图表生成函数的theme参数改成dark注意两处必须一起改否则图表区域和页面的视觉风格会割裂。4.3 Notebook 先行验证把调试成本降到最低项目附带pyecharts过程.ipynb不是摆设它是作者先逐块验证图表、再整合进 Flask 的路径记录。复现时强烈建议保留这个工作流每写一个新图表先在 Jupyter Notebook 里单跑验证确认数据、配色、交互都满意再挪进 app.py。理由很简单——Notebook 里报错直接看单元格输出Flask 里报错要同时翻浏览器控制台和终端日志排查链路多一倍。# 在 pyecharts过程.ipynb 中单块验证 from pyecharts.charts import Pie import pandas as pd divorce_df pd.read_excel(离婚登记(万对).xlsx) print(divorce_df.columns.tolist()) print(divorce_df.tail())tail()看最后几行确认数据是升序还是降序。如果原表按年份降序排列iloc[-1]取到的就是最早年份这在做“最近年份占比”时容易选错数据。Notebook 里这步检查 30 秒完成放进 Flask 里则是多轮重启才能发现。5. 避坑指南跑这个项目最容易踩的5个问题5.1 环境与启动类问题现象一python app.py后终端报Address already in use或浏览器访问localhost:5000一直转圈。原因上一次运行没正常关闭端口仍被占用。Windows 下 CtrlC 有时没有真正释放端口尤其之前跑过其他 Flask 项目。解决换端口是最快的app.run(port5001)要彻底清理就先查占用进程再杀掉。# macOS/Linux lsof -i:5000 kill -9 PID # Windows netstat -ano | findstr 5000 taskkill /PID PID /F提示排查期间把debugTrue开着报错信息会直接显示在网页上比反复看终端日志省事得多。现象二import pyecharts正常但运行到add_yaxis报TypeError提示参数不支持。原因pyecharts 版本不匹配。项目源码是按 1.x 的 API 写的本地装的是 0.5.x。两个版本差异很大旧版叫add_y_axis新版叫add_yaxisinit_opts的写法也完全变了。解决查版本再锁定到 1.x。pip show pyecharts pip install pyecharts1.9.0pyecharts 1.9.x 是 v1 系列里比较稳的版本配套 echarts 5.x和模板里引用的 echarts.min.js 版本能对上。现象三pd.read_excel(结婚登记(万对).xlsx)抛FileNotFoundError但文件明明在目录里。原因中文括号或全角空格被误改。压缩包里的括号是全角字符手动重命名文件时很容易被输入法替换成半角括号一个字符差异就找不到文件。Windows 命令行编码也可能导致中文文件名匹配失败。解决先确认文件名原文推荐用代码打印当前目录python -c import os; print(os.listdir(.))如果文件名没问题但控制台仍报错在 Windows 终端先执行chcp 65001切到 UTF-8 代码页再跑 python。另外把 Excel 文件和 app.py 放到同一级目录是最省心的位置约定。5.2 图表显示与数据类问题现象四页面能打开文字正常但图表 div 位置是空白的F12 控制台报 JS 错误。原因九成是 Jinja2 转义把 JSON 改坏了——模板里写了{{ chart_option }}而不是{{ chart_option | safe }}剩下一成是 echarts.min.js 版本和 dump_options 生成的配置不匹配。解决先检查模板里的 safe 过滤器再确认document.getElementById(chart)里的 id 和div idchart完全一致最后把 echarts.min.js 从本地 static 目录引入去掉 CDN 依赖。pyecharts 装好后pyecharts/static/目录下就有配套的 echarts.min.js直接复制进来版本绝对不会错。现象五图表显示出来了但登记量数值“看起来不对”比如预期是 800图上却显示 80。原因两个常见来源。一是单位混淆Excel 里存的本来就是“万对”图表 y 轴也标了“万对”但看的人以为是“对”二是 pyecharts 默认对 y 轴数值做了格式化数字太大时自动缩写。解决核对原始数据在 DataFrame 里的真实值再决定是改数据还是改显示。如果只是显示问题手动指定 y 轴格式化yaxis_optsopts.AxisOpts( name登记量万对, axislabel_optsopts.LabelOpts(formatter{value}) )formatter{value}保留原始整数不会被缩写成8×10²一类形式想更友好可以写成{value} 万对注意占位符{value}不能丢。另一个数据相关的隐藏坑是年份排序如果原表不是升序折线图会变成来回折线预处理阶段必须显式sort_values(年份)。6. 把 demo 变成自己的作业换数据源与加交互控件6.1 换数据源的固定流程这个项目最聪明的用法不是原封不动交上去而是保留 Flask pyecharts 框架把 Excel 换成自己找的数据。流程固定为三步先读新表确认列名和排序再改 app.py 里的数据加载段最后把图表函数里的列表变量替换掉。df_new pd.read_excel(自己的数据.xlsx) df_new df_new.sort_values(年份) new_years df_new[年份].astype(str).tolist() new_values df_new[数值].astype(float).tolist()换数据时最容易忽略的是年份排序和列名映射。新表的列名不一定是“年份”和“登记量”先打印columns.tolist()确认再统一改变量名。如果新数据里还有第三列分类字段比如城市或地区可以在现有图表基础上加一个堆叠图路由数据维度和答辩内容深度都会上一个台阶。6.2 加一个年份下拉筛选让图表真正“动”起来期末答辩的加分项是让用户能主动探索数据。pyecharts 的缩放、悬停是基础交互再加一个年份下拉筛选项目就从“固定图表”升级成“可交互分析”。后台接口返回 JSON前端用 fetch 拉新数据再 setOption。select idyear-select {% for y in years %} option value{{ y }}{{ y }}年/option {% endfor %} /select script document.getElementById(year-select).addEventListener(change, function() { fetch(/api/data?year this.value) .then(res res.json()) .then(data { myChart.setOption({ series: [{ data: data }] }); }); }); /script后端加一个 jsonify 接口from flask import jsonify, request app.route(/api/data) def api_data(): year request.args.get(year, ) filtered df_new[df_new[年份].astype(str) year] return jsonify(filtered[数值].tolist())这段逻辑不复杂但把“点击、筛选、更新”的动作闭环跑通了。从那以后我每次拿到新的可视化项目都会先原样把页面跑起来再按换数据的流程重走一遍最后加一个交互控件验证前后端链路是否通顺。这套动作做熟了任何 pyecharts 课设都能在半天内改成自己的版本希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

TensorFlow深度学习框架实战:从张量到部署的完整指南 2026/10/1 23:58:12

TensorFlow深度学习框架实战:从张量到部署的完整指南

TensorFlow,我是真的认真翻了大半个文档、跑坏了三个虚拟环境之后,才开始觉得自己“会用”它了。早几年写推荐系统的时候,我一听“深度学习框架”就头大,总觉得那是算法团队的事。后来自己动手才发现,你完全可以只写普…

阅读更多 →
C语言scanf空格陷阱:缓冲区残留与格式化字符串深层解析 2026/10/1 23:58:12

C语言scanf空格陷阱:缓冲区残留与格式化字符串深层解析

我被scanf的空格坑了整整一个下午事情发生在大一那年练OJ题的时候。题目要求输入一个整数、一个字符,再输入一个字符串,我老老实实写了三个scanf,结果程序表现完全不是我想的那样:字符变量里装了个回车,字符串只读到了…

阅读更多 →
hindsight:用HER后见经验回放破解稀疏奖励下的目标条件强化学习 2026/10/1 23:58:12

hindsight:用HER后见经验回放破解稀疏奖励下的目标条件强化学习

做强化学习的人,十有八九都栽在稀疏奖励上。目标条件任务尤其明显:环境给你一个目标,你希望训练出策略,让它学会针对不同目标做不同动作。但奖励一旦写成非 0 即 1 的稀疏形式,随机探索的成功率可能连千分之一都不到&a…

阅读更多 →
单片机开发工具链全解析:从IDE到调试烧录一网打尽 2026/10/1 23:58:12

单片机开发工具链全解析:从IDE到调试烧录一网打尽

1. 从一块芯片到一堆工具:单片机开发到底需要什么 干了这么多年单片机开发,经常被刚入行的朋友问:单片机开发是不是只需要一个编译器就够了?每次听到这种问题我都想笑。单片机开发从来不是“一个软件搞定一切”的事情,…

阅读更多 →
大西洋上的花园:马德拉岛旅行全攻略,徒步美食与避坑指南 2026/10/1 23:58:12

大西洋上的花园:马德拉岛旅行全攻略,徒步美食与避坑指南

第一次看到“Madeira”这个词,是在一张欧洲廉价航空的航线图上。我第一反应是:这不是一种蛋糕吗?后来翻了地图才发现,它是藏在葡萄牙西南方向大西洋深处的一片群岛。对许多旅行者来说,马德拉岛算不上一眼惊艳的目的地&…

阅读更多 →
让排名追踪自己跑起来:open-seo-mcp-skills定时任务与SEO自动化工作流实战 2026/10/1 23:58:05

让排名追踪自己跑起来:open-seo-mcp-skills定时任务与SEO自动化工作流实战

让排名追踪自己跑起来:open-seo-mcp-skills定时任务与SEO自动化工作流实战 【免费下载链接】open-seo-mcp-skills Free SEO MCP server open-source SEO and GEO skills for Claude: keyword research, rank tracking, audits, backlinks, AI visibility on your r…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉