Lashtw commited on
Commit
ac4afff
·
verified ·
1 Parent(s): dc7bfe9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +33 -37
app.py CHANGED
@@ -1,16 +1,12 @@
1
  import streamlit as st
2
  import pandas as pd
3
  import plotly.graph_objects as go
4
- import os
5
  from zipfile import ZipFile
6
  import plotly.io as pio
7
  from io import BytesIO
8
- import numpy as np
9
- import shutil
10
 
11
- # 中文字体配置(核心修改部分)
12
  def setup_chinese_font():
13
- # 列出多个备选中文字体
14
  chinese_fonts = [
15
  "Microsoft JhengHei",
16
  "Noto Sans CJK TC",
@@ -20,26 +16,18 @@ def setup_chinese_font():
20
  ]
21
  return ", ".join(chinese_fonts)
22
 
23
- # 初始化全局字体设置
24
  CHINESE_FONT = setup_chinese_font()
25
 
26
- try:
27
- import kaleido
28
- except ImportError:
29
- st.error("請安裝 'kaleido' 套件以啟用圖像導出功能:\n\n $ pip install kaleido")
30
-
31
  def load_data(uploaded_file):
32
- """改进的数据加载函数,增加数据验证"""
33
  try:
34
  df = pd.read_csv(uploaded_file, encoding='utf-8').dropna(how='all')
35
 
36
- # 数据验证
37
- required_columns = ['姓名']
38
- for col in required_columns:
39
- if col not in df.columns:
40
- raise ValueError(f"CSV文件中缺少必要欄位:{col}")
41
-
42
- # 动态识别数值列(改进点)
43
  numeric_columns = []
44
  potential_numeric = ['平均', '總分', '國文', '英文', '數學', '自科',
45
  '社會', '地理', '歷史', '公民', '物理', '化學', '生物']
@@ -49,18 +37,18 @@ def load_data(uploaded_file):
49
  df[col] = pd.to_numeric(df[col], errors='coerce')
50
  numeric_columns.append(col)
51
  except:
52
- pass
53
 
54
  if not numeric_columns:
55
- raise ValueError("CSV文件中未找到有效的數值欄位")
56
 
57
  return df, numeric_columns
58
  except Exception as e:
59
  st.error(f"數據加載錯誤:{str(e)}")
60
  return None, None
61
 
 
62
  def create_radar_chart(df, selected_rows, selected_columns, student_name=""):
63
- """改进的雷达图生成函数"""
64
  line_styles = ['solid', 'dot', 'dash', 'longdash', 'dashdot']
65
  colors = ['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728', '#9467BD']
66
 
@@ -83,7 +71,6 @@ def create_radar_chart(df, selected_rows, selected_columns, student_name=""):
83
 
84
  max_value = df[selected_columns].max().max() * 1.1 if selected_columns else 100
85
 
