news 2026/8/24 4:52:54

Python学生成绩数据分析可视化工具(Tkinter+Pandas+Matplotlib)完整源码

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python学生成绩数据分析可视化工具(Tkinter+Pandas+Matplotlib)完整源码

一、项目简介

本项目是一款基于Python Tkinter + Pandas + Matplotlib开发的桌面端学生成绩数据分析可视化工具,无需复杂部署,开箱即用。支持导入 Excel、CSV 成绩文件,自动完成成绩统计分析、多维度可视化绘图、报告导出、历史数据存档等功能。

工具适配教师、班委、教学管理人员日常成绩统计场景,完美解决传统 Excel 手动统计繁琐、图表制作困难、数据无存档的痛点,适合 Python 课程设计、毕设练手、教学辅助工具开发。

核心功能亮点

  • ✅ 支持Excel(xlsx/xls)、CSV通用成绩文件导入

  • ✅ 自动识别分数字段,无需手动配置列名

  • ✅ 全自动成绩数据分析:平均分、最值、标准差、及格率、优秀率

  • ✅ 智能分数段统计:0-59、60-79、80-100 三段分级

  • ✅ 四合一可视化图表:柱状图、饼图、直方图、横向对比图

  • ✅ 一键导出 TXT 结构化分析报告

  • ✅ 成绩数据本地历史存档,方便回溯对比

  • ✅ 可视化GUI界面,操作简单,零基础上手

  • ✅ 自动中文适配,解决 Matplotlib 乱码问题

二、开发环境与依赖

2.1 运行环境

  • Python 3.7 及以上版本

  • Windows / Mac / Linux 全平台兼容

2.2 第三方库依赖

执行以下命令批量安装依赖:

pip install pandas numpy matplotlib openpyxl xlrd

依赖说明:

  • tkinter:Python内置GUI界面库,无需额外安装

  • pandas:数据读取、清洗、统计分析核心库

  • numpy:数值计算、数据处理

  • matplotlib:数据可视化绘图

  • openpyxl/xlrd:支持Excel文件读写

三、软件功能详细介绍

3.1 数据导入与预览

支持导入主流的 Excel、CSV 成绩表格文件,自动去除空行脏数据,左侧表格实时预览数据内容,最多预览150行数据,清晰查看原始成绩信息。程序智能识别包含「分数、成绩、总分、得分」的字段作为统计列,适配任意规范表头。

3.2 全自动数据分析

一键执行数据分析,自动生成完整统计报告,包含:

  • 基础数据:有效学生人数、平均分、最高分、最低分、分数标准差

  • 达标统计:及格人数、及格率、优秀人数、优秀率(60分及格、80分优秀)

  • 分段统计:不及格、中等、优秀三个分数段人数分布

3.3 多维可视化图表生成

一键生成2×2四合一专业分析图表,自动保存本地,包含:

  1. 分数段人数柱状图:直观展示各分数段人数差异

  2. 及格率饼图:可视化整体及格、不及格占比

  3. 成绩分布直方图:查看班级成绩集中区间与分布趋势

  4. 分数段横向对比图:横向对比各层级人数

3.4 报告导出与数据存档

  • 支持一键将分析报告导出为 TXT 文档,方便存档、打印、汇报使用

  • 支持将本次成绩数据保存至历史记录文件夹,按时间命名,方便多次考试成绩对比分析

四、项目完整源码

直接复制以下代码,新建score_analysis.py文件即可运行:

