高中成績可視化平臺開發筆記

高中成績可視化平臺(1)


一、項目概述

本系統是一個基于 PyQt5 和 Matplotlib 的高中成績數據可視化分析平臺,旨在幫助教師快速了解學生成績分布、班級對比、學科表現等關鍵指標。平臺支持文科與理科的數據切換,并提供多個維度的圖表展示和交互式操作。

核心功能:

  • 文科/理科數據動態切換
  • 四個核心分析頁面(總覽、學科分析、班級分析、排名分析)
  • 圖表聯動刷新機制
  • 表格與圖表雙向綁定
  • 自定義樣式與視覺美化

二、技術選型

技術用途
PyQt5GUI 界面構建
Pandas數據處理與分析
Matplotlib圖表繪制
QTabWidget多選項卡管理
QComboBox / QTableWidget控件交互

三、模塊劃分與類結構

整個平臺主要由兩個類組成:

  • ScoreVisualizationPlatform:主窗口類,負責 UI 構建與事件處理
  • DataProcessor:數據處理類,封裝所有數據讀取與分析邏輯

四、UI 構建與控件初始化

def __init__(self):super().__init__()self.setWindowTitle("2023級成績可視化平臺")self.resize(1200, 800)# 初始化數據處理器self.data_processor = DataProcessor()# 主布局main_layout = QVBoxLayout(self)control_panel = QWidget()control_layout = QHBoxLayout(control_panel)# 下拉框選擇文理類型self.stream_combo = QComboBox()self.stream_combo.addItems(["文科", "理科"])control_layout.addWidget(QLabel("文理類型:"))control_layout.addWidget(self.stream_combo)# 科目選擇下拉框self.subject_combo = QComboBox()control_layout.addWidget(QLabel("科目選擇:"))control_layout.addWidget(self.subject_combo)# 班級選擇下拉框self.classes_combo = QComboBox()control_layout.addWidget(QLabel("班級選擇:"))control_layout.addWidget(self.classes_combo)# 加載數據按鈕load_button = QPushButton("加載數據")control_layout.addWidget(load_button)# 添加控件到主布局main_layout.addWidget(control_panel)# 創建選項卡self.tab_widget = QTabWidget()main_layout.addWidget(self.tab_widget)# 初始化各選項卡self.create_overview_tab()self.create_subject_analysis_tab()self.create_class_analysis_tab()self.create_ranking_tab()# 綁定信號self.stream_combo.currentTextChanged.connect(self.on_data_type_changed)self.subject_combo.currentTextChanged.connect(lambda: self.refresh_all_charts())self.classes_combo.currentTextChanged.connect(lambda: self.refresh_all_charts())load_button.clicked.connect(self.load_data)

📌 提示:該部分完成主窗口的創建,包含控制面板、四個選項卡以及數據加載按鈕。


五、選項卡頁面設計與實現

1. 總覽頁 create_overview_tab()

def create_overview_tab(self):tab = QWidget()self.tab_widget.addTab(tab, "總覽")layout = QGridLayout(tab)# 圖1:總分前20名圖表self.total_score_chart = ChartWidget("總分Top20")layout.addWidget(self.total_score_chart, 0, 0, 1, 1)# 圖2:班級占比圖表self.class_distribution_chart = ChartWidget("Top20班級占比")layout.addWidget(self.class_distribution_chart, 0, 3, 1, 3)# 圖3:各科目平均分對比self.subject_avg_chart = ChartWidget("學科Top20")layout.addWidget(self.subject_avg_chart, 1, 0, 1, 1)# 圖4:班級學科分布(占第1行后兩列)self.class_subject_chart = ChartWidget("學科Top20班級占比")layout.addWidget(self.class_subject_chart, 1, 3, 1, 3)

圖表說明:

區域內容
左上總分前20名柱狀圖
右上班級分布餅圖
左下當前科目前20名柱狀圖
右下當前科目班級分布餅圖

2. 學科分析頁 create_subject_analysis_tab()

def create_subject_analysis_tab(self):tab = QWidget()self.tab_widget.addTab(tab, "學科分析")layout = QGridLayout(tab)self.passing_rank = ChartWidget("本科上線排名")layout.addWidget(self.passing_rank, 0, 0)self.subject_stats_chart = ChartWidget("各科目統計分析")layout.addWidget(self.subject_stats_chart, 0, 1)self.single_subject_chart = ChartWidget("單科目上線人數排名")layout.addWidget(self.single_subject_chart, 1, 0)self.correlation_chart = ChartWidget("科目成績相關性分析")layout.addWidget(self.correlation_chart, 1, 1)

圖表說明:

區域內容
左上各班過線人數柱狀圖
右上各科平均分柱狀圖
左下各科及格人數柱狀圖
右下兩個科目的散點圖(顯示相關性)

3. 班級分析頁 create_class_analysis_tab()

