JUNGU commited on
Commit
f5b5cdc
ยท
verified ยท
1 Parent(s): 8702770

Update src/streamlit_app.py

Browse files
Files changed (1) hide show
  1. src/streamlit_app.py +103 -43
src/streamlit_app.py CHANGED
@@ -9,62 +9,76 @@ import os
9
  import matplotlib.font_manager as fm
10
 
11
  def set_korean_font():
12
- """ํ•œ๊ธ€ ํฐํŠธ ์„ค์ • ํ•จ์ˆ˜ - ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์œผ๋กœ ์‹œ๋„"""
13
 
14
- # 1. ์‹œ์Šคํ…œ ๊ธฐ๋ณธ ํ•œ๊ธ€ ํฐํŠธ ์ฐพ๊ธฐ
15
- available_fonts = [f.name for f in fm.fontManager.ttflist]
16
- korean_fonts = [
17
- 'NanumGothic', 'NanumBarunGothic', 'NanumSquare',
18
- 'Malgun Gothic', 'AppleGothic', 'Noto Sans CJK KR',
19
- 'DejaVu Sans', 'Arial Unicode MS'
20
- ]
21
 
22
- selected_font = None
23
-
24
- # 2. ์‚ฌ์šฉ์ž ์ง€์ • ํฐํŠธ ํŒŒ์ผ ํ™•์ธ
25
  font_filename = "NanumGaRamYeonGgoc.ttf"
26
  font_path = os.path.join(os.getcwd(), font_filename)
 
27
 
28
  if os.path.exists(font_path):
29
  try:
 
 
30
  # ํฐํŠธ ํŒŒ์ผ์„ ์‹œ์Šคํ…œ์— ๋“ฑ๋ก
31
  fm.fontManager.addfont(font_path)
32
  font_prop = fm.FontProperties(fname=font_path)
33
  selected_font = font_prop.get_name()
34
- plt.rcParams['font.family'] = selected_font
35
  st.sidebar.success(f"์‚ฌ์šฉ์ž ํฐํŠธ '{selected_font}' ๋กœ๋”ฉ ์„ฑ๊ณต!")
36
  except Exception as e:
37
  st.sidebar.warning(f"์‚ฌ์šฉ์ž ํฐํŠธ ๋กœ๋”ฉ ์‹คํŒจ: {e}")
38
 
39
- # 3. ์‹œ์Šคํ…œ ํฐํŠธ์—์„œ ํ•œ๊ธ€ ํฐํŠธ ์ฐพ๊ธฐ
40
  if not selected_font:
41
- for font in korean_fonts:
42
- if font in available_fonts:
43
- selected_font = font
44
- plt.rcParams['font.family'] = font
45
- st.sidebar.info(f"์‹œ์Šคํ…œ ํฐํŠธ '{font}' ์‚ฌ์šฉ ์ค‘")
46
- break
 
 
 
 
 
 
 
 
 
 
 
47
 
48
- # 4. ๋ชจ๋“  ๋ฐฉ๋ฒ•์ด ์‹คํŒจํ•œ ๊ฒฝ์šฐ ๊ธฐ๋ณธ ์„ค์ •
49
  if not selected_font:
50
- # ์šด์˜์ฒด์ œ๋ณ„ ๊ธฐ๋ณธ ์„ค์ •
51
  if platform.system() == 'Windows':
52
- plt.rcParams['font.family'] = 'Malgun Gothic'
53
  elif platform.system() == 'Darwin': # macOS
54
- plt.rcParams['font.family'] = 'AppleGothic'
55
- else: # Linux
56
- plt.rcParams['font.family'] = 'DejaVu Sans'
57
 
58
- st.sidebar.warning(
59
- f"ํ•œ๊ธ€ ํฐํŠธ๋ฅผ ์ฐพ์„ ์ˆ˜ ์—†์–ด ๊ธฐ๋ณธ ํฐํŠธ๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.\n"
60
- f"'{font_filename}' ํŒŒ์ผ์„ ์•ฑ๊ณผ ๊ฐ™์€ ํด๋”์— ๋„ฃ์œผ๋ฉด ๋” ์ข‹์€ ํ•œ๊ธ€ ํ‘œ์‹œ๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค."
61
- )
 
 
 
 
 
 
 
 
 
 
 