import tkinter as tk from tkinter import ttk, filedialog, messagebox, scrolledtext import pandas as pd import numpy as np import matplotlib.pyplot as plt import os from datetime import datetime import warnings warnings.filterwarnings("ignore") # ---------------------- 全局配置 ---------------------- plt.rcParams["font.family"] = ["SimHei", "WenQuanYi Micro Hei", "Heiti TC"] plt.rcParams["axes.unicode_minus"] = False OUTPUT_DIR = "output" HISTORY_DIR = "scores_history" os.makedirs(OUTPUT_DIR, exist_ok=True) os.makedirs(HISTORY_DIR, exist_ok=True) class ScoreAnalysisTool: def __init__(self, root): self.root = root self.root.title("学生考试成绩数据分析可视化工具") self.root.geometry("1100x720") # 全局变量 self.df = None self.file_path = None self.report_text = "" self.create_widgets() def create_widgets(self): # 顶部操作栏 top_frame = ttk.Frame(self.root, padding=8) top_frame.pack(fill=tk.X) ttk.Button(top_frame, text="导入Excel/CSV成绩文件", command=self.load_file).pack(side=tk.LEFT, padx=5) ttk.Button(top_frame, text="执行数据分析", command=self.run_analysis).pack(side=tk.LEFT, padx=5) ttk.Button(top_frame, text="生成可视化图表", command=self.draw_charts).pack(side=tk.LEFT, padx=5) ttk.Button(top_frame, text="导出分析报告", command=self.export_report).pack(side=tk.LEFT, padx=5) ttk.Button(top_frame, text="保存本次成绩至历史记录", command=self.save_history).pack(side=tk.LEFT, padx=5) # 分割左右布局 main_pane = ttk.PanedWindow(self.root, orient=tk.HORIZONTAL) main_pane.pack(fill=tk.BOTH, expand=True, padx=8, pady=8) # 左侧:数据预览表格 left_frame = ttk.Frame(main_pane) main_pane.add(left_frame, weight=3) ttk.Label(left_frame, text="数据预览", font=("微软雅黑",11,"bold")).pack(anchor="w") self.table = ttk.Treeview(left_frame, columns=[], show="headings") scroll_y = ttk.Scrollbar(left_frame, orient=tk.VERTICAL, command=self.table.yview) self.table.configure(yscrollcommand=scroll_y.set) self.table.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scroll_y.pack(side=tk.RIGHT, fill=tk.Y) # 右侧:分析报告文本框 right_frame = ttk.Frame(main_pane) main_pane.add(right_frame, weight=2) ttk.Label(right_frame, text="分析报告", font=("微软雅黑",11,"bold")).pack(anchor="w") self.text_area = scrolledtext.ScrolledText(right_frame) self.text_area.pack(fill=tk.BOTH, expand=True) def load_file(self): """加载Excel/CSV成绩文件""" path = filedialog.askopenfilename( filetypes=[("Excel文件", "*.xlsx;*.xls"), ("CSV文件", "*.csv"), ("所有文件", "*.*")] ) if not path: return self.file_path = path try: if path.endswith(".csv"): self.df = pd.read_csv(path) else: self.df = pd.read_excel(path) # 简单清洗:去除空行 self.df = self.df.dropna(how="all") self.refresh_table() messagebox.showinfo("成功", f"数据加载完成,共{len(self.df)}条学生记录") except Exception as e: messagebox.showerror("读取失败", str(e)) def refresh_table(self): """刷新预览表格""" # 清空旧数据 for item in self.table.get_children(): self.table.delete(item) self.table["columns"] = list(self.df.columns) for col in self.df.columns: self.table.heading(col, text=str(col)) self.table.column(col, width=100) # 插入前150行预览 for _, row in self.df.head(150).iterrows(): self.table.insert("", tk.END, values=list(row)) def run_analysis(self): """核心统计分析""" if self.df is None: messagebox.showwarning("提示", "请先导入成绩文件!") return self.text_area.delete(1.0, tk.END) self.report_text = "" # 自动识别分数列(匹配包含“分数/成绩/总分”字段) score_cols = [c for c in self.df.columns if any(k in str(c).lower() for k in ["分数","成绩","总分","得分"])] if not score_cols: messagebox.showerror("错误", "未找到分数列!请确保表头包含:分数/总分/成绩") return score_col = score_cols[0] scores = pd.to_numeric(self.df[score_col], errors="coerce").dropna() # 基础指标 total_count = len(scores) avg_score = round(scores.mean(),2) max_score = scores.max() min_score = scores.min() std_score = round(scores.std(),2) pass_line = 60 good_line = 80 pass_num = len(scores[scores >= pass_line]) good_num = len(scores[scores >= good_line]) pass_rate = round(pass_num / total_count *100,2) good_rate = round(good_num / total_count *100,2) # 分数段统计 seg_0_60 = len(scores[(scores >=0) & (scores <60)]) seg_60_80 = len(scores[(scores >=60) & (scores <80)]) seg_80_100 = len(scores[scores >=80]) now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") report = f""" ==================== 学生成绩分析报告 ==================== 分析时间:{now} 数据源文件:{os.path.basename(self.file_path)} 有效学生总数:{total_count}人 【整体概况】 平均分:{avg_score} 最高分:{max_score} 最低分:{min_score} 分数标准差:{std_score} 【达标情况】 及格线(≥60)人数:{pass_num} |及格率:{pass_rate}% 优秀线(≥80)人数:{good_num} |优秀率:{good_rate}% 【分数段分布】 0~59分:{seg_0_60}人 60~79分:{seg_60_80}人 80~100分:{seg_80_100}人 ========================================================== """ self.report_text = report self.text_area.insert(tk.END, report) def draw_charts(self): """绘制多张可视化图表""" if self.df is None or len(self.report_text)==0: messagebox.showwarning("提示", "请先导入数据并执行【数据分析】!") return score_cols = [c for c in self.df.columns if any(k in str(c).lower() for k in ["分数","成绩","总分","得分"])] score_col = score_cols[0] scores = pd.to_numeric(self.df[score_col], errors="coerce").dropna() fig, axes = plt.subplots(2,2, figsize=(14,10)) fig.suptitle("班级考试成绩可视化分析图表", fontsize=15) # 1.分数段柱状图 seg_names = ["0-59","60-79","80-100"] seg_data = [ len(scores[(scores >=0) & (scores <60)]), len(scores[(scores >=60) & (scores <80)]), len(scores[(scores >=80)]) ] axes[0,0].bar(seg_names, seg_data, color=["#e74c3c","#f39c12","#27ae60"]) axes[0,0].set_title("分数段人数分布柱状图") axes[0,0].set_ylabel("人数") # 2.及格/不及格饼图 pass_cnt = len(scores[scores>=60]) fail_cnt = len(scores[scores<60]) axes[0,1].pie([pass_cnt,fail_cnt], labels=["及格","不及格"], autopct="%.2f%%", colors=["#2ecc71","#e74c3c"]) axes[0,1].set_title("及格占比饼图") #3.成绩分布直方图 axes[1,0].hist(scores, bins=12, color="#3498db", alpha=0.7) axes[1,0].set_title("成绩分布直方图") axes[1,0].set_xlabel("分数") axes[1,0].set_ylabel("人数") #4.优秀/中等/不及格横向条形 axes[1,1].barh(seg_names, seg_data, color=["#e74c3c","#f39c12","#27ae60"]) axes[1,1].set_title("分数段横向对比图") plt.tight_layout() save_path = os.path.join(OUTPUT_DIR, f"成绩图表_{datetime.now().strftime('%Y%m%d_%H%M%S')}.png") plt.savefig(save_path, dpi=150, bbox_inches="tight") plt.show() messagebox.showinfo("绘图完成", f"图表已保存至:{save_path}") def export_report(self): """导出文本报告""" if len(self.report_text) == 0: messagebox.showwarning("提示", "请先执行数据分析!") return save_path = filedialog.asksaveasfilename( defaultextension=".txt", filetypes=[("文本文件","*.txt"),("所有文件","*.*")], initialfile="成绩分析报告.txt" ) if save_path: with open(save_path,"w",encoding="utf-8") as f: f.write(self.report_text) messagebox.showinfo("导出成功", f"报告保存至:{save_path}") def save_history(self): """保存当前成绩进入历史文件夹""" if self.df is None: messagebox.showwarning("提示", "请先导入成绩数据!") return save_name = f"历史成绩_{datetime.now().strftime('%Y%m%d_%H%M%S')}.xlsx" save_path = os.path.join(HISTORY_DIR, save_name) self.df.to_excel(save_path, index=False) messagebox.showinfo("保存成功", f"已存入历史记录:{save_name}") if __name__ == "__main__": root = tk.Tk() app = ScoreAnalysisTool(root) root.mainloop()

