|
|
2 months ago | |
|---|---|---|
| README.md | 2 months ago | |
| untitled4.py | 2 months ago | |
| 成绩分析系统 | 2 months ago | |
README.md
-- coding: utf-8 --
""" Created on Tue Nov 14 22:32:50 2023
@author: 21011 """ from IPython.display import display, HTML import getpass import mysql.connector import asyncio import nest_asyncio import hashlib import pandas as pd import numpy as np import matplotlib.pyplot as plt from datetime import datetime from matplotlib.pyplot import MultipleLocator #%matplotlib inline plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签 plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号 nest_asyncio.apply() def print_message(*message): print("【{}】 【{}】".format(datetime.now(), message))
def read_csv(): stus = pd.read_csv("stu.csv", index_col= False) #display(stus) return stus read_csv()
df = pd.read_csv("stu.csv") df.head() #display(df)
def add_stu():
while True:
print_message("添加学生成绩!")
# 添加学号
stu_id_flag = True
while stu_id_flag:
stu_id = input("请输入学号:")
# 判断学号是否为空
if stu_id == "":
print_message("学号不能为空,请重新输入!")
continue
# 判断学号是否正确
if len(stu_id) != 8:
print_message("学号长度为8,请重新输入!")
continue
# 判断学号是否存在
stus = read_csv()
stu_ids = stus["学号"].values.tolist()
if int(stu_id) in stu_ids:
print_message("该学号已经存在,请重新输入!")
continue
else:
stu_id_flag = False
# 添加学生姓名
stu_name_flag = True
while stu_name_flag:
name = input("请输入学生姓名:")
if len(name) < 2 or len(name) > 10:
print_message("学生姓名长度为2-10,请重新输入!")
continue
else:
stu_name_flag = False
subjects=["语文", "数学", "英语", "物理", "化学", "生物", "历史", "地理", "政治"]
scores={}
# 添加各科成绩
for subject in subjects:
stu_flag = True
while stu_flag:
scores[subject] = input("请输入"+subject+"成绩:")
if str.isdigit(scores[subject]):
if eval(scores[subject]) < 0 or eval(scores[subject]) > 100:
print_message("成绩范围为0-100,请重新输入!")
continue
else:
stu_flag = False
else:
print('请输入正确的分数')
continue
stu_dict = {"学号":stu_id,"姓名":name,"语文":scores['语文'],"数学":scores['数学'],"英语":scores['英语'],"物理":scores['物理'],"化学":scores['化学'],"生物":scores['生物'],"历史":scores['历史'],"地理":scores['地理'],"政治":scores['政治']}
stu_df = pd.DataFrame(stu_dict,index=[0])
new_stus = stus.append(stu_df, sort=False)
new_stus.to_csv("stu.csv", index = False)
print_message("添加学生成绩成功")
#display(stu_df)
break
#add_stu()
def read_someone(student=''): if student=='': print_message("查询学生成绩!") stus = read_csv() #display(stus) stu_names = stus["姓名"].values.tolist() while True: stu_name = input("请输入学生姓名:") if stu_name not in stu_names: print_message("该学生不存在,请重新输入!") continue else: stu = stus.loc[(stus['姓名'] == stu_name),:] print_message("【{}】该学生成绩如下:".format(stu_name)) display(stu) break else: stus = read_csv() stu = stus.loc[(stus['姓名'] == student),:] print_message("【{}】该学生成绩如下:".format(student)) display(stu) #read_someone()
def update_someone(): print_message("修改学生成绩!") stus = read_csv() #display(stus) stu_names = stus["姓名"].values.tolist() while True: # 学生姓名输入逻辑 stu_name_flag = True while stu_name_flag: stu_name = input("请输入待修改成绩学生姓名:") if stu_name not in stu_names: print_message("该学生不存在,请重新输入!") continue else: stu_name_flag = False # 学生课程输入逻辑 stu_subject_flag = True while stu_subject_flag: subject = input("请输入【{}】要修改的科目:".format(stu_name)) if subject not in ["语文","数学","英语","物理","化学","生物","历史","地理","政治"]: print_message("课程错误,请重新输入") continue else: stu_subject_flag = False # 学生成绩输入逻辑 stu_grade_flag = True while stu_grade_flag: grade = input("请输入【{}】要修改的分数:".format(subject)) if int(grade) not in range(0,100+1): print_message("成绩输入超出,请重新输入") continue else: stu_grade_flag = False # 获取输入课程index subject_index = list(stus.columns).index(subject) # 获取学生index stu_index = stus.loc[(stus['姓名'] == stu_name),:].index[0] # 修改对应index上的成绩(数值) stus.iloc[stu_index,subject_index] = int(grade) stus.to_csv("stu.csv", index = False) print_message("成绩修改完成") # 展示修改后的成绩 new_stu = stus.loc[(stus['姓名'] == stu_name),:] #display(new_stu) break
#update_someone()
def delete_someone(): print_message("删除学生成绩!") stus = read_csv() #display(stus) stu_names = stus["姓名"].values.tolist() while True: # 学生姓名输入逻辑 stu_name_flag = True while stu_name_flag: stu_name = input("请输入待删除成绩学生姓名:") if stu_name not in stu_names: print_message("该学生不存在,请重新输入!") continue else: stu_name_flag = False stu = stus.loc[(stus['姓名'] == stu_name),:] #display(stu) delete_flag = input("确认是否删除学生【{}】成绩(y/n)".format(stu_name_flag)) if delete_flag == "y": save_books = stus.drop(stus[stus['姓名']== stu_name].index) save_books.to_csv("stu.csv", index = False) #display(save_books) print_message("【{}】成绩删除成功".format(stu_name)) break else: print_message("退出删除") break
#delete_someone()
def grade_bar_sort(df): """学生总成绩柱状图""" # 获取学生的总成绩 grade = df.iloc[:, 2:].sum(axis=1) # 获取对应成绩的学生姓名 name = df.iloc[:, 1] # 数据合并 zf_df = pd.concat([name, grade], axis=1) zf_df.columns = ['name', 'gross_score']
# 根据学生总成绩进行降序排序
sort_df = zf_df.sort_values(by=['gross_score'], ascending=False)
print(sort_df)
width,height,size = 28, 12, 18
# 默认画布大小
plt.figure()
plt.figure(figsize=(width,height))
# 绘制柱形图
plt.bar(range(0, len(sort_df)*6, 6), sort_df.iloc[:, 1], width=4)
# 定义x轴的间隔,rotation:文字角度
plt.xticks(range(0, len(sort_df)*6, 6), sort_df.iloc[:, 0], rotation=90, fontsize=size)
# 柱子上的数字显示
for a,b in zip(np.arange(0, len(sort_df.iloc[:, 0])*6, 6), sort_df.iloc[:, 1]):
plt.text(a,b,'%d'%b,ha='center',va='bottom',fontsize=size);
plt.show();
#grade_bar_sort(df)
def grade_barh_sort(df): """学生总成绩水平柱状图""" # 获取学生总成绩 grade = df.iloc[:, 2:].sum(axis=1) # 获取学生成绩对应姓名 name = df.iloc[:, 1] # 数据合并 zf_df = pd.concat([name, grade], axis=1) zf_df.columns = ['name', 'gross_score'] # 根据学生总成绩进行降序排序 sort_df = zf_df.sort_values(by=['gross_score'])
print(sort_df)
width,height,size = 20, 24, 12
# 默认画布大小
plt.figure()
plt.figure(figsize=(width,height))
# 绘制水平柱状图
plt.barh(range(0, len(sort_df)*3, 3), sort_df.iloc[:, 1], height=2)
# 设置y轴的间隔
plt.yticks(range(0, len(sort_df)*3, 3), sort_df.iloc[:, 0], fontsize=size)
# 柱子上的数字显示
for a,b in zip(np.arange(0, len(sort_df.iloc[:, 0])*3, 3), sort_df.iloc[:, 1]):
plt.text(b+10,a-0.5,'%d'%b,ha='center',va='bottom',fontsize=size);
plt.show();
#grade_barh_sort(df)
打印数据后五行
#df.tail()
def grade_pass_count(df):
"""学生各科成绩等级比例扇形图"""
# 获取学生各科成绩
subjects = df.iloc[:, 1:]
width,height = 24, 18
# 默认画布大小
plt.figure(figsize=(width,height))
# 定义学生成绩等级
text = ["优秀","良好","中等","及格","不及格"]
# 对每科学生成绩进行等级划分
for i,name in enumerate(subjects.iloc[:, 1:].columns):
# 等级条件,>=90为优秀,<90&>=80为良好,<80&>=70为中等,<70&>=60为及格,<60为不及格
a = len(subjects[subjects[name]>=90])
b = len(subjects[(subjects[name]<90) & (subjects[name]>=80)])
c = len(subjects[(subjects[name]<80) & (subjects[name]>=70)])
d = len(subjects[(subjects[name]<70) & (subjects[name]>=60)])
e = len(subjects[subjects[name]<60])
#print(name,a,b,c,d,e,text)
data = [a,b,c,d,e]
#print(data, text)
# 绘制饼图
plt.subplot(3, 3, i + 1) # 3x3 网格中的第 (i+1) 个位置
plt.pie(data, labels=text, autopct="%.2f%%")
plt.title(name)
plt.show()
#grade_pass_count(df)
def grade_max_bar(df):
"""各科学生成绩前三柱状图"""
# 获取学生各科成绩
subjects = df.iloc[:, 1:]
# 获取各科的名字
names = list(subjects.iloc[:, 1:].columns)
datas = []
# 获取各科成绩前三的数据列表
for name in subjects.iloc[:, 1:].columns:
max3 = subjects.sort_values(by=name,ascending=False)'姓名', name[:3]
d = [x[0] for x in list(max3name.values)]
datas.append(d)
# 转换成df结构
data_df = pd.DataFrame(np.array(datas))
width,height = 26, 18
# 默认画布大小
plt.figure()
plt.figure(figsize=(width,height))
x =list(range(0, len(names)*3, 3))
total_width, n = 0.8, 2
width = total_width / n
# 绘制各科第一名成绩柱形图
plt.bar(x, data_df[0], width=width, label='第一名',tick_label=names,fc = 'y')
# 柱子上的数字显示
for a,b in zip(np.arange(0, len(data_df[0])*3, 3), data_df[0]):
plt.text(a,b,'%d'%b,ha='center',va='bottom',fontsize=12);
for i in range(len(x)):
x[i] = x[i] + width
# 绘制各科第一名成绩柱形图
plt.bar(x,data_df[1], width=width, label='第二名',tick_label=names, fc = 'r')
# 柱子上的数字显示
for a,b in zip(np.arange(0, len(data_df[1])*3, 3), data_df[1]):
plt.text(a+width,b,'%d'%b,ha='center',va='bottom',fontsize=12);
for i in range(len(x)):
x[i] = x[i] + width
# 绘制各科第一名成绩柱形图
plt.bar(x,data_df[2], width=width, label='第三名',tick_label=names, fc = 'g')
# 柱子上的数字显示
for a,b in zip(np.arange(0, len(data_df[2])*3, 3), data_df[2]):
plt.text(a+width*2,b,'%d'%b,ha='center',va='bottom',fontsize=12);
plt.legend()
plt.show()
#grade_max_bar(df)
def grade_max_polt(df):
"""各科学生成绩前三折线图"""
# 获取学生各科成绩
subjects = df.iloc[:, 1:]
# 获取学生各科名字
names = list(subjects.iloc[:, 1:].columns)
datas = []
# 获取各科成绩前三的数据列表
for name in subjects.iloc[:, 1:].columns:
max3 = subjects.sort_values(by=name,ascending=False)'姓名', name[:3]
d = [x[0] for x in list(max3name.values)]
datas.append(d)
# 转换为df数据类型
data_df = pd.DataFrame(np.array(datas))
width,height = 20, 10
# 默认画布大小
plt.figure()
plt.figure(figsize=(width,height))
# 绘制折线图
plt.plot(names, datas)
plt.ylim(90, 100)
# 设置图例
plt.legend(['第一名','第二名','第三名'])
plt.show()
#grade_max_polt(df)
def grade_max_bars(df): """各科学生成绩前三详细柱状图""" # 获取学生各科成绩 subjects = df.iloc[:, 1:] # 获取各科名字 infos = list(subjects.iloc[:, 1:].columns) names = [] k = [] n = 0 # 获取各科学生成绩前三、对应学生姓名 for name in subjects.iloc[:, 1:].columns: max3 = subjects.sort_values(by=name,ascending=False)'姓名', name[:3] d = [x[0] for x in max3'姓名'.values]
print(max3name.values[0].tolist())
h = [x[0] for x in list(max3[[name]].values)]
k.append(h)
names.append(d)
width,height = 20, 10
# 默认画布大小
plt.figure()
plt.figure(figsize=(width,height))
# 定义子图
plt.subplot(331+n)
# 绘制柱形图
plt.bar(range(len(max3)), k[n], tick_label=names[n])
# 显示柱形图数据
for a,b in zip(np.arange(len(k[n])), k[n]):
plt.text(a,b,'%d'%b,ha='center',va='bottom',fontsize=12);
n+=1
# 显示每科标签名字
plt.title(name)
# 定义y轴范围
plt.ylim(0,110)
plt.show()
#grade_max_bars(df)
def grade_polar(df,student): # 获取成绩 student_scores = df[df['姓名'] == student].iloc[:, 2:].values.flatten() student_scores = list(student_scores) student_scores.append(student_scores[0]) # 准备角度值,首尾相连 dim_num = 9 radians = np.linspace(0, 2 * np.pi, dim_num, endpoint=False) radians = np.concatenate((radians, [radians[0]])) # 绘制多边形(雷达图) plt.polar(radians,student_scores) #设置维度坐标(首尾相连) radar_labels =list(df.columns[2:]) radar_labels = np.concatenate((radar_labels, [radar_labels[0]])) # 设置极坐标的标签 angles = radians * 180/np.pi # 弧度转角度 plt.thetagrids(angles, labels=radar_labels) # 设置新的刻度标签 # 填充多边形 plt.fill(radians,student_scores,alpha=0.25) # 6.展示图表 plt.show()
async def grade_averge_polar(df): # 获取各科的平均成绩 grade = df.iloc[:, 2:].sum(axis=0)/(df.shape[0]) grade = np.concatenate((grade, [grade.iloc[0]])) # 准备角度值,首尾相连 dim_num = 9 radians = np.linspace(0, 2 * np.pi, dim_num, endpoint=False) radians = np.concatenate((radians, [radians[0]])) # 绘制多边形(雷达图) plt.polar(radians,grade) #设置维度坐标(首尾相连) radar_labels =list(df.columns[2:]) radar_labels = np.concatenate((radar_labels, [radar_labels[0]])) # 设置极坐标的标签 angles = radians * 180/np.pi # 弧度转角度 plt.thetagrids(angles, labels=radar_labels) # 设置新的刻度标签 # 填充多边形 plt.fill(radians,grade,alpha=0.25) # 6.展示图表 plt.show() #grade_averge_polar(df)
async def grade_average_line_plot(df): # 获取各科的平均成绩 grade = df.iloc[:, 2:].sum(axis=0)/(df.shape[0]) # 获取各科名字 subjects = list(df.columns[2:])
# 绘制折线图
plt.plot(subjects, grade, marker='o') # 使用圆点标记每个数据点
# 设置图表标签和标题
plt.xlabel('科目')
plt.ylabel('平均分')
plt.title('各科平均成绩折线图')
# 展示图表
plt.show()
#grade_average_line_plot(df)
async def fetch_data(): df = pd.read_csv("stu.csv") df.head() return df
async def grade_average_bar_chart(df): # 获取各科的平均成绩 grade = df.iloc[:, 2:].mean(axis=0) # 获取各科名字 subjects = list(df.columns[2:])
# 绘制柱状图
plt.bar(subjects, grade)
# 设置图表标签和标题
plt.xlabel('科目')
plt.ylabel('平均分')
plt.title('各科平均成绩柱状图')
# 设置y轴范围从0开始
plt.ylim([0, max(grade)+10])
# 展示图表
plt.show()
#grade_average_bar_chart(df)
async def averge(): df = await fetch_data() await asyncio.gather( grade_averge_polar(df), grade_average_line_plot(df), grade_average_bar_chart(df) )
html = """
"""#身份校验 def authenticate(): authorized_users = { "teacher": "ab3fe4003f14e3ef573417f95e47d4985c482eadd139c08b3758eeae7cc60b9d", #密码为 "password123" "student": "c0067d4af4e87f00dbac63b6156828237059172d1bbeac67427345d6a9fda484" #密码为 "password" }
user = input("请输入用户名: ")
password = getpass.getpass("Enter your password: ")
# 使用hashlib来计算密码的SHA-3散列值
hashed_password = hashlib.sha3_256(password.encode()).hexdigest()
if user in authorized_users and hashed_password == authorized_users[user]:
print("身份验证成功!")
return user
else:
print("身份验证失败,请检查用户名和密码!")
return False
def user_access(): attempts = 3 while attempts > 0: user=authenticate() if user: return user else: attempts -= 1 print(f"剩余尝试次数: {attempts}")
print("尝试次数超过限制,退出程序。")
return False
user1=user_access()
if_continue=True if user1=='teacher': print('Welcome!') while if_continue: read_csv() df = pd.read_csv("stu.csv") df.head() x=input('0:退出\n1:添加\n2:查找\n3:删除\n4:绘图\n') if x=='0': if_continue=False elif x=='1': add_stu() elif x=='2': read_someone() elif x=='3': delete_someone() elif x=='4': y=input('0:退出\n1:学生总成绩柱状图\n2学生总成绩水平柱状图\n3:学生各科成绩等级比例扇形图\n4:各科学生成绩前三柱状图\n5:各科学生成绩前三折线图\n6:各科学生成绩前三详细柱状图\n7:各科平均成绩图\n') if y=='0': if_continue=False elif y=='1': grade_bar_sort(df) elif y=='2': grade_barh_sort(df) elif y=='3': grade_pass_count(df) elif y=='4': grade_max_bar(df) elif y=='5': grade_max_polt(df) elif y=='6': grade_max_bars(df) elif y=='7': asyncio.run(averge()) pass else: print('请确保规范输入') continue else: print('请确保规范输入') continue elif user1=='student': stu=input('请输入姓名:') read_someone(stu) grade_polar(df,stu)