62
 
63
- # ๋งˆ์ด๋„ˆ์Šค ๊ธฐํ˜ธ ๊นจ์ง ๋ฐฉ์ง€
64
- plt.rcParams['axes.unicode_minus'] = False
65
 
66
- # ํ˜„์žฌ ์„ค์ •๋œ ํฐํŠธ ์ •๋ณด ํ‘œ์‹œ
67
- st.sidebar.text(f"ํ˜„์žฌ ํฐํŠธ: {plt.rcParams['font.family']}")
68
 
69
  def analyze_scores(df):
70
  """๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์„ ๋ฐ›์•„ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ํ•จ์ˆ˜"""
@@ -95,22 +109,52 @@ def analyze_scores(df):
95
 
96
  # 2. ๋ถ„ํฌ ์‹œ๊ฐํ™”
97
  st.write("#### ๐ŸŽจ ์ ์ˆ˜ ๋ถ„ํฌ ์‹œ๊ฐํ™”")
98
- fig, ax = plt.subplots(figsize=(10, 6))
 
 
 
 
 
 
 
99
 
100
  try:
101
- sns.histplot(scores, kde=True, stat='density', label='ํ•™์ƒ ์ ์ˆ˜ ๋ถ„ํฌ', ax=ax)
 
 
 
102
  mu, std = norm.fit(scores)
103
  xmin, xmax = ax.get_xlim()
104
  x = np.linspace(xmin, xmax, 100)
105
  p = norm.pdf(x, mu, std)
106
- ax.plot(x, p, 'k', linewidth=2, label='์ •๊ทœ๋ถ„ํฌ ๊ณก์„ ')
107
- ax.set_title(f"'{score_column}' ์ ์ˆ˜ ๋ถ„ํฌ (ํ‰๊ท : {mu:.2f}, ํ‘œ์ค€ํŽธ์ฐจ: {std:.2f})")
108
- ax.set_xlabel('์ ์ˆ˜')
109
- ax.set_ylabel('๋ฐ€๋„')
110
- ax.legend()
 
 
 
 
 
 
 
 
 
 
 
111
  st.pyplot(fig)
 
112
  except Exception as e:
113
  st.error(f"๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}")
 
 
 
 
 
 
 
 
114
  finally:
115
  plt.close(fig) # ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€
116
 
@@ -136,11 +180,27 @@ def main():
136
  layout="wide"
137
  )
138
 
139
- # ํฐํŠธ ์„ค์ •์„ ๋จผ์ € ์‹คํ–‰
140
- set_korean_font()
141
 
142
  st.title("ํ•™์ƒ ์ ์ˆ˜ ๋ถ„ํฌ ๋ถ„์„ ๋„๊ตฌ ๐Ÿ“Š")
