Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -138,17 +138,311 @@ combined_chart1 = alt.hconcat(
|
|
138 |
)
|
139 |
combined_chart1
|
140 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
141 |
chart1_panel = pn.pane.Vega(chart1, sizing_mode='stretch_width')
|
142 |
chart2_panel = pn.pane.Vega(chart2, sizing_mode='stretch_width')
|
|
|
|
|
|
|
143 |
|
144 |
dashboard = pn.Column(
|
145 |
"# My Interactive Dashboard", # 可以添加标题
|
146 |
chart1_panel,
|
147 |
chart2_panel
|
|
|
|
|
148 |
)
|
149 |
|
150 |
# 设置应用程序为可服务的
|
151 |
-
dashboard.servable(title='
|
152 |
|
153 |
# 如果你运行这个脚本,那么调用以下命令可以在本地启动服务器
|
154 |
if __name__.startswith('bokeh'):
|
|
|
138 |
)
|
139 |
combined_chart1
|
140 |
|
141 |
+
match_id = 2576335
|
142 |
+
a_match = []
|
143 |
+
for nation in nations:
|
144 |
+
for ev in events[nation]:
|
145 |
+
if ev['matchId'] == match_id:
|
146 |
+
a_match.append(ev)
|
147 |
+
|
148 |
+
for nation in nations:
|
149 |
+
for match in matches[nation]:
|
150 |
+
if match['wyId'] == match_id:
|
151 |
+
match_f = match
|
152 |
+
|
153 |
+
df_a_match = pd.DataFrame(a_match)
|
154 |
+
|
155 |
+
background_data = pd.DataFrame({
|
156 |
+
'x': [0],
|
157 |
+
'y': [0],
|
158 |
+
'x2': [100],
|
159 |
+
'y2': [100]
|
160 |
+
})
|
161 |
+
|
162 |
+
# Create the background
|
163 |
+
background = alt.Chart(background_data).mark_rect(
|
164 |
+
color='#195905'
|
165 |
+
).encode(
|
166 |
+
x='x:Q',
|
167 |
+
y='y:Q',
|
168 |
+
x2='x2:Q',
|
169 |
+
y2='y2:Q'
|
170 |
+
)
|
171 |
+
|
172 |
+
|
173 |
+
#Define the center circle
|
174 |
+
center_circle = alt.Chart(pd.DataFrame({'x': [50], 'y': [50]})).mark_point(
|
175 |
+
size=12000,
|
176 |
+
color='white',
|
177 |
+
strokeWidth=3
|
178 |
+
).encode(
|
179 |
+
x='x:Q',
|
180 |
+
y='y:Q'
|
181 |
+
)
|
182 |
+
|
183 |
+
|
184 |
+
# Create the border lines
|
185 |
+
border_lines_data = pd.DataFrame({
|
186 |
+
'x': [1, 1, 99.5, 99.5, 1],
|
187 |
+
'y': [1, 99.5, 99.5, 1, 1],
|
188 |
+
'x2': [1, 99.5, 99.5, 1, 1],
|
189 |
+
'y2': [99.5, 99.5, 1, 1, 1]
|
190 |
+
})
|
191 |
+
|
192 |
+
|
193 |
+
border_lines = alt.Chart(border_lines_data).mark_line(
|
194 |
+
color='white',
|
195 |
+
strokeWidth=3
|
196 |
+
).encode(
|
197 |
+
x=alt.X('x:Q', scale=alt.Scale(domain=[1, 99.5])),
|
198 |
+
y=alt.Y('y:Q', scale=alt.Scale(domain=[1, 99.5])),
|
199 |
+
x2='x2:Q',
|
200 |
+
y2='y2:Q'
|
201 |
+
)
|
202 |
+
|
203 |
+
midline_data = pd.DataFrame({
|
204 |
+
'x': [50, 50,],
|
205 |
+
'y': [1, 99, ]
|
206 |
+
})
|
207 |
+
|
208 |
+
# Create the line using `mark_line`
|
209 |
+
midline = alt.Chart(midline_data).mark_line(
|
210 |
+
color='white',
|
211 |
+
strokeWidth=3
|
212 |
+
).encode(
|
213 |
+
x='x:Q',
|
214 |
+
y='y:Q'
|
215 |
+
)
|
216 |
+
lines_data = pd.DataFrame({
|
217 |
+
'x': [1, 17.5, 17.5, 1, 82.5, 82.5, 99,1,6.5,6.5,1, 99,93.5,93.5],
|
218 |
+
'y': [21.3, 21.3, 77.7, 77.7, 21.3, 77.7, 77.7,37.5,37.5,62.5,62.5,37.5,37.5,62.5],
|
219 |
+
'x2': [17.5, 17.5, 1, 17.5, 99, 82.5, 82.5, 6.5,6.5,1,6.5,93.5,93.5,99],
|
220 |
+
'y2': [21.3, 77.7, 77.7, 77.7, 21.3, 21.3,77.7,37.5,62.5,62.5,62.5,37.5,62.5,62.5]
|
221 |
+
})
|
222 |
+
|
223 |
+
lines = alt.Chart(lines_data).mark_line(
|
224 |
+
color='white',
|
225 |
+
strokeWidth=3
|
226 |
+
).encode(
|
227 |
+
x='x:Q',
|
228 |
+
y='y:Q',
|
229 |
+
x2='x2:Q',
|
230 |
+
y2='y2:Q'
|
231 |
+
)
|
232 |
+
|
233 |
+
dot_positions = pd.DataFrame({
|
234 |
+
'x': [12, 87],
|
235 |
+
'y': [50, 50]
|
236 |
+
})
|
237 |
+
|
238 |
+
# Create the white dots
|
239 |
+
white_dots = alt.Chart(dot_positions).mark_point(
|
240 |
+
size=100,
|
241 |
+
color='white',
|
242 |
+
filled=True
|
243 |
+
).encode(
|
244 |
+
x='x:Q',
|
245 |
+
y='y:Q'
|
246 |
+
)
|
247 |
+
|
248 |
+
|
249 |
+
|
250 |
+
theta = np.linspace(0, np.pi, 100)
|
251 |
+
semicircle_x = 12 + 9.5 * np.cos(theta)
|
252 |
+
semicircle_y = 50 + 9.5 * np.sin(theta)
|
253 |
+
|
254 |
+
semicircle_data = pd.DataFrame({
|
255 |
+
'x': semicircle_x,
|
256 |
+
'y': semicircle_y
|
257 |
+
})
|
258 |
+
|
259 |
+
semicircle_data = semicircle_data[semicircle_data['x'] >= 17.5]
|
260 |
+
|
261 |
+
arc1 = alt.Chart(semicircle_data).mark_line(
|
262 |
+
color='white',
|
263 |
+
strokeWidth=3
|
264 |
+
).encode(
|
265 |
+
x=alt.X('x', scale=alt.Scale(domain=[0, 100])),
|
266 |
+
y=alt.Y('y', scale=alt.Scale(domain=[0, 100]))
|
267 |
+
)
|
268 |
+
|
269 |
+
|
270 |
+
|
271 |
+
theta = np.linspace(0, np.pi, 100)
|
272 |
+
semicircle_x2 = 12 + 9.5 * np.cos(theta)
|
273 |
+
semicircle_y2 = 50 - 9.5 * np.sin(theta)
|
274 |
+
|
275 |
+
semicircle_data2 = pd.DataFrame({
|
276 |
+
'x': semicircle_x2,
|
277 |
+
'y': semicircle_y2
|
278 |
+
})
|
279 |
+
|
280 |
+
|
281 |
+
semicircle_data2 = semicircle_data2[semicircle_data2['x'] >= 17.5]
|
282 |
+
|
283 |
+
|
284 |
+
arc2 = alt.Chart(semicircle_data2).mark_line(
|
285 |
+
color='white',
|
286 |
+
strokeWidth=3
|
287 |
+
).encode(
|
288 |
+
x=alt.X('x', scale=alt.Scale(domain=[0, 100])),
|
289 |
+
y=alt.Y('y', scale=alt.Scale(domain=[0, 100]))
|
290 |
+
)
|
291 |
+
|
292 |
+
|
293 |
+
theta = np.linspace(0, np.pi, 100)
|
294 |
+
semicircle_x3 = 87 - 9.5 * np.cos(theta)
|
295 |
+
semicircle_y3 = 50 + 9.5 * np.sin(theta)
|
296 |
+
|
297 |
+
|
298 |
+
semicircle_data3 = pd.DataFrame({
|
299 |
+
'x': semicircle_x3,
|
300 |
+
'y': semicircle_y3
|
301 |
+
})
|
302 |
+
|
303 |
+
|
304 |
+
semicircle_data3 = semicircle_data3[semicircle_data3['x'] <= 82.5]
|
305 |
+
|
306 |
+
|
307 |
+
arc3 = alt.Chart(semicircle_data3).mark_line(
|
308 |
+
color='white',
|
309 |
+
strokeWidth=3
|
310 |
+
).encode(
|
311 |
+
x=alt.X('x', scale=alt.Scale(domain=[0, 100])),
|
312 |
+
y=alt.Y('y', scale=alt.Scale(domain=[0, 100]))
|
313 |
+
)
|
314 |
+
|
315 |
+
|
316 |
+
|
317 |
+
theta = np.linspace(0, np.pi, 100)
|
318 |
+
semicircle_x4 = 87 - 9.5 * np.cos(theta)
|
319 |
+
semicircle_y4 = 50 - 9.5 * np.sin(theta)
|
320 |
+
|
321 |
+
semicircle_data4 = pd.DataFrame({
|
322 |
+
'x': semicircle_x4,
|
323 |
+
'y': semicircle_y4
|
324 |
+
})
|
325 |
+
|
326 |
+
semicircle_data4 = semicircle_data4[semicircle_data4['x'] <= 82.5]
|
327 |
+
|
328 |
+
arc4 = alt.Chart(semicircle_data4).mark_line(
|
329 |
+
color='white',
|
330 |
+
strokeWidth=3
|
331 |
+
).encode(
|
332 |
+
x=alt.X('x', scale=alt.Scale(domain=[0, 100]), title=None ),
|
333 |
+
y=alt.Y('y', scale=alt.Scale(domain=[0, 100]), title=None)
|
334 |
+
)
|
335 |
+
|
336 |
+
|
337 |
+
df_a_match['x'] = [pos[0]['x'] for pos in df_a_match['positions']]
|
338 |
+
df_a_match['y'] = [pos[0]['y'] for pos in df_a_match['positions']]
|
339 |
+
|
340 |
+
|
341 |
+
# brush2 = alt.selection_interval(
|
342 |
+
# on="[mousedown[event.shiftKey], mouseup] > mousemove",
|
343 |
+
# translate="[mousedown[event.shiftKey], mouseup] > mousemove!",
|
344 |
+
# )
|
345 |
+
|
346 |
+
brush2 = alt.selection(type='interval', encodings=['x', 'y'])
|
347 |
+
|
348 |
+
team_event = alt.Chart(df_a_match).mark_point(
|
349 |
+
size=50,
|
350 |
+
opacity=1,
|
351 |
+
filled=True
|
352 |
+
).encode(
|
353 |
+
x=alt.X('x:Q', axis=alt.Axis(labels=False, ticks=False, grid=False)),
|
354 |
+
y=alt.Y('y:Q', axis=alt.Axis(labels=False, ticks=False, grid=False)),
|
355 |
+
color=alt.condition(brush2,
|
356 |
+
alt.Color('teamId:N', legend=None, scale=alt.Scale(domain=list(df_a_match['teamId'].unique()), range=['black', 'cyan'])),
|
357 |
+
alt.value('lightgray')),
|
358 |
+
tooltip=['eventName:N', 'teamId:N', 'x:Q', 'y:Q']
|
359 |
+
).add_selection(
|
360 |
+
brush2
|
361 |
+
)
|
362 |
+
|
363 |
+
|
364 |
+
zoom = alt.selection_interval(
|
365 |
+
bind='scales',
|
366 |
+
on="[mousedown[!event.shiftKey], mouseup] > mousemove",
|
367 |
+
translate="[mousedown[!event.shiftKey], mouseup] > mousemove!",
|
368 |
+
)
|
369 |
+
|
370 |
+
|
371 |
+
|
372 |
+
soccer_pitch = alt.layer(background, border_lines, midline, lines, white_dots, arc1, arc2, arc3, arc4, center_circle, team_event).properties(
|
373 |
+
width=700,
|
374 |
+
height=440,
|
375 |
+
title="Lazio - Internazionale, 2 - 3"
|
376 |
+
)
|
377 |
+
|
378 |
+
|
379 |
+
soccer_pitch = soccer_pitch.add_selection(
|
380 |
+
zoom,
|
381 |
+
)
|
382 |
+
|
383 |
+
|
384 |
+
|
385 |
+
bars = alt.Chart(df_a_match).mark_bar().encode(
|
386 |
+
y=alt.Y('eventName:N', sort='-x', title=None),
|
387 |
+
x=alt.X('count():Q', title='frequency'),
|
388 |
+
color=alt.Color('eventName:N',legend=None)
|
389 |
+
).transform_filter(
|
390 |
+
brush2
|
391 |
+
)
|
392 |
+
|
393 |
+
|
394 |
+
annotations_df = pd.DataFrame({
|
395 |
+
'text': ['You can select part of the graph to see distributoon of events'],
|
396 |
+
'x': [0],
|
397 |
+
'y': [0]
|
398 |
+
})
|
399 |
+
|
400 |
+
annotations_chart = alt.Chart(annotations_df).mark_text(
|
401 |
+
align='left',
|
402 |
+
baseline='middle',
|
403 |
+
fontSize=12,
|
404 |
+
fontStyle='italic'
|
405 |
+
).encode(
|
406 |
+
text='text:N'
|
407 |
+
).properties(
|
408 |
+
width=700,
|
409 |
+
height=20
|
410 |
+
)
|
411 |
+
|
412 |
+
soccer_pitch_with_annotations = alt.vconcat(
|
413 |
+
soccer_pitch,
|
414 |
+
annotations_chart,
|
415 |
+
spacing=5
|
416 |
+
)
|
417 |
+
|
418 |
+
|
419 |
+
combined_chart2 = alt.hconcat(
|
420 |
+
soccer_pitch_with_annotations,
|
421 |
+
bars,
|
422 |
+
spacing=10
|
423 |
+
).resolve_scale(
|
424 |
+
color='independent'
|
425 |
+
)
|
426 |
+
|
427 |
+
combined_chart2.display()
|
428 |
+
|
429 |
+
|
430 |
chart1_panel = pn.pane.Vega(chart1, sizing_mode='stretch_width')
|
431 |
chart2_panel = pn.pane.Vega(chart2, sizing_mode='stretch_width')
|
432 |
+
combined_chart1_panel = pn.pane.Vega(combined_chart1, sizing_mode='stretch_width')
|
433 |
+
combined_chart2_panel = pn.pane.Vega(combined_chart2, sizing_mode='stretch_width')
|
434 |
+
|
435 |
|
436 |
dashboard = pn.Column(
|
437 |
"# My Interactive Dashboard", # 可以添加标题
|
438 |
chart1_panel,
|
439 |
chart2_panel
|
440 |
+
combined_chart1_panel,
|
441 |
+
combined_chart2_panel
|
442 |
)
|
443 |
|
444 |
# 设置应用程序为可服务的
|
445 |
+
dashboard.servable(title='Scientific Visualization Project')
|
446 |
|
447 |
# 如果你运行这个脚本,那么调用以下命令可以在本地启动服务器
|
448 |
if __name__.startswith('bokeh'):
|