def create_class_analysis_tab(self):tab = QWidget()self.tab_widget.addTab(tab, "班級分析")layout = QGridLayout(tab)self.class_avg_chart = ChartWidget("各班級平均分對比")layout.addWidget(self.class_avg_chart, 0, 0)self.class_score_dist_chart = ChartWidget("班級成績分布")layout.addWidget(self.class_score_dist_chart, 0, 1)self.class_subject_performance_chart = ChartWidget("班級各科表現")layout.addWidget(self.class_subject_performance_chart, 1, 0)self.total_top_5 = ChartWidget("各班級top5各科表現")layout.addWidget(self.total_top_5, 1, 1)

圖表說明:

區域內容
左上班級平均分柱狀圖
右上成績分布直方圖
左下各科平均分折線圖
右下每個班級 top5 學生的各科成績雷達圖

4. 排名分析頁 create_ranking_tab()

def create_ranking_tab(self):tab = QWidget()self.tab_widget.addTab(tab, "排名分析")main_layout = QVBoxLayout(tab)tables_container = QWidget()tables_layout = QVBoxLayout(tables_container)inner_layout = QHBoxLayout(tab)ranking_group = QVBoxLayout()self.ranking_title = QLabel("年級前100名學生")self.ranking_table = QTableWidget()self.ranking_table.setSortingEnabled(True)ranking_group.addWidget(self.ranking_title)ranking_group.addWidget(self.ranking_table)class_group = QVBoxLayout()self.class_title = QLabel("當前班級單科成績排名")self.class_tables = QTableWidget()self.class_tables.setSortingEnabled(True)class_group.addWidget(self.class_title)class_group.addWidget(self.class_tables)inner_layout.addLayout(ranking_group, stretch=1)inner_layout.addLayout(class_group, stretch=1)tables_layout.addLayout(inner_layout)main_layout.addWidget(tables_container)self.figure = Figure(figsize=(5, 3))self.canvas = FigureCanvas(self.figure)self.canvas.setStyleSheet("background-color:rgba(0, 1, 1, 0.3); border: 1px solid #ccc;")main_layout.addWidget(self.canvas)

圖表說明:

區域內容
上部兩個表格(年級前100名 / 當前班級單科排名)
下部動態繪圖區域(用于展示趨勢、對比等圖表)

六、數據處理與圖表聯動

1. 數據加載與刷新機制

def load_data(self):if self.data_processor.load_data():self.refresh_all_charts()QMessageBox.information(self, "成功", "數據加載完成!")else:QMessageBox.warning(self, "錯誤", "數據加載失敗,請檢查數據文件!")def on_data_type_changed(self, data_type):self.refresh_all_charts()def refresh_all_charts(self):data_type = "liberal" if self.stream_combo.currentText() == "文科" else "science"subject_prefix = "文科" if data_type == "liberal" else "理科"subject_type = self.subject_combo.currentText()self.total_score_chart.title = f"2023級{subject_prefix}總分前20名"self.class_distribution_chart.title = f"2023級{subject_prefix}前20名班級占比"self.update_overview_charts(data_type, subject_type)self.update_subject_analysis_charts(data_type)self.update_class_analysis_charts(data_type)self.update_ranking_table(data_type)

? 特點:通過組合文理科類型 + 科目 + 班級,動態更新所有圖表與表格內容。


2. 總覽頁圖表更新 update_overview_charts()

def update_overview_charts(self, data_type, subject):# 總分前20名柱狀圖top_students = self.data_processor.get_top_students(data_type, 20)if top_students is not None:self.total_score_chart.plot_bar_chart(top_students, '姓名', '總分',f"{'文科' if data_type == 'liberal' else '理科'}總分Top20")# 班級分布餅圖top20_class_dist = top_students['班級'].value_counts().reset_index()top20_class_dist.columns = ['班級', '人數']self.class_distribution_chart.plot_pie_chart(top20_class_dist, '班級', '人數',f"{'文科' if data_type == 'liberal' else '理科'}Top20班級占比")# 單科前20名柱狀圖subject_top20 = data.nlargest(20, subject)[['姓名', subject]]self.subject_avg_chart.plot_bar_chart(subject_top20, '姓名', subject,f"{'文科' if data_type == 'liberal' else '理科'}{subject}Top20")# 班級學科分布餅圖class_subject_data = self.data_processor.get_class_subject_top20(data_type)subject_class_dist = class_subject_data[subject].reset_index()subject_class_dist.columns = ['班級', '人數']self.class_subject_chart.plot_pie_chart(subject_class_dist, '班級', '人數',f"{'文科' if data_type == 'liberal' else '理科'}{subject}Top20班級占比")

3. 學科分析頁圖表更新 update_subject_analysis_charts()

def update_subject_analysis_charts(self, data_type):passing = self.data_processor.get_pass_line(data_type)totals = self.data_processor.calculate_total_scores(data_type)ranks = totals[totals['總分'] > passing].groupby('班級').size(). \reset_index(name='人數').sort_values(by='人數', ascending=False)self.passing_rank.plot_bar_chart(ranks, '班級', '人數', f"{'文科' if data_type == 'liberal' else '理科'}各班過線人數")subject_analysis = self.data_processor.get_subject_analysis(data_type)avg_scores = subject_analysis['平均分'].reset_index()avg_scores.columns = ['科目', '平均分']self.subject_stats_chart.plot_bar_chart(avg_scores, '科目', '平均分', "各科目平均分對比")online_counts = []for subject in subjects:if subject in data.columns:online_count = (data[subject] >= 60).sum()online_counts.append({'科目': subject, '及格人數': online_count})online_df = pd.DataFrame(online_counts)self.single_subject_chart.plot_bar_chart(online_df, '科目', '及格人數', "各科目及格人數統計")subject1, subject2 = subjects[0], subjects[1]clean_data = data[[subject1, subject2]].dropna()ax.scatter(clean_data[subject1], clean_data[subject2], alpha=0.9, edgecolors='#8A0808')self.correlation_chart.figure.tight_layout()self.correlation_chart.canvas.draw()