143
  st.write("CSV ํŒŒ์ผ์„ ์ง์ ‘ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜ Google Sheets URL์„ ๋ถ™์—ฌ๋„ฃ์–ด ํ•™์ƒ ์ ์ˆ˜ ๋ถ„ํฌ๋ฅผ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  st.write("---")
145
 
146
  st.sidebar.title("๐Ÿ“ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ")
@@ -177,7 +237,7 @@ def main():
177
 
178
  elif source_option == "Google Sheets URL":
179
  st.sidebar.info("Google Sheets๋ฅผ '์›น์— ๊ฒŒ์‹œ'ํ•˜๊ณ  CSV ํ˜•์‹์˜ URL์„ ์ž…๋ ฅํ•˜์„ธ์š”.")
180
- sample_url = "https://docs.google.com/spreadsheets/d/e/2PACX-1vSGdxUwlxDVZXlqFJtLMPcZbKt_B3qBAUSj-hO-EwnG25iQRR3wxWVT9X54a1XkhBVw-BSEIXfeWKg6/pub?gid=966112810&single=true&output=csv"
181
  url = st.sidebar.text_input(
182
  "Google Sheets CSV URL",
183
  value="",
 
9
  import matplotlib.font_manager as fm
10
 
11
  def set_korean_font():
12
+ """ํ•œ๊ธ€ ํฐํŠธ ์„ค์ • ํ•จ์ˆ˜ - ๊ฐ•์ œ๋กœ ํฐํŠธ ์ ์šฉ"""
13
 
14
+ # matplotlib ์บ์‹œ ํด๋ฆฌ์–ด (์ค‘์š”!)
15
+ plt.rcdefaults()
 
 
 
 
 
16
 
17
+ # 1. ์‚ฌ์šฉ์ž ์ง€์ • ํฐํŠธ ํŒŒ์ผ ํ™•์ธ
 
 
18
  font_filename = "NanumGaRamYeonGgoc.ttf"
19
  font_path = os.path.join(os.getcwd(), font_filename)
20
+ selected_font = None
21
 
22
  if os.path.exists(font_path):
23
  try:
24
+ # ํฐํŠธ ๋งค๋‹ˆ์ € ์บ์‹œ ํด๋ฆฌ์–ด
25
+ fm.fontManager.__init__()
26
  # ํฐํŠธ ํŒŒ์ผ์„ ์‹œ์Šคํ…œ์— ๋“ฑ๋ก
27
  fm.fontManager.addfont(font_path)
28
  font_prop = fm.FontProperties(fname=font_path)
29
  selected_font = font_prop.get_name()
 
30
  st.sidebar.success(f"์‚ฌ์šฉ์ž ํฐํŠธ '{selected_font}' ๋กœ๋”ฉ ์„ฑ๊ณต!")
31
  except Exception as e:
32
  st.sidebar.warning(f"์‚ฌ์šฉ์ž ํฐํŠธ ๋กœ๋”ฉ ์‹คํŒจ: {e}")
33
 
34
+ # 2. ์‹œ์Šคํ…œ์—์„œ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํ•œ๊ธ€ ํฐํŠธ ์ฐพ๊ธฐ
35
  if not selected_font:
36
+ # ์‹ค์ œ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ํฐํŠธ๋“ค ์ฒดํฌ
37
+ system_fonts = fm.findSystemFonts()
38
+ korean_font_candidates = []
39
+
40
+ for font_path in system_fonts:
41
+ try:
42
+ font_name = fm.FontProperties(fname=font_path).get_name()
43
+ # ํ•œ๊ธ€ ํฐํŠธ ํ›„๋ณด๋“ค
44
+ if any(keyword in font_name.lower() for keyword in
45
+ ['nanum', 'malgun', 'gothic', 'gulim', 'dotum', 'batang']):
46
+ korean_font_candidates.append(font_name)
47
+ except:
48
+ continue
49
+
50
+ if korean_font_candidates:
51
+ selected_font = korean_font_candidates[0]
52
+ st.sidebar.info(f"์‹œ์Šคํ…œ ํ•œ๊ธ€ ํฐํŠธ '{selected_font}' ๋ฐœ๊ฒฌ!")
53
 
54
+ # 3. ์šด์˜์ฒด์ œ๋ณ„ ๊ธฐ๋ณธ ํฐํŠธ ์„ค์ •
55
  if not selected_font:
 
56
  if platform.system() == 'Windows':
57
+ selected_font = 'Malgun Gothic'
58
  elif platform.system() == 'Darwin': # macOS
59
+ selected_font = 'AppleGothic'
60
+ else: # Linux - ๋‚˜๋ˆ”ํฐํŠธ๊ฐ€ ์—†์œผ๋ฉด ๊ธฐ๋ณธ Sans ์‚ฌ์šฉ
61
+ selected_font = 'sans-serif'
62
 
63
+ st.sidebar.warning(f"๊ธฐ๋ณธ ํฐํŠธ '{selected_font}' ์‚ฌ์šฉ")
64
+
65
+ # 4. matplotlib ์„ค์ • ๊ฐ•์ œ ์ ์šฉ
66
+ plt.rcParams.update({
67
+ 'font.family': selected_font,
68
+ 'font.sans-serif': [selected_font, 'DejaVu Sans', 'Arial'],
69
+ 'axes.unicode_minus': False,
70
+ 'font.size': 10
71
+ })
72
+
73
+ # 5. ํฐํŠธ ์„ค์ • ๊ฒ€์ฆ
74
+ test_fig, test_ax = plt.subplots(figsize=(1, 1))
75
+ test_ax.text(0.5, 0.5, 'ํ•œ๊ธ€ํ…Œ์ŠคํŠธ', ha='center', va='center')
76
+ current_font = test_ax.texts[0].get_fontname()
77
+ plt.close(test_fig)
78
 
79
+ st.sidebar.text(f"์ ์šฉ๋œ ํฐํŠธ: {current_font}")
 
80
 
81
+ return selected_font
 
82
 
83
  def analyze_scores(df):
84
  """๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„์„ ๋ฐ›์•„ ๋ถ„์„ ๊ฒฐ๊ณผ๋ฅผ ํ‘œ์‹œํ•˜๋Š” ํ•จ์ˆ˜"""
 
109
 
110
  # 2. ๋ถ„ํฌ ์‹œ๊ฐํ™”
111
  st.write("#### ๐ŸŽจ ์ ์ˆ˜ ๋ถ„ํฌ ์‹œ๊ฐํ™”")
112
+
113
+ # ๋งค๋ฒˆ ์ƒˆ๋กœ์šด figure ์ƒ์„ฑ ์‹œ ํฐํŠธ ์„ค์ • ์žฌ์ ์šฉ
114
+ plt.rcParams.update({
115
+ 'font.family': plt.rcParams.get('font.family', 'sans-serif'),
116
+ 'axes.unicode_minus': False
117
+ })
118
+
119
+ fig, ax = plt.subplots(figsize=(12, 7))
120
 
121
  try:
122
+ # ํžˆ์Šคํ† ๊ทธ๋žจ๊ณผ KDE ๊ณก์„  ๊ทธ๋ฆฌ๊ธฐ
123
+ sns.histplot(scores, kde=True, stat='density', alpha=0.7, ax=ax)
124
+
125
+ # ์ •๊ทœ๋ถ„ํฌ ๊ณก์„  ์ถ”๊ฐ€
126
  mu, std = norm.fit(scores)
127
  xmin, xmax = ax.get_xlim()
128
  x = np.linspace(xmin, xmax, 100)
129
  p = norm.pdf(x, mu, std)
130
+ ax.plot(x, p, 'r-', linewidth=2, label=f'์ •๊ทœ๋ถ„ํฌ (ฮผ={mu:.1f}, ฯƒ={std:.1f})')
131
+
132
+ # ์ œ๋ชฉ๊ณผ ๋ผ๋ฒจ ์„ค์ • (ํ•œ๊ธ€ ํฌํ•จ)
133
+ ax.set_title(f'{score_column} ์ ์ˆ˜ ๋ถ„ํฌ ๋ถ„์„', fontsize=16, pad=20)
134
+ ax.set_xlabel('์ ์ˆ˜', fontsize=12)
135
+ ax.set_ylabel('๋ฐ€๋„', fontsize=12)
136
+ ax.legend(fontsize=10)
137
+ ax.grid(True, alpha=0.3)
138
+
139
+ # ํ†ต๊ณ„ ์ •๋ณด ํ…์ŠคํŠธ ๋ฐ•์Šค ์ถ”๊ฐ€
140
+ stats_text = f'ํ‰๊ท : {mu:.2f}\nํ‘œ์ค€ํŽธ์ฐจ: {std:.2f}\n์ƒ˜ํ”Œ ์ˆ˜: {len(scores)}'
141
+ ax.text(0.02, 0.98, stats_text, transform=ax.transAxes,
142
+ fontsize=10, verticalalignment='top',
143
+ bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.8))
144
+
145
+ plt.tight_layout()
146
  st.pyplot(fig)
147
+
148
  except Exception as e:
149
  st.error(f"๊ทธ๋ž˜ํ”„ ์ƒ์„ฑ ์ค‘ ์˜ค๋ฅ˜ ๋ฐœ์ƒ: {e}")
150
+ # ์—๋Ÿฌ ๋ฐœ์ƒ ์‹œ ๊ฐ„๋‹จํ•œ ํžˆ์Šคํ† ๊ทธ๋žจ์œผ๋กœ ๋Œ€์ฒด
151
+ fig2, ax2 = plt.subplots(figsize=(10, 6))
152
+ ax2.hist(scores, bins=20, alpha=0.7, edgecolor='black')
153
+ ax2.set_title('Score Distribution (Fallback)', fontsize=14)
154
+ ax2.set_xlabel('Score')
155
+ ax2.set_ylabel('Frequency')
156
+ st.pyplot(fig2)
157
+ plt.close(fig2)
158
  finally:
159
  plt.close(fig) # ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐฉ์ง€
160
 
 
180
  layout="wide"
181
  )
