fantos commited on
Commit
836a04b
ยท
verified ยท
1 Parent(s): b07ae4e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +39 -74
app.py CHANGED
@@ -5,40 +5,9 @@ from datetime import datetime, timedelta
5
  import requests
6
  from io import BytesIO
7
 
8
- def create_trend_chart(space_id, daily_ranks_df):
9
- if space_id is None or daily_ranks_df.empty:
10
- return None
11
-
12
- try:
13
- space_data = daily_ranks_df[daily_ranks_df['id'] == space_id].copy()
14
- if space_data.empty:
15
- return None
16
-
17
- space_data = space_data.sort_values('date')
18
-
19
- fig = px.line(
20
- space_data,
21
- x='date',
22
- y='rank',
23
- title=f'Daily Rank Trend for {space_id}',
24
- labels={'date': 'Date', 'rank': 'Rank'},
25
- markers=True,
26
- height=500 # ์ˆ˜์ •๋œ ๋ถ€๋ถ„
27
- )
28
-
29
- fig.update_layout(
30
- xaxis_title="Date",
31
- yaxis_title="Rank",
32
- yaxis=dict(
33
- range=[100, 1],
34
- tickmode='linear',import gradio as gr
35
- import pandas as pd
36
- import plotly.express as px
37
- from datetime import datetime, timedelta
38
- import requests
39
- from io import BytesIO
40
 
41
  def create_trend_chart(space_id, daily_ranks_df):
 
42
  if space_id is None or daily_ranks_df.empty:
43
  return None
44
 
@@ -56,7 +25,7 @@ def create_trend_chart(space_id, daily_ranks_df):
56
  title=f'Daily Rank Trend for {space_id}',
57
  labels={'date': 'Date', 'rank': 'Rank'},
58
  markers=True,
59
- height=500 # ํ•„์š”์‹œ ์กฐ์ •
60
  )
61
 
62
  fig.update_layout(
@@ -89,15 +58,16 @@ def create_trend_chart(space_id, daily_ranks_df):
89
  print(f"Error creating chart: {e}")
90
  return None
91
 
 
92
  def get_duplicate_spaces(top_100_spaces):
93
  """
94
- top_100_spaces ์•ˆ์—์„œ username/spacename ํ˜•ํƒœ์˜ id์—์„œ username๋งŒ ๋–ผ์–ด๋‚ธ ํ›„
95
- (clean_id), ํ•ด๋‹น username์— ์†ํ•œ ์—ฌ๋Ÿฌ ์ŠคํŽ˜์ด์Šค ์ ์ˆ˜๋ฅผ ํ•ฉ์‚ฐํ•˜์—ฌ ์ƒ์œ„ 20์„ ์ถ”์ถœ
96
  """
97
- # clean_id ์ถ”์ถœ
98
  top_100_spaces['clean_id'] = top_100_spaces['id'].apply(lambda x: x.split('/')[0])
99
 
100
- # username๋ณ„ ํŠธ๋ Œ๋”ฉ ์Šค์ฝ”์–ด ํ•ฉ์‚ฐ
101
  score_sums = top_100_spaces.groupby('clean_id')['trendingScore'].sum()
102
 
103
  # ๋””๋ฒ„๊น…์šฉ ์ถœ๋ ฅ
@@ -105,15 +75,17 @@ def get_duplicate_spaces(top_100_spaces):
105
  for cid, score in score_sums.sort_values(ascending=False).head(20).items():
106
  print(f"Clean ID: {cid}, Total Score: {score}")
107
 
108
- # ์ƒ์œ„ 20๊ฐœ๋งŒ ์ถ”์ถœ
109
  top_20_scores = score_sums.sort_values(ascending=False).head(20)
110
  return top_20_scores
111
 
 
112
  def create_duplicates_chart(score_sums):
 
113
  if score_sums.empty:
114
  return None
115
 
116
- # ๋ฐ์ดํ„ฐํ”„๋ ˆ์ž„ ์ƒ์„ฑ
117
  df = pd.DataFrame({
118
  'id': score_sums.index,
119
  'total_score': score_sums.values,
@@ -129,7 +101,7 @@ def create_duplicates_chart(score_sums):
129
  x='id',
130
  y='rank',
131
  title="Top 20 Spaces by Combined Trending Score",
132
- height=500, # ํ•„์š”์‹œ ์กฐ์ •
133
  text='total_score'
134
  )
135
 
@@ -140,7 +112,7 @@ def create_duplicates_chart(score_sums):
140
  paper_bgcolor='white',
141
  xaxis_tickangle=-45,
142
  yaxis=dict(
143
- range=[len(df) + 0.5, 0.5], # ์ƒ์œ„ 20๊ฐœ ๊ธฐ์ค€
144
  tickmode='linear',
145
  tick0=1,
146
  dtick=1
@@ -170,7 +142,9 @@ def create_duplicates_chart(score_sums):
170
 
171
  return fig
172
 
 
173
  def update_display(selection):
 
174
  global daily_ranks_df
175
 
176
  if not selection:
@@ -179,9 +153,7 @@ def update_display(selection):
179
  try:
180
  space_id = selection
181
 
182
- latest_data = daily_ranks_df[
183
- daily_ranks_df['id'] == space_id
184
- ].sort_values('date').iloc[-1]
185
 
186
  info_text = f"""
187
  <div style="padding: 16px; background-color: white; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
@@ -201,20 +173,19 @@ def update_display(selection):
201
  """
202
 
203
  chart = create_trend_chart(space_id, daily_ranks_df)
204
-
205
  return chart, gr.HTML(value=info_text)
206
 
207
  except Exception as e:
208
  print(f"Error in update_display: {e}")
209
  return None, gr.HTML(value=f"<div style='color: red;'>Error processing data: {str(e)}</div>")
210
 
 
211
  def load_and_process_data():
212
  """
213
- - spaces.parquet ํŒŒ์ผ์„ ๋กœ๋“œ ํ›„ 30์ผ ์ด๋‚ด ๋ฐ์ดํ„ฐ๋งŒ ํ•„ํ„ฐ๋ง.
214
- - ์ค‘๋ณต ๋ฐฉ์ง€:
215
- 1) (์„ ๏ฟฝ๏ฟฝ) createdAt/ID ๊ธฐ์ค€์œผ๋กœ ์ค‘๋ณต ์ œ๊ฑฐ (๋™์ผ ์‹œ๊ฐ„๋Œ€์— ์—ฌ๋Ÿฌ๋ฒˆ ๊ธฐ๋ก๋œ Space๊ฐ€ ์žˆ์œผ๋ฉด)
216
- 2) ๋‚ ์งœ๋ณ„๋กœ ๋žญํ‚น ์‚ฐ์ • -> daily_ranks_df
217
- 3) ์ตœ์ข… ์ตœ์‹  ๋‚ ์งœ ๊ธฐ์ค€ Top 100 ์ถ”์ถœ ํ›„ ๋™์ผ ID ์ค‘๋ณต ์ œ๊ฑฐ
218
  """
219
  try:
220
  url = "https://huggingface.co/datasets/cfahlgren1/hub-stats/resolve/main/spaces.parquet"
@@ -229,7 +200,6 @@ def load_and_process_data():
229
  df = df[df['createdAt'] >= thirty_days_ago].copy()
230
 
231
  # (์„ ํƒ) createdAt & id ๊ธฐ์ค€ ์ค‘๋ณต ์ œ๊ฑฐ
232
- # ๋งŒ์•ฝ ๋™์ผ createdAt ์‹œ์ ์— ๋™์ผ id๊ฐ€ ์—ฌ๋Ÿฌ ํ–‰์œผ๋กœ ๋“ค์–ด์˜จ ๊ฒฝ์šฐ ๊ฐ€์žฅ ์ตœ์‹ (๋˜๋Š” ๊ฐ€์žฅ ๋†’์€ ์Šค์ฝ”์–ด)๋งŒ ๋‚จ๊น€
233
  df = (
234
  df
235
  .sort_values(['createdAt', 'trendingScore'], ascending=[True, False])
@@ -243,16 +213,11 @@ def load_and_process_data():
243
 
244
  # ๋‚ ์งœ๋ณ„๋กœ rank ๊ณ„์‚ฐ
245
  for date in dates:
246
- # date ๊ธฐ์ค€์œผ๋กœ createdAt์ด date ์ดํ•˜์ธ ์ŠคํŽ˜์ด์Šค๋งŒ ์ถ”์ถœ
247
  date_data = df[df['createdAt'].dt.date <= date.date()].copy()
248
- # trendingScore ๋‚ด๋ฆผ์ฐจ์ˆœ, id ์˜ค๋ฆ„์ฐจ์ˆœ ์ •๋ ฌ
249
  date_data = date_data.sort_values(['trendingScore', 'id'], ascending=[False, True])
250
  date_data['rank'] = range(1, len(date_data) + 1)
251
  date_data['date'] = date.date()
252
-
253
- daily_ranks.append(
254
- date_data[['id', 'date', 'rank', 'trendingScore', 'createdAt']]
255
- )
256
 
257
  # ์ผ์ž๋ณ„ ๋žญํ‚น ๋ฐ์ดํ„ฐ๋ฅผ ํ•ฉ์นจ
258
  daily_ranks_df = pd.concat(daily_ranks, ignore_index=True)
@@ -264,24 +229,26 @@ def load_and_process_data():
264
  (daily_ranks_df['rank'] <= 100)
265
  ].sort_values('rank').copy()
266
 
267
- # ํ˜น์‹œ ์ค‘๋ณต(id๊ฐ€ ๋™์ผ) ํ–‰์ด ์žˆ์„ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ํ•œ ๋ฒˆ ๋” ์ œ๊ฑฐ
268
  top_100_spaces = top_100_spaces.drop_duplicates(subset=['id'], keep='first').reset_index(drop=True)
269
 
270
  return daily_ranks_df, top_100_spaces
 
271
  except Exception as e:
272
  print(f"Error loading data: {e}")
273
  return pd.DataFrame(), pd.DataFrame()
274
 
275
- # ์‹ค์ œ ์‹คํ–‰: ๋ฐ์ดํ„ฐ ๋กœ๋“œ
 
276
  print("Loading initial data...")
277
  daily_ranks_df, top_100_spaces = load_and_process_data()
278
  print("Data loaded successfully!")
279
 
280
- # ์ค‘๋ณต ์ŠคํŽ˜์ด์Šค ๋ฐ์ดํ„ฐ(= ๋™์ผ username์ด ์—ฌ๋Ÿฌ ์ŠคํŽ˜์ด์Šค ์šด์˜)๋ฅผ ๊ณ„์‚ฐ
281
  duplicates = get_duplicate_spaces(top_100_spaces)
282
  duplicates_chart = create_duplicates_chart(duplicates)
283
 
284
- # Gradio ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌ์„ฑ
285
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
286
  gr.Markdown("""
287
  # HF Space Ranking Tracker (~30 Days)
@@ -311,14 +278,14 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
311
  value="<div style='text-align: center; padding: 20px; color: #666;'>Select a space to view details</div>"
312
  )
313
 
314
- # Radio ๋ฒ„ํŠผ์€ ์ˆจ๊ฒจ๋‘๊ณ , ์นด๋“œ ํด๋ฆญ์œผ๋กœ ์„ ํƒํ•˜๋„๋ก ๊ตฌ์„ฑ
315
  space_selection = gr.Radio(
316
  choices=[row['id'] for _, row in top_100_spaces.iterrows()],
317
  value=None,
318
  visible=False
319
  )
320
 
321
- # Top 100์„ ์นด๋“œ ํ˜•ํƒœ๋กœ ํ‘œ์‹œ
322
  html_content = """
323
  <div style='display: flex; flex-wrap: wrap; gap: 16px; justify-content: center;'>
324
  """ + "".join([
@@ -369,7 +336,7 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
369
  </div>
370
  <script>
371
  function gradioEvent(spaceId) {
372
- // Radio ๋ฒ„ํŠผ ์ค‘์—์„œ ํ•ด๋‹น value๋ฅผ ๊ฐ€์ง„ ํ•ญ๋ชฉ์„ ์ฐพ์•„ ์„ ํƒ ์ด๋ฒคํŠธ ๋ฐœ์ƒ
373
  const radio = document.querySelector(`input[type="radio"][value="${spaceId}"]`);
374
  if (radio) {
375
  radio.checked = true;
@@ -387,13 +354,13 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
387
  gr.Markdown("""
388
  ### Our Tracking System
389
 
390
- #### What We Track
391
  - Daily ranking changes for all Hugging Face Spaces
392
  - Comprehensive trending scores based on 30-day activity
393
  - Detailed performance metrics for top 100 Spaces
394
  - Historical ranking data with daily granularity
395
 
396
- #### Key Features
397
  - **Real-time Rankings**: Stay updated with daily rank changes
398
  - **Interactive Visualizations**: Track ranking trajectories over time
399
  - **Trend Analysis**: Identify emerging popular AI applications
@@ -407,16 +374,14 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
407
  - Make data-driven decisions about your AI projects
408
  - Stay ahead of the curve in AI application development
409
 
410
- Our dashboard provides a comprehensive view of the Hugging Face Spaces ecosystem,
411
- helping developers, researchers, and enthusiasts track and understand the dynamics of popular AI applications.
412
- Whether you're monitoring your own Space's performance or discovering new trending applications,
413
- HF Space Ranking Tracker offers the insights you need.
414
 
415
- Experience the pulse of the AI community through our daily updated rankings and discover
416
- what's making waves in the world of practical AI applications.
417
  """)
418
-
419
- # ์ŠคํŽ˜์ด์Šค ์„ ํƒ์‹œ ์ฐจํŠธ/์ •๋ณด ์—…๋ฐ์ดํŠธ
420
  space_selection.change(
421
  fn=update_display,
422
  inputs=[space_selection],
 
5
  import requests
6
  from io import BytesIO
7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
 
9
  def create_trend_chart(space_id, daily_ranks_df):
10
+ """๋ผ์ธ ์ฐจํŠธ ์ƒ์„ฑ ํ•จ์ˆ˜"""
11
  if space_id is None or daily_ranks_df.empty:
12
  return None
13
 
 
25
  title=f'Daily Rank Trend for {space_id}',
26
  labels={'date': 'Date', 'rank': 'Rank'},
27
  markers=True,
28
+ height=500
29
  )
30
 
31
  fig.update_layout(
 
58
  print(f"Error creating chart: {e}")
59
  return None
60
 
61
+
62
  def get_duplicate_spaces(top_100_spaces):
63
  """
64
+ ๋™์ผ username(๋˜๋Š” organization) ์•„๋ž˜ ์—ฌ๋Ÿฌ ์ŠคํŽ˜์ด์Šค๊ฐ€ ์˜ฌ๋ผ์˜จ ๊ฒฝ์šฐ
65
+ ๊ฐ๊ฐ์˜ trendingScore๋ฅผ ํ•ฉ์‚ฐํ•œ ๋’ค ์ƒ์œ„ 20๋ช…์„ ๋ฝ‘๋Š” ํ•จ์ˆ˜
66
  """
67
+ # username/spacename -> username๋งŒ ์ถ”์ถœ
68
  top_100_spaces['clean_id'] = top_100_spaces['id'].apply(lambda x: x.split('/')[0])
69
 
70
+ # clean_id๋ณ„ ํŠธ๋ Œ๋”ฉ ์Šค์ฝ”์–ด ํ•ฉ์‚ฐ
71
  score_sums = top_100_spaces.groupby('clean_id')['trendingScore'].sum()
72
 
73
  # ๋””๋ฒ„๊น…์šฉ ์ถœ๋ ฅ
 
75
  for cid, score in score_sums.sort_values(ascending=False).head(20).items():
76
  print(f"Clean ID: {cid}, Total Score: {score}")
77
 
78
+ # ์ƒ์œ„ 20๊ฐœ ์ถ”์ถœ
79
  top_20_scores = score_sums.sort_values(ascending=False).head(20)
80
  return top_20_scores
81
 
82
+
83
  def create_duplicates_chart(score_sums):
84
+ """์ค‘๋ณต(๋˜๋Š” ์—ฌ๋Ÿฌ Spaces ์šด์˜) ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ํ•ฉ์‚ฐ ์ฐจํŠธ ์ƒ์„ฑ"""
85
  if score_sums.empty:
86
  return None
87
 
88
+ # ์‹œ๊ฐํ™”๋ฅผ ์œ„ํ•œ DataFrame ์ƒ์„ฑ
89
  df = pd.DataFrame({
90
  'id': score_sums.index,
91
  'total_score': score_sums.values,
 
101
  x='id',
102
  y='rank',
103
  title="Top 20 Spaces by Combined Trending Score",
104
+ height=500,
105
  text='total_score'
106
  )
107
 
 
112
  paper_bgcolor='white',
113
  xaxis_tickangle=-45,
114
  yaxis=dict(
115
+ range=[len(df) + 0.5, 0.5],
116
  tickmode='linear',
117
  tick0=1,
118
  dtick=1
 
142
 
143
  return fig
144
 
145
+
146
  def update_display(selection):
147
+ """์‚ฌ์šฉ์ž๊ฐ€ Space๋ฅผ ์„ ํƒํ–ˆ์„ ๋•Œ, ์ƒ์„ธ ์ •๋ณด์™€ ํŠธ๋ Œ๋“œ ์ฐจํŠธ๋ฅผ ์—…๋ฐ์ดํŠธ"""
148
  global daily_ranks_df
149
 
150
  if not selection:
 
153
  try:
154
  space_id = selection
155
 
156
+ latest_data = daily_ranks_df[daily_ranks_df['id'] == space_id].sort_values('date').iloc[-1]
 
 
157
 
158
  info_text = f"""
159
  <div style="padding: 16px; background-color: white; border-radius: 8px; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">
 
173
  """
174
 
175
  chart = create_trend_chart(space_id, daily_ranks_df)
 
176
  return chart, gr.HTML(value=info_text)
177
 
178
  except Exception as e:
179
  print(f"Error in update_display: {e}")
180
  return None, gr.HTML(value=f"<div style='color: red;'>Error processing data: {str(e)}</div>")
181
 
182
+
183
  def load_and_process_data():
184
  """
185
+ - Parquet ํŒŒ์ผ ๋กœ๋“œ ํ›„ 30์ผ ์ด๋‚ด ๋ฐ์ดํ„ฐ๋งŒ ํ•„ํ„ฐ๋ง
186
+ - (์„ ํƒ) createdAt + id ๊ธฐ์ค€ ์ค‘๋ณต ์ œ๊ฑฐ
187
+ - ๋‚ ์งœ๋ณ„ ranking ์‚ฐ์ • -> daily_ranks_df ๊ตฌ์„ฑ
188
+ - ์ตœ์‹  ๋‚ ์งœ ๊ธฐ์ค€ top 100 ์ถ”์ถœ ํ›„ id ์ค‘๋ณต ์ œ๊ฑฐ
 
189
  """
190
  try:
191
  url = "https://huggingface.co/datasets/cfahlgren1/hub-stats/resolve/main/spaces.parquet"
 
200
  df = df[df['createdAt'] >= thirty_days_ago].copy()
201
 
202
  # (์„ ํƒ) createdAt & id ๊ธฐ์ค€ ์ค‘๋ณต ์ œ๊ฑฐ
 
203
  df = (
204
  df
205
  .sort_values(['createdAt', 'trendingScore'], ascending=[True, False])
 
213
 
214
  # ๋‚ ์งœ๋ณ„๋กœ rank ๊ณ„์‚ฐ
215
  for date in dates:
 
216
  date_data = df[df['createdAt'].dt.date <= date.date()].copy()
 
217
  date_data = date_data.sort_values(['trendingScore', 'id'], ascending=[False, True])
218
  date_data['rank'] = range(1, len(date_data) + 1)
219
  date_data['date'] = date.date()
220
+ daily_ranks.append(date_data[['id', 'date', 'rank', 'trendingScore', 'createdAt']])
 
 
 
221
 
222
  # ์ผ์ž๋ณ„ ๋žญํ‚น ๋ฐ์ดํ„ฐ๋ฅผ ํ•ฉ์นจ
223
  daily_ranks_df = pd.concat(daily_ranks, ignore_index=True)
 
229
  (daily_ranks_df['rank'] <= 100)
230
  ].sort_values('rank').copy()
231
 
232
+ # id ๊ธฐ์ค€ ์ค‘๋ณต ์ œ๊ฑฐ
233
  top_100_spaces = top_100_spaces.drop_duplicates(subset=['id'], keep='first').reset_index(drop=True)
234
 
235
  return daily_ranks_df, top_100_spaces
236
+
237
  except Exception as e:
238
  print(f"Error loading data: {e}")
239
  return pd.DataFrame(), pd.DataFrame()
240
 
241
+
242
+ # ๋ฉ”์ธ ์‹คํ–‰
243
  print("Loading initial data...")
244
  daily_ranks_df, top_100_spaces = load_and_process_data()
245
  print("Data loaded successfully!")
246
 
247
+ # ์ค‘๋ณต(์—ฌ๋Ÿฌ Space) ์šด์˜ ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ๋ฐ์ดํ„ฐ ๊ณ„์‚ฐ
248
  duplicates = get_duplicate_spaces(top_100_spaces)
249
  duplicates_chart = create_duplicates_chart(duplicates)
250
 
251
+ # Gradio ์•ฑ ์ƒ์„ฑ
252
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
253
  gr.Markdown("""
254
  # HF Space Ranking Tracker (~30 Days)
 
278
  value="<div style='text-align: center; padding: 20px; color: #666;'>Select a space to view details</div>"
279
  )
280
 
281
+ # Radio ๋ฒ„ํŠผ์€ ์ˆจ๊น€. ์•„๋ž˜ ์นด๋“œ ํด๋ฆญ์œผ๋กœ ์„ ํƒํ•˜๋„๋ก ์œ ๋„
282
  space_selection = gr.Radio(
283
  choices=[row['id'] for _, row in top_100_spaces.iterrows()],
284
  value=None,
285
  visible=False
286
  )
287
 
288
+ # Top 100 ์ŠคํŽ˜์ด์Šค๋ฅผ ์นด๋“œ ํ˜•ํƒœ๋กœ ํ‘œ์‹œ
289
  html_content = """
290
  <div style='display: flex; flex-wrap: wrap; gap: 16px; justify-content: center;'>
291
  """ + "".join([
 
336
  </div>
337
  <script>
338
  function gradioEvent(spaceId) {
339
+ // Space ์นด๋“œ ๋‚ด "View Trend" ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ, ๋Œ€์‘๋˜๋Š” Radio ํ•ญ๋ชฉ ์„ ํƒ ์ด๋ฒคํŠธ ๋ฐœ์ƒ
340
  const radio = document.querySelector(`input[type="radio"][value="${spaceId}"]`);
341
  if (radio) {
342
  radio.checked = true;
 
354
  gr.Markdown("""
355
  ### Our Tracking System
356
 
357
+ **What We Track**
358
  - Daily ranking changes for all Hugging Face Spaces
359
  - Comprehensive trending scores based on 30-day activity
360
  - Detailed performance metrics for top 100 Spaces
361
  - Historical ranking data with daily granularity
362
 
363
+ **Key Features**
364
  - **Real-time Rankings**: Stay updated with daily rank changes
365
  - **Interactive Visualizations**: Track ranking trajectories over time
366
  - **Trend Analysis**: Identify emerging popular AI applications
 
374
  - Make data-driven decisions about your AI projects
375
  - Stay ahead of the curve in AI application development
376
 
377
+ Our dashboard provides a comprehensive view of the Hugging Face Spaces ecosystem,
378
+ helping developers, researchers, and enthusiasts track and understand the dynamics of popular AI applications.
 
 
379
 
380
+ Whether you're monitoring your own Space's performance or discovering new trending applications,
381
+ HF Space Ranking Tracker offers the insights you need.
382
  """)
383
+
384
+ # ์‚ฌ์šฉ์ž ์„ ํƒ์‹œ(=Radio.value ๋ณ€๊ฒฝ ์‹œ) update_display ํ˜ธ์ถœ
385
  space_selection.change(
386
  fn=update_display,
387
  inputs=[space_selection],