4. 班級分析頁圖表更新 update_class_analysis_charts()

def update_class_analysis_charts(self, data_type):# 平均總分柱狀圖class_avg_scores = []for class_name in data['班級'].unique():class_data = data[data['班級'] == class_name]total_scores = class_data[subjects].sum(axis=1, skipna=True)avg_score = total_scores.mean()class_avg_scores.append({'班級': class_name, '平均總分': avg_score})class_avg_df = pd.DataFrame(class_avg_scores).sort_values('平均總分', ascending=False)self.class_avg_chart.plot_bar_chart(class_avg_df, '班級', '平均總分', "各班級平均總分對比")# 分數段分布柱狀圖bins = [0, 300, 400, 500, 600, 700, 800]labels = ['0-300', '300-400', '400-500', '500-600', '600-700', '700-800']score_dist = []for label, (low, high) in zip(labels, zip(bins[:-1], bins[1:])):count = ((total_scores_data['總分'] >= low) & (total_scores_data['總分'] < high)).sum()score_dist.append({'分數段': label, '人數': count})score_dist_df = pd.DataFrame(score_dist)self.class_score_dist_chart.plot_bar_chart(score_dist_df, '分數段', '人數', "總分分布統計")# 各科表現堆疊柱狀圖stacked_data = []for class_name in sorted(all_classes):row = {'班級': class_name}for subject, subject_data in class_subject_data.items():row[subject] = subject_data.get(class_name, 0)stacked_data.append(row)stacked_df = pd.DataFrame(stacked_data)self.class_subject_performance_chart.plot_stacked_bar(stacked_df, "各班級各科目前20名人數分布")# 各班前5名圖表top_5 = self.data_processor.get_class_top_5(data_type, class_name)[0][['姓名'] + subjects]self.total_top_5.plot_stacked_bar(data=top_5, title=f"{class_name} 學生學科成績分布",item_1='姓名', item_2='姓名',x_label='學生姓名', y_label='分數')

5. 排名分析頁表格與圖表更新 update_ranking_table()

def update_ranking_table(self, data_type):top_students = self.data_processor.get_top_students(data_type, 100)if top_students is not None:self.ranking_table.setRowCount(len(top_students))self.ranking_table.setColumnCount(4)self.ranking_table.setHorizontalHeaderLabels(['排名', '姓名', '班級', '總分'])for i, (_, row) in enumerate(top_students.iterrows()):self.ranking_table.setItem(i, 0, QTableWidgetItem(str(i + 1)))self.ranking_table.setItem(i, 1, QTableWidgetItem(str(row['姓名'])))self.ranking_table.setItem(i, 2, QTableWidgetItem(str(row['班級'])))self.ranking_table.setItem(i, 3, QTableWidgetItem(f"{row['總分']:.1f}"))self.ranking_table.resizeColumnsToContents()cla = self.classes_combo.currentText()sujects = self.subject_combo.currentText()data = self.data_processor.get_subject_scores(data_type, cla, sujects)if data is not None:self.class_tables.setRowCount(len(data))self.class_tables.setColumnCount(4)self.class_tables.setHorizontalHeaderLabels(['單科排名', '姓名', '班級', sujects])for i, (_, row) in enumerate(data.iterrows()):self.class_tables.setItem(i, 0, QTableWidgetItem(str(i + 1)))self.class_tables.setItem(i, 1, QTableWidgetItem(str(row['姓名'])))self.class_tables.setItem(i, 2, QTableWidgetItem(str(row['班級'])))self.class_tables.setItem(i, 3, QTableWidgetItem(f"{row[sujects]:.1f}"))self.class_tables.resizeColumnsToContents()data = data.head()self.figure.clear()self.figure.patch.set_alpha(0.0)ax = self.figure.add_subplot(111)ax.set_facecolor((0, 1, 1, 0.3))bars = ax.bar(data["姓名"], data[sujects], color="#4CAF50")for bar in bars:yval = bar.get_height()ax.text(bar.get_x() + bar.get_width() / 2.0, yval, int(yval),va='bottom', ha='center', color='cyan')ax.set_title(f"{'文科' if data_type == 'liberal' else '理科'}-{cla}-{sujects}前5名", color='cyan')ax.set_ylabel('分數', color='cyan')ax.set_xlabel('姓名', color='cyan')ax.grid(True, linestyle='--', alpha=0.6)ax.tick_params(axis='x', colors='cyan')ax.tick_params(axis='y', colors='cyan')self.canvas.draw()