182
 
183
+ # ํฐํŠธ ์„ค์ •์„ ๋จผ์ € ์‹คํ–‰ํ•˜๊ณ  ์„ค์ •๋œ ํฐํŠธ๋ช… ๋ฐ›๊ธฐ
184
+ selected_font = set_korean_font()
185
 
186
  st.title("ํ•™์ƒ ์ ์ˆ˜ ๋ถ„ํฌ ๋ถ„์„ ๋„๊ตฌ ๐Ÿ“Š")
187
  st.write("CSV ํŒŒ์ผ์„ ์ง์ ‘ ์—…๋กœ๋“œํ•˜๊ฑฐ๋‚˜ Google Sheets URL์„ ๋ถ™์—ฌ๋„ฃ์–ด ํ•™์ƒ ์ ์ˆ˜ ๋ถ„ํฌ๋ฅผ ๋ถ„์„ํ•ฉ๋‹ˆ๋‹ค.")
188
+
189
+ # ํฐํŠธ ํ…Œ์ŠคํŠธ (๋””๋ฒ„๊น…์šฉ)
190
+ if st.sidebar.checkbox("ํฐํŠธ ํ…Œ์ŠคํŠธ ๋ณด๊ธฐ"):
191
+ test_fig, test_ax = plt.subplots(figsize=(8, 4))
192
+ test_ax.text(0.5, 0.7, f'ํ•œ๊ธ€ ํฐํŠธ ํ…Œ์ŠคํŠธ: {selected_font}',
193
+ ha='center', va='center', fontsize=14)
194
+ test_ax.text(0.5, 0.5, '๊ฐ€๋‚˜๋‹ค๋ผ๋งˆ๋ฐ”์‚ฌ ABCD 1234',
195
+ ha='center', va='center', fontsize=12)
196
+ test_ax.text(0.5, 0.3, '์ ์ˆ˜, ๋ถ„ํฌ, ๋ถ„์„, ๊ทธ๋ž˜ํ”„',
197
+ ha='center', va='center', fontsize=12)
198
+ test_ax.set_xlim(0, 1)
199
+ test_ax.set_ylim(0, 1)
200
+ test_ax.axis('off')
201
+ st.pyplot(test_fig)
202
+ plt.close(test_fig)
203
+
204
  st.write("---")
205
 
206
  st.sidebar.title("๐Ÿ“ ๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ")
 
237
 
238
  elif source_option == "Google Sheets URL":
239
  st.sidebar.info("Google Sheets๋ฅผ '์›น์— ๊ฒŒ์‹œ'ํ•˜๊ณ  CSV ํ˜•์‹์˜ URL์„ ์ž…๋ ฅํ•˜์„ธ์š”.")
240
+ sample_url = "https://docs.google.com/spreadsheets/d/e/2PACX-1vQ2Z8kzJq2sM7w2_9gXo-jZ-mO5o-BvC-w5p2nJ6oJ7oJ9xL-w3kZ9j5Z3kX7vN1aQ4mB1cW8jB7fR/pub?gid=0&single=true&output=csv"
241
  url = st.sidebar.text_input(
242
  "Google Sheets CSV URL",
243
  value="",