五、运行教程

步骤1:安装依赖库

打开CMD或PyCharm终端,执行依赖安装命令:

pip install pandas numpy matplotlib openpyxl xlrd

步骤2:准备成绩文件

新建 Excel / CSV 文件,表格中必须包含分数、总分、成绩等关键字段,程序可自动识别统计列。

步骤3:运行程序

直接运行Python脚本,自动弹出GUI窗口,操作流程: 1、导入成绩文件 → 2、执行数据分析 → 3、生成可视化图表 → 4、导出报告/保存历史数据。

步骤4:文件输出说明

  • output文件夹:自动保存生成的可视化图表图片

  • scores_history文件夹:存放所有存档的历史成绩表格

六、项目总结

本成绩数据分析工具功能完整、界面简洁、实用性极强,完美实现了数据导入、智能分析、可视化绘图、报告导出、数据存档全流程功能。代码结构清晰、注释规范、易于二次开发,可拓展多科目分析、班级对比、成绩预测、数据筛选等功能。

适合作为Python课程设计、期末大作业、小型桌面软件开发实训、教学辅助工具使用,零基础可直接运行部署。

七、拓展方向(可自行二次开发)

  • 增加多科目成绩独立分析功能

  • 添加成绩排名、升降序筛选

  • 增加历史成绩对比分析功能

  • 支持自定义及格线、优秀线分数

  • 新增PDF报告导出功能

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