高中成績可視化平臺(2)


一、項目概述

本系統是一個基于 PyQt5 和 Matplotlib 的高中成績數據可視化分析平臺,旨在幫助教師快速了解學生成績分布、班級對比、學科表現等關鍵指標。平臺支持文科與理科的數據切換,并提供多個維度的圖表展示和交互式操作。

核心功能:

  • 文科/理科數據動態切換
  • 四個核心分析頁面(總覽、學科分析、班級分析、排名分析)
  • 圖表聯動刷新機制
  • 表格與圖表雙向綁定
  • 自定義樣式與視覺美化

二、技術選型

技術用途
PyQt5GUI 界面構建
Pandas數據處理與分析
Matplotlib圖表繪制
QTabWidget多選項卡管理
QComboBox / QTableWidget控件交互

三、模塊劃分與類結構

整個平臺主要由兩個類組成:

  • ScoreVisualizationPlatform:主窗口類,負責 UI 構建與事件處理
  • DataProcessor:數據處理類,封裝所有數據讀取與分析邏輯

四、UI 構建與控件初始化

def __init__(self):super().__init__()self.setWindowTitle("2023級成績可視化平臺")self.resize(1200, 800)# 初始化數據處理器self.data_processor = DataProcessor()# 主布局main_layout = QVBoxLayout(self)control_panel = QWidget()control_layout = QHBoxLayout(control_panel)# 下拉框選擇文理類型self.stream_combo = QComboBox()self.stream_combo.addItems(["文科", "理科"])control_layout.addWidget(QLabel("文理類型:"))control_layout.addWidget(self.stream_combo)# 科目選擇下拉框self.subject_combo = QComboBox()control_layout.addWidget(QLabel("科目選擇:"))control_layout.addWidget(self.subject_combo)# 班級選擇下拉框self.classes_combo = QComboBox()control_layout.addWidget(QLabel("班級選擇:"))control_layout.addWidget(self.classes_combo)# 加載數據按鈕load_button = QPushButton("加載數據")control_layout.addWidget(load_button)# 添加控件到主布局main_layout.addWidget(control_panel)# 創建選項卡self.tab_widget = QTabWidget()main_layout.addWidget(self.tab_widget)# 初始化各選項卡self.create_overview_tab()self.create_subject_analysis_tab()self.create_class_analysis_tab()self.create_ranking_tab()# 綁定信號self.stream_combo.currentTextChanged.connect(self.on_data_type_changed)self.subject_combo.currentTextChanged.connect(lambda: self.refresh_all_charts())self.classes_combo.currentTextChanged.connect(lambda: self.refresh_all_charts())load_button.clicked.connect(self.load_data)

📌 提示:該部分完成主窗口的創建,包含控制面板、四個選項卡以及數據加載按鈕。


五、選項卡頁面設計與實現

1. 總覽頁 create_overview_tab()

def create_overview_tab(self):tab = QWidget()self.tab_widget.addTab(tab, "總覽")layout = QGridLayout(tab)# 圖1:總分前20名圖表self.total_score_chart = ChartWidget("總分Top20")layout.addWidget(self.total_score_chart, 0, 0, 1, 1)# 圖2:班級占比圖表self.class_distribution_chart = ChartWidget("Top20班級占比")layout.addWidget(self.class_distribution_chart, 0, 3, 1, 3)# 圖3:各科目平均分對比self.subject_avg_chart = ChartWidget("學科Top20")layout.addWidget(self.subject_avg_chart, 1, 0, 1, 1)# 圖4:班級學科分布(占第1行后兩列)self.class_subject_chart = ChartWidget("學科Top20班級占比")layout.addWidget(self.class_subject_chart, 1, 3, 1, 3)

圖表說明:

區域內容
左上總分前20名柱狀圖
右上班級分布餅圖
左下當前科目前20名柱狀圖
右下當前科目班級分布餅圖

2. 學科分析頁 create_subject_analysis_tab()

def create_subject_analysis_tab(self):tab = QWidget()self.tab_widget.addTab(tab, "學科分析")layout = QGridLayout(tab)self.passing_rank = ChartWidget("本科上線排名")layout.addWidget(self.passing_rank, 0, 0)self.subject_stats_chart = ChartWidget("各科目統計分析")layout.addWidget(self.subject_stats_chart, 0, 1)self.single_subject_chart = ChartWidget("單科目上線人數排名")layout.addWidget(self.single_subject_chart, 1, 0)self.correlation_chart = ChartWidget("科目成績相關性分析")layout.addWidget(self.correlation_chart, 1, 1)

圖表說明:

區域內容
左上各班過線人數柱狀圖
右上各科平均分柱狀圖
左下各科及格人數柱狀圖
右下兩個科目的散點圖(顯示相關性)

3. 班級分析頁 create_class_analysis_tab()

def create_class_analysis_tab(self):tab = QWidget()self.tab_widget.addTab(tab, "班級分析")layout = QGridLayout(tab)self.class_avg_chart = ChartWidget("各班級平均分對比")layout.addWidget(self.class_avg_chart, 0, 0)self.class_score_dist_chart = ChartWidget("班級成績分布")layout.addWidget(self.class_score_dist_chart, 0, 1)self.class_subject_performance_chart = ChartWidget("班級各科表現")layout.addWidget(self.class_subject_performance_chart, 1, 0)self.total_top_5 = ChartWidget("各班級top5各科表現")layout.addWidget(self.total_top_5, 1, 1)