86
- # 统一字体设置
87
  fig.update_layout(
88
  polar=dict(
89
  radialaxis=dict(
@@ -115,27 +102,23 @@ def create_radar_chart(df, selected_rows, selected_columns, student_name=""):
115
  )
116
  return fig
117
 
 
118
  def apply_font_settings(fig):
119
- """强化字体设置"""
120
  fig.update_layout(
121
  font_family=CHINESE_FONT,
122
  title_font_family=CHINESE_FONT,
123
  legend_font_family=CHINESE_FONT
124
  )
125
- fig.update_polars(
126
- angularaxis_tickfont_family=CHINESE_FONT,
127
- radialaxis_tickfont_family=CHINESE_FONT
128
- )
129
  return fig
130
 
 
131
  def generate_radar_image(fig):
132
- """改进的图片生成函数"""
133
- # 配置kaleido的字体设置
134
  pio.kaleido.scope.default_format = "png"
135
  pio.kaleido.scope.default_width = 800
136
  pio.kaleido.scope.default_height = 600
137
  return pio.to_image(fig, format="png", engine="kaleido")
138
 
 
139
  def main():
140
  st.title('學生成績雷達圖產生器')
141
  uploaded_file = st.file_uploader("上傳CSV檔案", type=['csv'])
@@ -144,11 +127,12 @@ def main():
144
  df, numeric_columns = load_data(uploaded_file)
145
 
146
  if df is not None and numeric_columns:
 
147
  st.write("### 選擇要比較的欄位")
148
  selected_columns = st.multiselect(
149
  '選擇科目',
150
  numeric_columns,
151
- default=numeric_columns[:3] # 默认选择前三个
152
  )
153
 
154
  st.write("### 選擇要比較的對象")
@@ -163,15 +147,24 @@ def main():
163
  except Exception as e:
164
  st.error(f"生成雷達圖錯誤:{str(e)}")
165
 
 
166
  st.write("### 批次下載全班學生雷達圖")
167
  comparison_items = st.multiselect("選擇比較基準", all_students)
168
 
169
  if comparison_items:
 
 
 
 
 
 
 
 
170
  progress_bar = st.progress(0)
171
  image_bytes = {}
172
- total_students = len(all_students) - len(comparison_items)
173
-
174
- for idx, student in enumerate(all_students):
175
  if student in comparison_items:
176
  continue
177
 
@@ -184,10 +177,13 @@ def main():
184
  )
185
  fig = apply_font_settings(fig)
186
  image_bytes[student] = generate_radar_image(fig)
 
 
 
 
 
187
  except Exception as e:
188
  st.error(f"生成 {student} 圖表失敗:{str(e)}")
189
-
190
- progress_bar.progress((idx+1)/total_students)
191
 
192
  # 显示预览
193
  cols = st.columns(3)
@@ -197,7 +193,7 @@ def main():
197
  st.caption(f"{student} 與 {', '.join(comparison_items)} 的比較")
198
 
199
  # 打包下载
200
- if st.button("打包下載全部圖表"):
201
  zip_buffer = BytesIO()
202
  with ZipFile(zip_buffer, "w") as zip_file:
203
  for student, img in image_bytes.items():
 
1
  import streamlit as st
2
  import pandas as pd
3
  import plotly.graph_objects as go
 
4
  from zipfile import ZipFile
5
  import plotly.io as pio
6
  from io import BytesIO
 
 
7
 
8
+ # ================== 中文字体配置 ==================
9
  def setup_chinese_font():
 
10
  chinese_fonts = [
11
  "Microsoft JhengHei",
12
  "Noto Sans CJK TC",
 
16
  ]
17
  return ", ".join(chinese_fonts)
18
 
 
19
  CHINESE_FONT = setup_chinese_font()
20
 
21
+ # ================== 数据加载函数 ==================
 
 
 
 
22
  def load_data(uploaded_file):
 
23
  try:
24
  df = pd.read_csv(uploaded_file, encoding='utf-8').dropna(how='all')
25
 
26
+ # 验证必要字段
27
+ if '姓名' not in df.columns:
28
+ raise ValueError("CSV文件中缺少'姓名'欄位")
29
+
30
+ # 动态识别数值列
 
 
31
  numeric_columns = []
32
  potential_numeric = ['平均', '總分', '國文', '英文', '數學', '自科',
33
  '社會', '地理', '歷史', '公民', '物理', '化學', '生物']
 
37
  df[col] = pd.to_numeric(df[col], errors='coerce')
38
  numeric_columns.append(col)
39
  except:
40
+ continue
41
 
42
  if not numeric_columns:
43
+ raise ValueError("未找到有效的數值欄位")
44
 
45
  return df, numeric_columns
46
  except Exception as e:
47
  st.error(f"數據加載錯誤:{str(e)}")
48
  return None, None
49
 
50
+ # ================== 雷达图生成函数 ==================
51
  def create_radar_chart(df, selected_rows, selected_columns, student_name=""):
 
52
  line_styles = ['solid', 'dot', 'dash', 'longdash', 'dashdot']
53
  colors = ['#1F77B4', '#FF7F0E', '#2CA02C', '#D62728', '#9467BD']
54
 
 
71
 
72
  max_value = df[selected_columns].max().max() * 1.1 if selected_columns else 100
73
 
 
74
  fig.update_layout(
75
  polar=dict(
76
  radialaxis=dict(
 
102
  )
103
  return fig
104
 
105
+ # ================== 字体强制设置 ==================
106
  def apply_font_settings(fig):
 
107
  fig.update_layout(
108
  font_family=CHINESE_FONT,
109
  title_font_family=CHINESE_FONT,
110
  legend_font_family=CHINESE_FONT
111
  )
 
 
 
 
112
  return fig
113
 
114
+ # ================== 图片生成函数 ==================
115
  def generate_radar_image(fig):
 
 
116
  pio.kaleido.scope.default_format = "png"
117
  pio.kaleido.scope.default_width = 800
118
  pio.kaleido.scope.default_height = 600
119
  return pio.to_image(fig, format="png", engine="kaleido")
120
 
121
+ # ================== 主程序 ==================
122
  def main():
123
  st.title('學生成績雷達圖產生器')
124
  uploaded_file = st.file_uploader("上傳CSV檔案", type=['csv'])
 
127
  df, numeric_columns = load_data(uploaded_file)
128
 
129
  if df is not None and numeric_columns:
130
+ # ===== 单次比较模式 =====
131
  st.write("### 選擇要比較的欄位")
132
  selected_columns = st.multiselect(
133
  '選擇科目',
134
  numeric_columns,
135
+ default=numeric_columns[:3]
136
  )
137
 
138
  st.write("### 選擇要比較的對象")
 
147
  except Exception as e:
148
  st.error(f"生成雷達圖錯誤:{str(e)}")
149
 
150
+ # ===== 批量下载模式 =====
151
  st.write("### 批次下載全班學生雷達圖")
152
  comparison_items = st.multiselect("選擇比較基準", all_students)
153
 
154
  if comparison_items:
155
+ # 计算有效学生数量
156
+ valid_students = [s for s in all_students if s not in comparison_items]
157
+ total_students = len(valid_students)
158
+
159
+ if total_students == 0:
160
+ st.warning("比較基準已包含所有學生,請至少保留一個非基準學生")
161
+ return
162
+
163
  progress_bar = st.progress(0)
164
  image_bytes = {}
165
+ processed_count = 0
166
+
167
+ for student in all_students:
168
  if student in comparison_items:
169
  continue
170
 
 
177
  )
178
  fig = apply_font_settings(fig)
179
  image_bytes[student] = generate_radar_image(fig)
180
+
181
+ # 更新进度条
182
+ processed_count += 1
183
+ progress_bar.progress(processed_count / total_students)
184
+
185
  except Exception as e:
186
  st.error(f"生成 {student} 圖表失敗:{str(e)}")
 
 
187
 
188
  # 显示预览
189
  cols = st.columns(3)
 
193
  st.caption(f"{student} 與 {', '.join(comparison_items)} 的比較")
194
 
195
  # 打包下载
196
+ if image_bytes:
197
  zip_buffer = BytesIO()
198
  with ZipFile(zip_buffer, "w") as zip_file:
199
  for student, img in image_bytes.items():