Moldia超大规模分块高斯重建:原理、流程与工程实践

大家好&#xff0c;我是专注于计算机视觉与三维重建领域的技术博主。在三维重建任务中&#xff0c;面对海量点云或图像数据时&#xff0c;如何高效、高质量地完成全局重建&#xff0c;一直是工程实践中的核心挑战。传统的全局优化方法往往受限于内存和计算量&#xff0c;难以扩…

作者头像 李华
网站建设 2026/8/24 4:51:21

高性能人形机器人开发实战:从仿真部署到功能验证全流程解析

这次我们来看一个关于“力大无穷的人形机器人”的项目。这听起来像是一个结合了先进机械设计、高功率驱动与智能控制系统的硬核工程。它可能是一个开源机器人平台&#xff0c;也可能是一个特定机构发布的演示项目。对于技术爱好者、机器人研究者或相关领域的学生来说&#xff0…

作者头像 李华
网站建设 2026/8/24 4:50:46

Java开发者技术栈与面试核心要点解析

1. Java程序员技术栈全景解析"金三银四"这个说法在IT行业流传已久&#xff0c;指的是每年三四月份的人才流动高峰期。作为从业十余年的Java开发者&#xff0c;我见证过太多候选人因为技术栈不完整而与心仪岗位失之交臂。这份汇总不是简单的题库罗列&#xff0c;而是结…

作者头像 李华
网站建设 2026/8/24 4:50:15

递归智能体框架:构建多AI协同的自动化系统架构

1. 项目概述&#xff1a;什么是递归智能体“马具”&#xff1f;最近在AI智能体开发圈里&#xff0c;一个叫“Recursive Agent Harnesses”的概念开始被频繁讨论。乍一听这个名字&#xff0c;有点玄乎——“递归智能体马具”&#xff1f;这到底是个什么玩意儿&#xff1f;简单来…

作者头像 李华
网站建设 2026/8/24 4:47:43

高级RAG架构演进:从朴素检索到图检索与自适应策略

这里写自定义目录标题欢迎使用Markdown编辑器引言:朴素 RAG 的瓶颈在哪里一、朴素 RAG 的四大瓶颈二、自适应检索:让系统决定"要不要检索"2.1 核心思想2.2 实现方式2.3 价值与代价三、图检索增强:让 RAG 学会多跳推理3.1 从向量列表到知识图谱3.2 多跳推理的价值3.3 …

作者头像 李华