圖表說明:

區域內容
左上班級平均分柱狀圖
右上成績分布直方圖
左下各科平均分折線圖
右下每個班級 top5 學生的各科成績雷達圖

4. 排名分析頁 create_ranking_tab()

def create_ranking_tab(self):tab = QWidget()self.tab_widget.addTab(tab, "排名分析")main_layout = QVBoxLayout(tab)tables_container = QWidget()tables_layout = QVBoxLayout(tables_container)inner_layout = QHBoxLayout(tab)ranking_group = QVBoxLayout()self.ranking_title = QLabel("年級前100名學生")self.ranking_table = QTableWidget()self.ranking_table.setSortingEnabled(True)ranking_group.addWidget(self.ranking_title)ranking_group.addWidget(self.ranking_table)class_group = QVBoxLayout()self.class_title = QLabel("當前班級單科成績排名")self.class_tables = QTableWidget()self.class_tables.setSortingEnabled(True)class_group.addWidget(self.class_title)class_group.addWidget(self.class_tables)inner_layout.addLayout(ranking_group, stretch=1)inner_layout.addLayout(class_group, stretch=1)tables_layout.addLayout(inner_layout)main_layout.addWidget(tables_container)self.figure = Figure(figsize=(5, 3))self.canvas = FigureCanvas(self.figure)self.canvas.setStyleSheet("background-color:rgba(0, 1, 1, 0.3); border: 1px solid #ccc;")main_layout.addWidget(self.canvas)

圖表說明:

區域內容
上部兩個表格(年級前100名 / 當前班級單科排名)
下部動態繪圖區域(用于展示趨勢、對比等圖表)

六、數據處理與圖表聯動

1. 數據加載與刷新機制

def load_data(self):if self.data_processor.load_data():self.refresh_all_charts()QMessageBox.information(self, "成功", "數據加載完成!")else:QMessageBox.warning(self, "錯誤", "數據加載失敗,請檢查數據文件!")def on_data_type_changed(self, data_type):self.refresh_all_charts()def refresh_all_charts(self):data_type = "liberal" if self.stream_combo.currentText() == "文科" else "science"subject_prefix = "文科" if data_type == "liberal" else "理科"subject_type = self.subject_combo.currentText()self.total_score_chart.title = f"2023級{subject_prefix}總分前20名"self.class_distribution_chart.title = f"2023級{subject_prefix}前20名班級占比"self.update_overview_charts(data_type, subject_type)self.update_subject_analysis_charts(data_type)self.update_class_analysis_charts(data_type)self.update_ranking_table(data_type)

? 特點:通過組合文理科類型 + 科目 + 班級,動態更新所有圖表與表格內容。


2. 總覽頁圖表更新 update_overview_charts()

def update_overview_charts(self, data_type, subject):# 總分前20名柱狀圖top_students = self.data_processor.get_top_students(data_type, 20)if top_students is not None:self.total_score_chart.plot_bar_chart(top_students, '姓名', '總分',f"{'文科' if data_type == 'liberal' else '理科'}總分Top20")# 班級分布餅圖top20_class_dist = top_students['班級'].value_counts().reset_index()top20_class_dist.columns = ['班級', '人數']self.class_distribution_chart.plot_pie_chart(top20_class_dist, '班級', '人數',f"{'文科' if data_type == 'liberal' else '理科'}Top20班級占比")# 單科前20名柱狀圖subject_top20 = data.nlargest(20, subject)[['姓名', subject]]self.subject_avg_chart.plot_bar_chart(subject_top20, '姓名', subject,f"{'文科' if data_type == 'liberal' else '理科'}{subject}Top20")# 班級學科分布餅圖class_subject_data = self.data_processor.get_class_subject_top20(data_type)subject_class_dist = class_subject_data[subject].reset_index()subject_class_dist.columns = ['班級', '人數']self.class_subject_chart.plot_pie_chart(subject_class_dist, '班級', '人數',f"{'文科' if data_type == 'liberal' else '理科'}{subject}Top20班級占比")

3. 學科分析頁圖表更新 update_subject_analysis_charts()

def update_subject_analysis_charts(self, data_type):passing = self.data_processor.get_pass_line(data_type)totals = self.data_processor.calculate_total_scores(data_type)ranks = totals[totals['總分'] > passing].groupby('班級').size(). \reset_index(name='人數').sort_values(by='人數', ascending=False)self.passing_rank.plot_bar_chart(ranks, '班級', '人數', f"{'文科' if data_type == 'liberal' else '理科'}各班過線人數")subject_analysis = self.data_processor.get_subject_analysis(data_type)avg_scores = subject_analysis['平均分'].reset_index()avg_scores.columns = ['科目', '平均分']self.subject_stats_chart.plot_bar_chart(avg_scores, '科目', '平均分', "各科目平均分對比")online_counts = []for subject in subjects:if subject in data.columns:online_count = (data[subject] >= 60).sum()online_counts.append({'科目': subject, '及格人數': online_count})online_df = pd.DataFrame(online_counts)self.single_subject_chart.plot_bar_chart(online_df, '科目', '及格人數', "各科目及格人數統計")subject1, subject2 = subjects[0], subjects[1]clean_data = data[[subject1, subject2]].dropna()ax.scatter(clean_data[subject1], clean_data[subject2], alpha=0.9, edgecolors='#8A0808')self.correlation_chart.figure.tight_layout()self.correlation_chart.canvas.draw()

4. 班級分析頁圖表更新 update_class_analysis_charts()

def update_class_analysis_charts(self, data_type):# 平均總分柱狀圖class_avg_scores = []for class_name in data['班級'].unique():class_data = data[data['班級'] == class_name]total_scores = class_data[subjects].sum(axis=1, skipna=True)avg_score = total_scores.mean()class_avg_scores.append({'班級': class_name, '平均總分': avg_score})class_avg_df = pd.DataFrame(class_avg_scores).sort_values('平均總分', ascending=False)self.class_avg_chart.plot_bar_chart(class_avg_df, '班級', '平均總分', "各班級平均總分對比")# 分數段分布柱狀圖bins = [0, 300, 400, 500, 600, 700, 800]labels = ['0-300', '300-400', '400-500', '500-600', '600-700', '700-800']score_dist = []for label, (low, high) in zip(labels, zip(bins[:-1], bins[1:])):count = ((total_scores_data['總分'] >= low) & (total_scores_data['總分'] < high)).sum()score_dist.append({'分數段': label, '人數': count})score_dist_df = pd.DataFrame(score_dist)self.class_score_dist_chart.plot_bar_chart(score_dist_df, '分數段', '人數', "總分分布統計")# 各科表現堆疊柱狀圖stacked_data = []for class_name in sorted(all_classes):row = {'班級': class_name}for subject, subject_data in class_subject_data.items():row[subject] = subject_data.get(class_name, 0)stacked_data.append(row)stacked_df = pd.DataFrame(stacked_data)self.class_subject_performance_chart.plot_stacked_bar(stacked_df, "各班級各科目前20名人數分布")# 各班前5名圖表top_5 = self.data_processor.get_class_top_5(data_type, class_name)[0][['姓名'] + subjects]self.total_top_5.plot_stacked_bar(data=top_5, title=f"{class_name} 學生學科成績分布",item_1='姓名', item_2='姓名',x_label='學生姓名', y_label='分數')

5. 排名分析頁表格與圖表更新 update_ranking_table()

def update_ranking_table(self, data_type):top_students = self.data_processor.get_top_students(data_type, 100)if top_students is not None:self.ranking_table.setRowCount(len(top_students))self.ranking_table.setColumnCount(4)self.ranking_table.setHorizontalHeaderLabels(['排名', '姓名', '班級', '總分'])for i, (_, row) in enumerate(top_students.iterrows()):self.ranking_table.setItem(i, 0, QTableWidgetItem(str(i + 1)))self.ranking_table.setItem(i, 1, QTableWidgetItem(str(row['姓名'])))self.ranking_table.setItem(i, 2, QTableWidgetItem(str(row['班級'])))self.ranking_table.setItem(i, 3, QTableWidgetItem(f"{row['總分']:.1f}"))self.ranking_table.resizeColumnsToContents()cla = self.classes_combo.currentText()sujects = self.subject_combo.currentText()data = self.data_processor.get_subject_scores(data_type, cla, sujects)if data is not None:self.class_tables.setRowCount(len(data))self.class_tables.setColumnCount(4)self.class_tables.setHorizontalHeaderLabels(['單科排名', '姓名', '班級', sujects])for i, (_, row) in enumerate(data.iterrows()):self.class_tables.setItem(i, 0, QTableWidgetItem(str(i + 1)))self.class_tables.setItem(i, 1, QTableWidgetItem(str(row['姓名'])))self.class_tables.setItem(i, 2, QTableWidgetItem(str(row['班級'])))self.class_tables.setItem(i, 3, QTableWidgetItem(f"{row[sujects]:.1f}"))self.class_tables.resizeColumnsToContents()data = data.head()self.figure.clear()self.figure.patch.set_alpha(0.0)ax = self.figure.add_subplot(111)ax.set_facecolor((0, 1, 1, 0.3))bars = ax.bar(data["姓名"], data[sujects], color="#4CAF50")for bar in bars:yval = bar.get_height()ax.text(bar.get_x() + bar.get_width() / 2.0, yval, int(yval),va='bottom', ha='center', color='cyan')ax.set_title(f"{'文科' if data_type == 'liberal' else '理科'}-{cla}-{sujects}前5名", color='cyan')ax.set_ylabel('分數', color='cyan')ax.set_xlabel('姓名', color='cyan')ax.grid(True, linestyle='--', alpha=0.6)ax.tick_params(axis='x', colors='cyan')ax.tick_params(axis='y', colors='cyan')self.canvas.draw()

七、項目結果圖(部分)

總覽
學科分析

附:qss樣式

QMainWindow {background-color: #16003a;
}
QWidget {background-color: #16003a;color: cyan;
}
QTabWidget::pane {border: 1px solid rgba(221, 221, 221, 0);background-color: #16003a;
}
QTabBar::tab {background-color: #16003a;padding: 8px 16px;margin-right: 2px;border-top-left-radius: 4px;border-top-right-radius: 4px;
}
QTabBar::tab:selected {background-color: #00385e;color: #ffffff;
}
QPushButton {background-color: rgba(31, 106, 152, 0.81);color: cyan;border: none;padding: 8px 16px;border-radius: 4px;font-weight: bold;
}
QPushButton:hover {background-color: #00560f;
}
QGroupBox {color: #4dffff;font-size: 13px;border: 2px solid #4dffff;border-radius: 5px;margin-top: 2px;padding-top: 2px;
}
QGroupBox::title {color: cyan;subcontrol-origin: margin;left: 5px;padding: 0 5px 0 5px;
}
QLabel {color: cyan;text-align: center;background-color: #16003a;font-size: 20px;font-weight: bold;
}
QLabel#titleLabel {padding: 5px;font-size: 40px;font-family: "Microsoft YaHei";text-align: center;
}
QComboBox {background-color: rgba(162, 88, 0, 0.7);color: cyan;font-size: 12px;border: 1px solid #ffffff;border-radius: 35px;padding: 0px 5px;
}
QComboBox QAbstractItemView::item:hover {background-color: #0B6121;
}
  • 數據: 需要數據或遇到問題可聯系QQ(1591236129)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/911911.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/911911.shtml
英文地址,請注明出處:http://en.pswp.cn/news/911911.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

自動化按需導入組件庫的工具rust版本完成開源了

背景 當我為每個Vue項目使用ui組件庫的時候&#xff0c;都會使用按需導入的方式來使用ui組件庫。但是每次按需導入&#xff0c;不可避免的就需要做以下三步。我們以element plus ui組件庫為例。 1. 安裝依賴 第一步&#xff0c;當然是需要安裝依賴。命令如下: pnpm add unp…

Linux內核中TCP分段的核心機制:tcp_fragment函數解析

引言:TCP分段的必要性 在TCP/IP協議棧中,MSS(最大分段大小) 限制了單次傳輸的數據量。當應用層發送的數據超過當前路徑的MSS時,內核必須執行分段操作。tcp_fragment函數正是Linux內核中處理TCP分段的核心機制,它巧妙地在協議合規性、內存安全和性能效率之間取得平衡。 一…

【趙渝強老師】OceanBase OBServer節點的SQL層

OceanBase OBServer節點的SQL層將用戶的SQL請求轉化成對一個或多個Tablet的數據訪問。SQL層會按照以下順序經過一系列組件來處理一個SQL&#xff1a; Parser -->Resolver-->Transformer-->Optimizer-->CodeGenerator-->Executor。視頻講解如下 【趙渝強老師】O…

從“高配”到“普惠”,黑芝麻智能攜手Nullmax打造輔助駕駛主流量產方案

近日&#xff0c;黑芝麻智能攜手Nullmax打造的輔助駕駛主流量產方案正式發布。該方案面向8-15萬元級別主流車型&#xff0c;基于單顆黑芝麻智能武當C1236跨域計算芯片&#xff0c;集成Nullmax全棧自研的軟件技術架構&#xff0c;結合領先的視覺感知算法&#xff0c;打造高性能輔…

信息安全認證體系全解析:從資質證明到行業準入的實踐指南

Hello&#xff01;大家好&#xff0c;小編是一名專注IT領域的資深探索家&#xff0c;大家發現了嗎&#xff1f;現在刷招聘軟件&#xff0c;國企安全崗必標 "CISP 優先"&#xff0c;外企招聘悄悄寫著 "CISSP 加分"—— 這些帶字母的證書到底是啥&#xff1f…

優雅地創建實體類——Builder 鏈式調用

我們來看以下的代碼。改造前構造實體類用重載構造器或用 setter 對變量進行賦值&#xff0c;一旦變量變多則需要對每個變量進行 set 賦值&#xff0c;并且有可能會賦值錯對象。 private static void test() {//1.構造器賦值Task task1 new Task("2023000000009439"…

如何輕松將照片從 iPhone 傳輸到 Android?

從 iPhone 換到 Android 手機后&#xff0c;你肯定不想丟掉珍貴的照片回憶吧&#xff1f;好在&#xff0c;本文分享了 6 種有效的解決方案&#xff0c;教你如何輕松地將照片從 iPhone 傳輸到 Android。 第 1 部分&#xff1a;如何通過 iReaShare Phone Transfer 將照片從 iPhon…

AI編程:[體驗]存量微服務架構下植入WebSocket的“踩坑”與“填坑”

一、核心需求 功能需求&#xff1a;用戶可以通過語音與AI對話&#xff0c;并實現類似ChatGPT的實時交互&#xff08;流式響應&#xff0c;打字機效果&#xff09;技術需求&#xff1a;在現有微服務架構中進行擴展&#xff08;SpringCloud&#xff09; 二、技術盲點 陌生領域 …

uniapp事件onLoad區分大小寫

區分大小寫。不然會不起作用。onLoad方法中的功能均不會被執行。 除了功能邏輯要檢查外。大小寫是要認真檢查的一部分

《打破微前端困局:樣式沖突與資源隔離破局指南》

微前端架構憑借其獨特優勢&#xff0c;正逐漸成為眾多大型項目的首選架構模式。它將一個龐大的前端應用拆解為多個相對獨立的子應用&#xff0c;每個子應用可以獨立開發、部署和維護&#xff0c;極大地提升了開發效率與團隊協作的靈活性。然而&#xff0c;隨著微前端架構的廣泛…

OpenCV——邊緣檢測

邊緣檢測 一、邊緣檢測二、邊緣檢測算子2.1、Sobel算子2.2、Scharr算子2.3、Laplacian算子 三、Canny邊緣檢測3.1、Canny邊緣檢測的步驟3.2、Canny算法的實現 一、邊緣檢測 邊緣是指圖像中像素的灰度值發生劇烈變化的區域&#xff1a; 圖像中的邊緣主要有以下幾種成因&#x…

2506認證資訊|工信部出手整治多品牌充電寶,WMC上海稍遜往年,RED修訂Common Charger,WiFi7 FCC測試

01 — 中國 工信部擬制定移動電源強制性國家標準 該標準將從以下方面全面提升移動電源安全性&#xff1a; 1. 擬在GB 31241、GB 4943.1基礎上&#xff0c;新增或加嚴過充電、針刺等試驗要求。 2. 擬提出影響電池安全的正負極材料、隔膜等關鍵材料要求。 3. 擬規范鋰離子電池…

Linux Regulator 子系統核心邏輯與關鍵問題全解析

Linux Regulator 子系統核心邏輯與關鍵問題全解析 一、什么是 regulator 子系統&#xff1f;核心作用&#xff1f; regulator 子系統是 Linux 內核為板級/SoC 多路可控電源設計的統一電源管理框架。它的主要作用是&#xff1a; 為每一路可控電源&#xff08;Buck、LDO、DCDC …

制造業官網3D應用,讓產品會“說話”

在當今數字化時代&#xff0c;裝備制造業正經歷著前所未有的變革。隨著消費升級和國內經濟的蓬勃發展&#xff0c;中國社會的經濟格局從傳統的“工業經濟”向多元化的“服務經濟”轉型。裝備制造業作為制造業與服務業融合的核心領域&#xff0c;積極探索全新的“服務化”發展模…

SCAU15--氣球狂歡節

15 氣球狂歡節 Time Limit:1000MS Memory Limit:65535K 題型: 編程題 語言: G;GCC 描述&#xff1a; 一個充滿魔法的國度中&#xff0c;存在一場年度的節日&#xff0c;名為“氣球狂歡節”。在這個節日中&#xff0c;有一個傳統的比賽&#xff0c;那就是“氣球挑戰賽”…

python打卡day56@浙大疏錦行

知識點回顧&#xff1a; 假設檢驗基礎知識 原假設與備擇假設P值、統計量、顯著水平、置信區間 白噪聲 白噪聲的定義自相關性檢驗&#xff1a;ACF檢驗和Ljung-Box 檢驗偏自相關性檢驗&#xff1a;PACF檢驗 平穩性 平穩性的定義單位根ADF檢驗: 越小越平穩 季節性檢驗 ACF檢驗序列…

采集文章+原創AI處理+發布網站詳細教程

簡數采集器是新一代的網站文章采集和發布平臺&#xff0c;完全在線配置和使用云采集&#xff0c;功能強大&#xff0c;操作簡單&#xff0c;配置快捷高效。 簡數不僅提供網頁文章采集、數據批量處理、定時采集、定時定量自動發布等基本功能&#xff0c;還集成強大的SEO工具與接…

Hystrix超時降級機制全解析

Hystrix的超時降級實現主要通過以下核心機制完成&#xff0c;結合配置、注解和Fallback邏輯實現服務容錯&#xff1a; 1. 超時觸發條件 默認超時時間&#xff1a;Hystrix默認超時閾值為1秒&#xff0c;超過該時間未響應則觸發降級。自定義配置&#xff1a;可通過HystrixComman…

6月份最新代發考試戰報:思科華為HCIP HCSE 考試通過

6月份最新代發考試戰報&#xff1a;思科華為HCIP HCSE 考試通過 H19-423 HCSA-Presales-IP Network 數通考試通過&#xff0c; H12-725 HCIP-Security安全 考試通過&#xff0c;H13-121 HCIP-Kunpeng Application Developer鯤鵬計算 考試通過&#xff0c;CCNP 350-401考試通過…

談談我的軟考經歷

我 2020 年高考進入大學&#xff0c;軟件工程專業&#xff0c;去年&#xff08;24年7月&#xff09;畢業開始工作。我實習是在一家云計算公司&#xff0c;公司內部對軟考的證書沒有什么激勵或補助之類的&#xff0c;我也一直認為計算機嘛&#xff0c;“talk is cheap&#xff0…