53Devon/Dota_2_Machine_Learning
0
1# Library dokumentasi streamlit
2import streamlit as st
3
4# Library pengolahan data
5import pandas as pd
6import json
7
8# Library visualisasi
9import plotly.express as px
10
11
12def run():
13 df = pd.read_csv("P1M2_Devon.csv")
14 df["DURATION"] = df["DURATION"].apply(
15 lambda x: int(x.split(":")[0]) * 60 + int(x.split(":")[1])
16 )
17 df["SCORE"] = pd.to_numeric(df["SCORE"], errors="coerce")
18 df["SCORE"] = df["SCORE"].astype("Int64")
19
20 with open("team.txt", "r") as file:
21 team = json.load(file)
22
23 with open("tournament.txt", "r") as file:
24 tournament = json.load(file)
25
26 with open("heroes.txt", "r") as file:
27 heroes = json.load(file)
28
29 st.subheader("🧩Exploratory Data Analysis")
30 st.write(
31 "Visualisasi data dilakukan untuk mengidentifikasi pola, anomali dan memberikan wawasan terkait informasi umum dari Dataframe."
32 )
33 st.write("")
34
35 expander_1 = st.expander(
36 "#### 🎯 Grafik Visualisasi Skor dan Durasi", expanded=True
37 )
38 with expander_1:
39 st.write("")
40
41 col_1, col_divier, col_2 = st.columns((68, 0.00000000001, 100))
42
43 col_1.markdown(
44 "<div style='margin-left: 18px'>Grafik ini menunjukkan informasi mengenai skor yang diperoleh dan durasi pertandingan 🕒</div>",
45 unsafe_allow_html=True,
46 )
47
48 with col_divier:
49 st.markdown(
50 '<div style="height: 80px; border-right: 1px solid grey;"></div>',
51 unsafe_allow_html=True,
52 )
53
54 col_2.markdown(
55 '<div style="margin-left: 25px; margin-bottom: 10px">Berikut merupakan <i>filter</i> yang dapat digunakan.',
56 unsafe_allow_html=True,
57 )
58 col_20, col_21, col_22, col_23, col_24 = col_2.columns(
59 (0.01, 10.7, 15.8, 13, 3)
60 )
61 st.write("")
62
63 exclude_team_popover = None
64 input_team_popover = None
65 exclude_tournament_popover = None
66 input_tournament_popover = None
67 exclude_karakter_popover = None
68 input_karakter_popover = None
69
70 with col_21.popover("Team"):
71 filter_mode = st.toggle("Mode Exclude Team")
72 if not filter_mode:
73 input_team_popover = st.multiselect(
74 "Nama Tim yang ingin di-include",
75 sorted(team),
76 help="Field ini memungkinkan pengguna untuk mengisi nama tim yang ingin dipilih",
77 )
78 if filter_mode:
79 exclude_team_popover = st.multiselect(
80 "Nama Tim yang ingin di-exclude",
81 sorted(team),
82 help="Field ini memungkinkan pengguna untuk mengisi nama tim yang tidak ingin dipilih.",
83 )
84
85 if not input_team_popover:
86 input_team_popover = "No Filter"
87 if not exclude_team_popover:
88 exclude_team_popover = "No Filter"
89
90 with col_22.popover("Tournament"):
91 filter_mode_2 = st.toggle("Mode Exclude Tournament")
92 if not filter_mode_2:
93 input_tournament_popover = st.multiselect(
94 "Nama Tournament yang ingin di-include",
95 sorted(tournament),
96 help="Field ini memungkinkan pengguna untuk mengisi nama tournament yang ingin dipilih",
97 )
98 if filter_mode_2:
99 exclude_tournament_popover = st.multiselect(
100 "Nama Tournament yang ingin di-exclude",
101 sorted(tournament),
102 help="Field ini memungkinkan pengguna untuk mengisi nama tournament yang tidak ingin dipilih.",
103 )
104 if not input_tournament_popover:
105 input_tournament_popover = "No Filter"
106 if not exclude_tournament_popover:
107 exclude_tournament_popover = "No Filter"
108
109 with col_23.popover("Karakter"):
110 filter_mode_2 = st.toggle("Mode Exclude karakter")
111 if not filter_mode_2:
112 input_karakter_popover = st.multiselect(
113 "Nama karakter yang ingin di-include",
114 sorted(heroes),
115 help="Field ini memungkinkan pengguna untuk mengisi nama karakter yang ingin dipilih",
116 )
117 if filter_mode_2:
118 exclude_karakter_popover = st.multiselect(
119 "Nama karakter yang ingin di-exclude",
120 sorted(heroes),
121 help="Field ini memungkinkan pengguna untuk mengisi nama karakter yang tidak ingin dipilih.",
122 )
123 if not input_karakter_popover:
124 input_karakter_popover = "No Filter"
125 if not exclude_karakter_popover:
126 exclude_karakter_popover = "No Filter"
127
128 df_hist = df
129 title = " Histogram Distribusi Skor Pertandingan Keseluruhan Tim"
130 insight = "Mayoritas skor dalam pertandingan selama 2019 - 2022 berakhir diantara skor 10 sampai 40 sementara cukup sedikit data skor di atas 50 dan di bawah 5."
131
132 if input_team_popover != "No Filter":
133 df_hist = df_hist[df_hist["TEAM"].isin(input_team_popover)]
134 title = f' Histogram Distribusi Skor Pertandingan {", ".join(input_team_popover)}'
135
136 if exclude_team_popover != "No Filter":
137 df_hist = df_hist[~df_hist["TEAM"].isin(exclude_team_popover)]
138 title = f' Histogram Distribusi Skor Pertandingan Tidak Termasuk {", ".join(exclude_team_popover)}'
139
140 if input_tournament_popover != "No Filter":
141 df_hist = df_hist[df_hist["TOURNAMENT"].isin(input_tournament_popover)]
142
143 if exclude_tournament_popover != "No Filter":
144 df_hist = df_hist[~df_hist["TOURNAMENT"].isin(exclude_tournament_popover)]
145
146 if input_karakter_popover != "No Filter":
147 df_hist = df_hist[
148 df_hist[["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]]
149 .isin(input_karakter_popover)
150 .any(axis=1)
151 ]
152
153 if exclude_karakter_popover != "No Filter":
154 df_hist = df_hist[
155 ~df_hist[["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]]
156 .isin(exclude_karakter_popover)
157 .any(axis=1)
158 ]
159
160 tab_0, tab_a, tab_b, tab_c = st.tabs(
161 [
162 " ",
163 "Skor Keseluruhan",
164 "Skor Berdasarkan Hasil",
165 "Durasi Keseluruhan",
166 ]
167 )
168 with tab_0:
169 st.write("")
170 st.markdown(
171 '<div style="margin-left: 28px">Terdapat tiga tab yang dapat diakses, yaitu:</div>',
172 unsafe_allow_html=True,
173 )
174 st.write("")
175 st.markdown(
176 "1. **Skor Keseluruhan**:a Tab ini akan menampilkan ringkasan semua skor pertandingan yang ada dalam dataset. \n\n2. **Skor Berdasarkan Hasil**:a Tab ini akan menampilkan perbandingan skor antara hasil pertandingan menang dan kalah.\n3. **Durasi Keseluruhan**:a Tab ini akan menyajikan data mengenai durasi rata-rata atau total dari semua pertandingan."
177 )
178
179 with tab_a:
180 fig = px.histogram(
181 df_hist,
182 x="SCORE",
183 nbins=50,
184 barmode="overlay",
185 color_discrete_sequence=["#58a3cd", "#9baebc"],
186 )
187
188 fig.update_layout(
189 title=title,
190 xaxis_title="Skor Pertandingan",
191 yaxis_title="Jumlah",
192 barmode="overlay",
193 margin=dict(r=80),
194 )
195
196 fig.add_annotation(
197 x=df_hist["SCORE"].mean(),
198 y=0.9,
199 text="Average <br>Line",
200 xref="x",
201 yref="paper",
202 showarrow=True,
203 arrowhead=4,
204 arrowsize=1,
205 arrowwidth=2,
206 arrowcolor="#9baebc",
207 ax=0,
208 ay=-35,
209 font=dict(color="#58a3cd"),
210 )
211
212 fig.add_shape(
213 type="line",
214 x1=df_hist["SCORE"].mean(),
215 x0=df_hist["SCORE"].mean(),
216 y0=0,
217 y1=0.89,
218 xref="x",
219 yref="paper",
220 line=dict(color="#9baebc", dash="dash", width=1.5),
221 name="Average WIN",
222 )
223 st.plotly_chart(fig)
224
225 col0, col1, col3, col4, col5, col6 = st.columns((3, 10, 10, 10, 10, 5))
226
227 if (
228 (input_team_popover == "No Filter")
229 and (exclude_team_popover == "No Filter")
230 and (exclude_tournament_popover == "No Filter")
231 and (input_tournament_popover == "No Filter")
232 and (input_karakter_popover == "No Filter")
233 and (exclude_karakter_popover == "No Filter")
234 ):
235 col1.metric("Rata-rata Skor", f'{df_hist["SCORE"].mean():.2f}')
236 col3.metric("Modus Skor", f'{df_hist["SCORE"].mode()[0]}')
237 col4.metric("Skor Minimum", f'{df_hist["SCORE"].min()}')
238 col5.metric("Skor Maximum", f'{df_hist["SCORE"].max()}')
239
240 else:
241 col1.metric(
242 "Rata-rata Skor",
243 f'{df_hist["SCORE"].mean():.2f}',
244 (f'{(df_hist["SCORE"].mean())-(df["SCORE"].mean()):.2f}'),
245 )
246 col3.metric(
247 "Modus Skor",
248 f'{df_hist["SCORE"].mode()[0]}',
249 (f'{(df_hist["SCORE"].mode()[0])-(df["SCORE"].mode()[0]):.2f}'),
250 )
251 col4.metric(
252 "Skor Minimum",
253 f'{df_hist["SCORE"].min()}',
254 (f'{(df_hist["SCORE"].min())-(df["SCORE"].min()):.2f}'),
255 )
256 col5.metric(
257 "Skor Maximum",
258 f'{df_hist["SCORE"].max()}',
259 (f'{(df_hist["SCORE"].max())-(df["SCORE"].max()):.2f}'),
260 )
261
262 st.write("")
263 st.markdown(
264 f'<div style="margin-left: 40px; margin-right: 60px;text-align: justify; ">{insight}</div>',
265 unsafe_allow_html=True,
266 )
267 col_div, col, col_div2 = st.columns((1, 18, 1))
268 t1 = col.toggle("Detail Informasi DataFrame")
269 if t1:
270 col.dataframe(df_hist)
271
272 with tab_b:
273 fig = px.histogram(
274 df_hist,
275 x="SCORE",
276 barmode="overlay",
277 color="RESULT",
278 color_discrete_map={"LOSE": "lightcoral", "WIN": "lightskyblue"},
279 )
280
281 fig.update_layout(
282 title=title,
283 xaxis_title="Skor Pertandingan",
284 yaxis_title="Jumlah",
285 barmode="overlay",
286 )
287
288 fig.add_annotation(
289 x=df_hist[df_hist["RESULT"] == "WIN"]["SCORE"].mean(),
290 y=0.9,
291 text="Average <br>Win ",
292 xref="x",
293 yref="paper",
294 showarrow=True,
295 arrowhead=4,
296 arrowcolor="#9baebc",
297 ax=0,
298 ay=-35,
299 font=dict(color="#58a3cd"),
300 )
301
302 fig.add_shape(
303 type="line",
304 x1=df_hist[df_hist["RESULT"] == "WIN"]["SCORE"].mean(),
305 x0=df_hist[df_hist["RESULT"] == "WIN"]["SCORE"].mean(),
306 y0=0,
307 y1=0.89,
308 xref="x",
309 yref="paper",
310 line=dict(color="#9baebc", dash="dash", width=1.5),
311 name="Average WIN",
312 )
313
314 fig.add_annotation(
315 x=df_hist[df_hist["RESULT"] == "LOSE"]["SCORE"].mean(),
316 y=0.9,
317 text="Average<br>Lose",
318 xref="x",
319 yref="paper",
320 showarrow=True,
321 arrowhead=4,
322 arrowcolor="#9baebc",
323 ax=0,
324 ay=-35,
325 font=dict(color="#c85d5f"),
326 )
327
328 fig.add_shape(
329 type="line",
330 x1=df_hist[df_hist["RESULT"] == "LOSE"]["SCORE"].mean(),
331 x0=df_hist[df_hist["RESULT"] == "LOSE"]["SCORE"].mean(),
332 y0=0,
333 y1=0.89,
334 xref="x",
335 yref="paper",
336 line=dict(color="#9baebc", dash="dash", width=1.5),
337 name="Average Lose",
338 )
339 st.plotly_chart(fig)
340
341 col0, col1, col2, col3, col4, col5 = st.columns((3, 10, 10, 10, 10, 5))
342 if (
343 (input_team_popover == "No Filter")
344 and (exclude_team_popover == "No Filter")
345 and (exclude_tournament_popover == "No Filter")
346 and (input_tournament_popover == "No Filter")
347 and (input_karakter_popover == "No Filter")
348 and (exclude_karakter_popover == "No Filter")
349 ):
350 col1.metric(
351 "Mean Menang",
352 f'{df_hist[df_hist["RESULT"] == "WIN"]["SCORE"].mean():.2f}',
353 )
354 col2.metric(
355 "Mean Kalah",
356 f'{df_hist[df_hist["RESULT"] == "LOSE"]["SCORE"].mean():.2f}',
357 )
358 col3.metric(
359 "Modus Menang",
360 f'{df_hist[df_hist["RESULT"] == "WIN"]["SCORE"].mode()[0]}',
361 )
362 col4.metric(
363 "Modus Kalah",
364 f'{df_hist[df_hist["RESULT"] == "LOSE"]["SCORE"].mode()[0]}',
365 )
366 else:
367 col1.metric(
368 "Mean Menang",
369 f'{df_hist[df_hist["RESULT"] == "WIN"]["SCORE"].mean():.2f}',
370 f'{(df_hist[df_hist["RESULT"] == "WIN"]["SCORE"].mean() - (df[df["RESULT"] == "WIN"]["SCORE"].mean())):,.2f}',
371 )
372 col2.metric(
373 "Mean Kalah",
374 f'{df_hist[df_hist["RESULT"] == "LOSE"]["SCORE"].mean():.2f}',
375 f'{(df_hist[df_hist["RESULT"] == "LOSE"]["SCORE"].mean() - (df[df["RESULT"] == "LOSE"]["SCORE"].mean())):,.2f}',
376 )
377 col3.metric(
378 "Modus Menang",
379 f'{df_hist[df_hist["RESULT"] == "WIN"]["SCORE"].mode()[0]}',
380 f'{(df_hist[df_hist["RESULT"] == "WIN"]["SCORE"].mode()[0]) - (df[df["RESULT"] == "WIN"]["SCORE"].mode()[0]):,.2f}',
381 )
382 col4.metric(
383 "Modus Kalah",
384 f'{df_hist[df_hist["RESULT"] == "LOSE"]["SCORE"].mode()[0]}',
385 f'{(df_hist[df_hist["RESULT"] == "LOSE"]["SCORE"].mode()[0]) - (df[df["RESULT"] == "LOSE"]["SCORE"].mode()[0]):,.2f}',
386 )
387
388 st.write(
389 '<div style="margin-left: 40px; margin-right: 60px;text-align: justify; ">Terlihat adanya pergeseran mayoritas data hasil pertandingan kalah memiliki skor yang relatif lebih rendah daripada data skor dengan hasil pertandingan menang. Hal ini dianggap wajar dan logis karena tim yang berada pada situasi menang berpotensi memiliki skor yang lebih tinggi dari pada tim lawan.</div>',
390 unsafe_allow_html=True,
391 )
392 col_div, col, col_div2 = st.columns((1, 18, 1))
393 t2 = col.toggle("Detail Informasi DataFrame", key="t2")
394 if t2:
395 col.dataframe(df_hist)
396
397 with tab_c:
398 fig = px.histogram(
399 df_hist,
400 x="DURATION",
401 barmode="overlay",
402 )
403
404 fig.update_layout(
405 title=title,
406 xaxis_title="Durasi Pertandingan (detik)",
407 yaxis_title="Jumlah",
408 barmode="overlay",
409 xaxis_title_standoff=25,
410 )
411
412 fig.add_annotation(
413 x=df_hist["DURATION"].mean(),
414 y=0.9,
415 text="Average <br>duration",
416 xref="x",
417 yref="paper",
418 showarrow=True,
419 arrowhead=4,
420 arrowsize=1,
421 arrowwidth=2,
422 arrowcolor="#9baebc",
423 ax=0,
424 ay=-35,
425 font=dict(color="#58a3cd"),
426 )
427
428 fig.add_shape(
429 type="line",
430 x1=df_hist["DURATION"].mean(),
431 x0=df_hist["DURATION"].mean(),
432 y0=0,
433 y1=0.89,
434 xref="x",
435 yref="paper",
436 line=dict(color="#9baebc", dash="dash", width=1.5),
437 name="Average WIN",
438 )
439
440 st.plotly_chart(fig)
441
442 col0, col1, col3, col4, col5 = st.columns((3, 10, 10, 10, 20))
443
444 if (
445 (input_team_popover == "No Filter")
446 and (exclude_team_popover == "No Filter")
447 and (exclude_tournament_popover == "No Filter")
448 and (input_tournament_popover == "No Filter")
449 and (input_karakter_popover == "No Filter")
450 and (exclude_karakter_popover == "No Filter")
451 ):
452 col1.metric(
453 "Rata-rata Durasi", f"{(df_hist['DURATION'].mean()/60):.1f}'"
454 )
455 col3.metric(
456 "Durasi Minimum",
457 f'{df_hist["DURATION"].min()//60:02d}:{df_hist["DURATION"].min()%60:02d}',
458 )
459 col4.metric(
460 "Durasi Maximum",
461 f'{df_hist["DURATION"].max()//60:02d}:{df_hist["DURATION"].max()%60:02d}',
462 )
463
464 else:
465 col1.metric(
466 "Rata-rata Durasi",
467 f"{(df_hist['DURATION'].mean()/60):.1f}'",
468 (
469 f"{(((df_hist['DURATION'].mean())-(df['DURATION'].mean()))/60):.1f}'"
470 ),
471 )
472 col3.metric(
473 "Durasi Minimum",
474 f'{df_hist["DURATION"].min()//60:02d}:{df_hist["DURATION"].min()%60:02d}',
475 f'{(df_hist["DURATION"].min()-df["DURATION"].min())//60:02d}:{(df_hist["DURATION"].min()-df["DURATION"].min())%60:02d}',
476 )
477 col4.metric(
478 "Durasi Maximum",
479 f'{df_hist["DURATION"].max()//60:02d}:{df_hist["DURATION"].max()%60:02d}',
480 f'{(df_hist["DURATION"].max()-df["DURATION"].max())//60:02d}:{(df_hist["DURATION"].max()-df["DURATION"].max())%60:02d}',
481 )
482
483 st.write("")
484 st.markdown(
485 '<div style="margin-left: 40px; margin-right: 60px;text-align: justify; ">Mayoritas pertandingan berlangsung diantara 1500 sampai 2500 detik atau setara dengan 25 sampai 41 menit sementara cukup sedikit data pertandingan selesai di bawah 1000 detik dan di atas 4000 detik. ',
486 unsafe_allow_html=True,
487 )
488 col_div, col, col_div2 = st.columns((1, 18, 1))
489
490 if col.toggle("Detail Informasi DataFrame", key="t3"):
491 col.dataframe(df_hist)
492 st.markdown("<br>", unsafe_allow_html=True)
493
494 expander_2 = st.expander("#### 🏆 Grafik Persentase Kemenangan Tim", expanded=True)
495 with expander_2:
496 st.write("")
497 col_1, col_divier, col_2 = st.columns((75, 3, 100))
498
499 col_1.markdown(
500 "<div style='margin-left: 18px'>Grafik ini menampilkan persentase kemenangan tim 🎉, maka dapat dengan mudah melihat performa tim.</div>",
501 unsafe_allow_html=True,
502 )
503
504 with col_divier:
505 st.markdown(
506 '<div style="height: 80px; border-right: 1px solid grey;"></div>',
507 unsafe_allow_html=True,
508 )
509
510 col_2.markdown(
511 '<div style="margin-left: 25px; margin-bottom: 10px">Berikut merupakan <i>filter</i> yang dapat digunakan.',
512 unsafe_allow_html=True,
513 )
514
515 st.write("")
516
517 exclude_tournament_popover = None
518 input_tournament_popover = None
519 exclude_karakter_popover = None
520 input_karakter_popover = None
521
522 col_20, col_22, col_23, col_24 = col_2.columns((2, 18, 16, 11))
523
524 with col_22.popover("Tournament"):
525 filter_mode_3 = st.toggle("Mode Exclude Tournament.")
526 if not filter_mode_3:
527 input_tournament_popover = st.multiselect(
528 "Nama Tournament yang ingin di-include",
529 sorted(tournament),
530 help="Field ini memungkinkan pengguna untuk mengisi nama tournament yang ingin dipilih untuk di-filter",
531 )
532 if filter_mode_3:
533 exclude_tournament_popover = st.multiselect(
534 "Nama Tournament yang ingin di-exclude",
535 sorted(tournament),
536 help="Field ini memungkinkan pengguna untuk mengisi nama tournament yang tidak ingin dipilih untuk di-filter.",
537 )
538 if not input_tournament_popover:
539 input_tournament_popover = "No Filter"
540 if not exclude_tournament_popover:
541 exclude_tournament_popover = "No Filter"
542
543 with col_23.popover("Karakter"):
544 filter_mode_2 = st.toggle("Mode Exclude karakter.")
545 if not filter_mode_2:
546 input_karakter_popover = st.multiselect(
547 "Nama karakter yang ingin di-include",
548 sorted(heroes),
549 help="Field ini memungkinkan pengguna untuk mengisi nama karakter yang ingin dipilih untuk di-filter",
550 )
551 if filter_mode_2:
552 exclude_karakter_popover = st.multiselect(
553 "Nama karakter yang ingin di-exclude",
554 sorted(heroes),
555 help="Field ini memungkinkan pengguna untuk mengisi nama karakter yang tidak ingin dipilih untuk di-filter.",
556 )
557 if not input_karakter_popover:
558 input_karakter_popover = "No Filter"
559 if not exclude_karakter_popover:
560 exclude_karakter_popover = "No Filter"
561
562 df_winrate = df
563 df_unfilter = (
564 (df.groupby("TEAM")["RESULT"].value_counts(normalize=True) * 100)
565 .reset_index()
566 .sort_values(by="proportion", ascending=False)
567 )
568 df_unfilter.rename({"proportion": "Winrate"}, axis=1, inplace=True)
569 df_unfilter = df_unfilter[df_unfilter["RESULT"] == "WIN"]
570
571 if input_tournament_popover != "No Filter":
572 df_winrate = df_winrate[
573 df_winrate["TOURNAMENT"].isin(input_tournament_popover)
574 ]
575
576 if exclude_tournament_popover != "No Filter":
577 df_winrate = df_winrate[
578 ~df_winrate["TOURNAMENT"].isin(exclude_tournament_popover)
579 ]
580
581 if input_karakter_popover != "No Filter":
582 df_winrate = df_winrate[
583 df_winrate[["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]]
584 .isin(input_karakter_popover)
585 .any(axis=1)
586 ]
587
588 if exclude_karakter_popover != "No Filter":
589 df_winrate = df_winrate[
590 ~df_winrate[["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]]
591 .isin(exclude_karakter_popover)
592 .any(axis=1)
593 ]
594
595 tab_00, tab0, tab1 = st.tabs(
596 [
597 " ",
598 "Keseluruhan Winrate",
599 "Perbandingan dengan Jumlah Pertandingan",
600 ]
601 )
602 with tab_00:
603 st.write("")
604 st.markdown(
605 '<div style="margin-left: 28px">Terdapat dua tab yang dapat diakses, yaitu:</div>',
606 unsafe_allow_html=True,
607 )
608 st.write("")
609 st.markdown(
610 "1. **Keseluruhan Winrate**:a Tab ini akan menampilkan ringkasan tingkat kemenangan dari keseluruhan tim. \n\n2. **Perbandingan dengan Jumlah Pertandingan**:a Tab ini akan menampilkan perbandingan tingkat kemenangan dan jumlah pertandingan."
611 )
612 with tab0:
613 df_winrate_final = (
614 (
615 df_winrate.groupby("TEAM")["RESULT"].value_counts(normalize=True)
616 * 100
617 )
618 .reset_index()
619 .sort_values(by="proportion", ascending=False)
620 )
621 df_win1 = df_winrate_final[df_winrate_final["RESULT"] == "WIN"]
622 df_win1.rename({"proportion": "Winrate"}, axis=1, inplace=True)
623 df_win1["Match"] = df_win1["TEAM"].apply(
624 lambda team: df_winrate[df_winrate["TEAM"] == team]["TEAM"].count()
625 )
626 df_win1.sort_values(by=["Winrate", "Match"], ascending=False, inplace=True)
627
628 fig3_1 = px.bar(
629 df_win1,
630 x="Winrate",
631 y="TEAM",
632 orientation="h",
633 color="Winrate",
634 color_continuous_scale="rdbu",
635 )
636 fig3_1.update_layout(
637 title=" Winrate Keseluruhan Tim",
638 xaxis_title="Persentase Menang (%)",
639 )
640 fig3_1.update_coloraxes(colorbar_title="Winrate(%)")
641
642 if (
643 (input_tournament_popover == "No Filter")
644 and (exclude_tournament_popover == "No Filter")
645 and (input_karakter_popover == "No Filter")
646 and (exclude_karakter_popover == "No Filter")
647 ):
648 fig3_1.add_shape(
649 type="rect",
650 x0=0,
651 x1=46,
652 y0=173,
653 y1=67,
654 line=dict(color="red", width=1.5, dash="dot"),
655 opacity=0.8,
656 )
657 fig3_1.add_annotation(
658 x=46,
659 y=173,
660 text="<b>Low Winrate</b>",
661 font_size=18,
662 font_color="lightcoral",
663 hovertext="",
664 showarrow=False,
665 yshift=-15,
666 xshift=-60,
667 )
668 fig3_1.add_annotation(
669 x=46,
670 y=173,
671 text="<b>under 45%</b>",
672 font_size=15,
673 font_color="lightcoral",
674 hovertext="",
675 showarrow=False,
676 yshift=-33,
677 xshift=-47,
678 )
679 fig3_1.add_annotation(
680 x=46,
681 y=173,
682 text=f"<b>{df_win1[df_win1['Winrate'] < 45]['TEAM'].count()} teams</b>",
683 font_size=13,
684 font_color="lightcoral",
685 hovertext="",
686 showarrow=False,
687 yshift=-50,
688 xshift=-42,
689 )
690
691 fig3_1.add_shape(
692 type="rect",
693 x0=0,
694 x1=73,
695 y0=0,
696 y1=20,
697 line=dict(color="blue", width=1.5, dash="dot"),
698 opacity=0.8,
699 )
700 fig3_1.add_annotation(
701 x=70,
702 y=20,
703 text="<b>High Winrate</b>",
704 font_size=18,
705 font_color="lightskyblue",
706 hovertext="",
707 showarrow=False,
708 yshift=48,
709 xshift=-35,
710 )
711 fig3_1.add_annotation(
712 x=70,
713 y=20,
714 text="<b>Over 55%</b>",
715 font_size=15,
716 font_color="lightskyblue",
717 hovertext="",
718 showarrow=False,
719 yshift=28,
720 xshift=-17,
721 )
722 fig3_1.add_annotation(
723 x=70,
724 y=20,
725 text=f"<b>{df_win1[df_win1['Winrate'] > 55]['TEAM'].count()} teams</b>",
726 font_size=13,
727 font_color="lightskyblue",
728 hovertext="",
729 showarrow=False,
730 yshift=13,
731 xshift=-12,
732 )
733
734 fig3_1.update_xaxes(showgrid=True, gridwidth=1, linewidth=2)
735 st.plotly_chart(fig3_1)
736 col0, col1, col3 = st.columns((1, 10, 1))
737
738 if (input_karakter_popover == "No Filter") and (
739 exclude_karakter_popover == "No Filter"
740 ):
741 con1 = col1.container(border=True)
742 con1.markdown(
743 '<div style="margin-left: 80px; "><h3>Statistik Winrate tim terbaik.',
744 unsafe_allow_html=True,
745 )
746 col_10, col_11, col_12, col_13, col_00 = con1.columns((1, 12, 5, 5, 1))
747 col_11.metric(
748 "Tim dengan Winrate tertinggi pertama:",
749 f"{df_win1['TEAM'].iloc[0]}",
750 )
751 col_12.metric(
752 "Jumlah Match",
753 df_win1["Match"].iloc[0],
754 )
755 col_13.metric(
756 "Winrate (%)",
757 f'{df_win1["Winrate"].max():.1f}%',
758 )
759 col_11.metric(
760 "Tim dengan Winrate tertinggi kedua:", f"{df_win1['TEAM'].iloc[1]}"
761 )
762 col_12.metric(
763 "Jumlah Match",
764 df_win1["Match"].iloc[1],
765 )
766 col_13.metric(
767 "Winrate (%)",
768 f'{df_win1["Winrate"].iloc[1]:.1f}%',
769 )
770 col_11.metric(
771 "Tim dengan Winrate tertinggi ketiga:", f"{df_win1['TEAM'].iloc[2]}"
772 )
773 col_12.metric(
774 "Jumlah Match",
775 df_win1["Match"].iloc[2],
776 )
777 col_13.metric(
778 "Winrate (%)",
779 f'{df_win1["Winrate"].iloc[2]:.1f}%',
780 )
781 con1.write("")
782
783 st.write("")
784
785 with tab1:
786 df_winrate_final = (
787 (
788 df_winrate.groupby("TEAM")["RESULT"].value_counts(normalize=True)
789 * 100
790 )
791 .reset_index()
792 .sort_values(by="proportion", ascending=False)
793 )
794 df_win1 = df_winrate_final[df_winrate_final["RESULT"] == "WIN"]
795 df_win1.rename({"proportion": "Winrate"}, axis=1, inplace=True)
796 df_win1["label"] = df_win1.apply(
797 lambda row: row["TEAM"] if row["Winrate"] > 63 else "", axis=1
798 )
799 for team in df_win1["TEAM"]:
800 df_win1.loc[df_win1["TEAM"] == team, "match"] = df[df["TEAM"] == team][
801 "TEAM"
802 ].count()
803
804 fig3 = px.scatter(
805 df_win1,
806 x="match",
807 y="Winrate",
808 hover_name="TEAM",
809 color="match",
810 color_continuous_scale="haline",
811 )
812
813 fig3.update_layout(
814 title=" Penyebaran Persentase Kemenangan berdasarkan Jumlah Pertandingan",
815 xaxis_title="Jumlah pertandingan",
816 yaxis_title="Persentase Menang (%)",
817 )
818 fig3.update_traces(
819 textposition="top center",
820 )
821 if (
822 (input_tournament_popover == "No Filter")
823 and (exclude_tournament_popover == "No Filter")
824 and (input_karakter_popover == "No Filter")
825 and (exclude_karakter_popover == "No Filter")
826 ):
827 fig3.add_shape(
828 type="circle",
829 x0=-120,
830 x1=200,
831 y0=0,
832 y1=80,
833 line_width=0,
834 fillcolor="#8897ff",
835 opacity=0.1,
836 )
837 fig3.add_shape(
838 type="circle",
839 x0=215,
840 x1=820,
841 y0=78,
842 y1=33,
843 line_width=0,
844 fillcolor="#abffd2",
845 opacity=0.1,
846 )
847 fig3.add_annotation(
848 x=46,
849 y=80,
850 text="<b>Less Experience<br>Teams</b>",
851 font_size=20,
852 font_color="lightskyblue",
853 hovertext="",
854 showarrow=False,
855 )
856 fig3.add_annotation(
857 x=520,
858 y=77,
859 text="<b>More Experience Teams</b>",
860 font_size=20,
861 font_color="#51b27c",
862 hovertext="",
863 showarrow=False,
864 )
865 fig3.add_annotation(
866 x=520,
867 y=40,
868 text="<b>More experience tends to <br>have good winrate</b>",
869 font_size=15,
870 font_color="#238a57",
871 hovertext="",
872 showarrow=False,
873 )
874
875 fig3.update_xaxes(showgrid=False, gridwidth=1, linewidth=2)
876 st.plotly_chart(fig3)
877
878 col0, col1, col2, col3, col_end = st.columns((3.5, 20, 20, 15, 2))
879
880 if (
881 (exclude_tournament_popover == "No Filter")
882 and (input_tournament_popover == "No Filter")
883 and (input_karakter_popover == "No Filter")
884 and (exclude_karakter_popover == "No Filter")
885 ):
886 col1.metric(
887 "Persentase Tim Berpengalaman",
888 f'{df_win1[df_win1["match"] > 200]["TEAM"].count()/df_win1["TEAM"].count()*100:.1f}%',
889 )
890 col2.metric(
891 "Rata-rata jumlah pertandingan",
892 f'{(df_win1["match"].mean()):.2f}',
893 )
894 col3.metric(
895 "Jumlah Tim",
896 f'{(df_win1["TEAM"].count())}',
897 )
898
899 else:
900 col1.metric(
901 "Persentase Tim Berpengalaman",
902 f'{df_win1[df_win1["match"] > 200]["TEAM"].count()/df_win1["TEAM"].count()*100:.1f}%',
903 f'{(df_win1[df_win1["match"] > 200]["TEAM"].count()/df_win1["TEAM"].count()*100) - (15.1):.1f}%',
904 )
905 col2.metric(
906 "Rata-rata jumlah pertandingan",
907 f'{(df_win1["match"].mean()):.2f}',
908 f'{(df_win1["match"].mean()) - (102.83):.2f}',
909 )
910 col3.metric(
911 "Jumlah Tim",
912 f'{(df_win1["TEAM"].count())}',
913 )
914
915 st.markdown(
916 '<div style="margin-left: 40px; margin-right: 60px; text-align: justify; ">Grafik menunjukkan hubungan positif antara jumlah pertandingan dengan persentase kemenangan, dimana tim dengan lebih banyak pertandingan cenderung memiliki persentase kemenangan yang lebih tinggi. Namun, terdapat variasi dalam setiap kelompok, yang mengindikasikan faktor lain selain pengalaman juga mempengaruhi hasil pertandingan.</div>',
917 unsafe_allow_html=True,
918 )
919
920 st.markdown("<br>", unsafe_allow_html=True)
921
922 expander_3 = st.expander("#### 💪 Grafik Popularitas Karakter", expanded=True)
923 with expander_3:
924 st.write("")
925
926 col_1, col_divier, col_2 = st.columns((68, 0.00000000001, 100))
927
928 col_1.write(
929 "<div style='margin-left: 18px'>Grafik ini menunjukkan karakter mana yang paling populer dalam permainan 🕹️ </div>",
930 unsafe_allow_html=True,
931 )
932
933 with col_divier:
934 st.markdown(
935 '<div style="height: 80px; border-right: 1px solid grey;"></div>',
936 unsafe_allow_html=True,
937 )
938
939 col_2.markdown(
940 '<div style="margin-left: 25px; margin-bottom: 10px">Berikut merupakan <i>filter</i> yang dapat digunakan.',
941 unsafe_allow_html=True,
942 )
943
944 col_20, col_21, col_22, col_23 = col_2.columns((2, 10.7, 15.8, 15))
945 st.write("")
946
947 exclude_team_popover = None
948 input_team_popover = None
949 exclude_tournament_popover = None
950 input_tournament_popover = None
951 exclude_karakter_popover = None
952 input_karakter_popover = None
953
954 with open("team.txt", "r") as file:
955 team = json.load(file)
956
957 with col_21.popover("Team"):
958 filter_mode = st.toggle("Mode Exclude Team", key="t5")
959 if not filter_mode:
960 input_team_popover = st.multiselect(
961 "Nama Tim yang ingin di-include",
962 sorted(team),
963 help="Field ini memungkinkan pengguna untuk mengisi nama tim yang ingin dipilih",
964 key="ms10",
965 )
966 if filter_mode:
967 exclude_team_popover = st.multiselect(
968 "Nama Tim yang ingin di-exclude",
969 sorted(team),
970 help="Field ini memungkinkan pengguna untuk mengisi nama tim yang tidak ingin dipilih.",
971 key="ms11",
972 )
973 if not input_team_popover:
974 input_team_popover = "No Filter"
975 if not exclude_team_popover:
976 exclude_team_popover = "No Filter"
977
978 with col_22.popover("Tournament"):
979 filter_mode_2 = st.toggle("Mode Exclude Tournament", key="t6")
980 if not filter_mode_2:
981 input_tournament_popover = st.multiselect(
982 "Nama Tournament yang ingin di-include",
983 sorted(tournament),
984 help="Field ini memungkinkan pengguna untuk mengisi nama tournament yang ingin dipilih",
985 key="ms1",
986 )
987 if filter_mode_2:
988 exclude_tournament_popover = st.multiselect(
989 "Nama Tournament yang ingin di-exclude",
990 sorted(tournament),
991 help="Field ini memungkinkan pengguna untuk mengisi nama tournament yang tidak ingin dipilih.",
992 key="ms2",
993 )
994 if not input_tournament_popover:
995 input_tournament_popover = "No Filter"
996 if not exclude_tournament_popover:
997 exclude_tournament_popover = "No Filter"
998
999 if input_team_popover != "No Filter":
1000 df_hist = df_hist[df_hist["TEAM"].isin(input_team_popover)]
1001
1002 if exclude_team_popover != "No Filter":
1003 df_hist = df_hist[~df_hist["TEAM"].isin(exclude_team_popover)]
1004
1005 if input_tournament_popover != "No Filter":
1006 df_hist = df_hist[df_hist["TOURNAMENT"].isin(input_tournament_popover)]
1007
1008 if exclude_tournament_popover != "No Filter":
1009 df_hist = df_hist[~df_hist["TOURNAMENT"].isin(exclude_tournament_popover)]
1010
1011 tab_0, tab1, tab2 = st.tabs(
1012 [
1013 " ",
1014 "Popularitas Keseluruhan",
1015 "Popularitas berdasarkan Jumlah Penggunaan",
1016 ]
1017 )
1018
1019 df_bar_1 = (
1020 df_hist[["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]]
1021 .stack()
1022 .value_counts()
1023 .reset_index()
1024 )
1025 df_bar_1.columns = ["HERO", "COUNT"]
1026 df_bar_1["WIN COUNT"] = 0
1027 for index, row in df_bar_1.iterrows():
1028 hero = row["HERO"]
1029 win_count = 0
1030 for col in ["HERO_1", "HERO_2", "HERO_3", "HERO_4", "HERO_5"]:
1031 win_count += (
1032 df_hist[df_hist["RESULT"] == "WIN"][col].value_counts().get(hero, 0)
1033 )
1034 df_bar_1.at[index, "WIN COUNT"] = win_count
1035 df_bar_1["WINRATE"] = round(df_bar_1["WIN COUNT"] / df_bar_1["COUNT"] * 100, 2)
1036
1037 with tab_0:
1038 st.write("")
1039 st.markdown(
1040 '<div style="margin-left: 28px">Terdapat dua tab yang dapat diakses, yaitu:</div>',
1041 unsafe_allow_html=True,
1042 )
1043 st.write("")
1044 st.markdown(
1045 "1. **Popularitas Keseluruhan**:a Tab ini akan menampilkan ringkasan semua popularitas karakter yang ada dalam dataset. \n\n2. **Popularitas berdasarkan Jumlah Penggunaan**:a Tab ini akan menampilkan perbandingan popularitas karakter antara jumlah penggunaan sepanjang tahun 2019 sampai 2022."
1046 )
1047 st.write("")
1048
1049 with tab1:
1050 fig5 = px.bar(
1051 df_bar_1,
1052 x="COUNT",
1053 y="HERO",
1054 color="COUNT",
1055 orientation="h",
1056 color_continuous_scale="haline",
1057 )
1058 fig5.update_layout(
1059 title=" Popularitas Keseluruhan Karakter",
1060 xaxis_title="Jumlah digunakan",
1061 )
1062 fig5.update_xaxes(showgrid=True, gridwidth=1, linewidth=2)
1063 st.plotly_chart(fig5)
1064
1065 col0, col1, col2, col3 = st.columns((3, 20, 20, 3))
1066
1067 with col1.container(border=True):
1068 st.markdown("##### Karakter Terpopuler")
1069
1070 col11, col12, coldiv = st.columns((8.8, 5, 0.5))
1071 col11.metric("Posisi Pertama", df_bar_1["HERO"].iloc[0])
1072 col12.metric("Penggunaan", df_bar_1["COUNT"].iloc[0])
1073 col11.metric("Posisi Kedua", df_bar_1["HERO"].iloc[1])
1074 col12.metric("Penggunaan", df_bar_1["COUNT"].iloc[1])
1075 col11.metric("Posisi Ketiga", df_bar_1["HERO"].iloc[2])
1076 col12.metric("Penggunaan", df_bar_1["COUNT"].iloc[2])
1077
1078 with col2.container(border=True):
1079 st.markdown("##### Karakter Tidak Populer")
1080
1081 col11, col12, coldiv = st.columns((8.8, 5, 0.5))
1082 col11.metric("Posisi Pertama", df_bar_1["HERO"].iloc[-1])
1083 col12.metric("Penggunaan", df_bar_1["COUNT"].iloc[-1])
1084 col11.metric("Posisi Kedua", df_bar_1["HERO"].iloc[-2])
1085 col12.metric("Penggunaan", df_bar_1["COUNT"].iloc[-2])
1086 col11.metric("Posisi Ketiga", df_bar_1["HERO"].iloc[-3])
1087 col12.metric("Penggunaan", df_bar_1["COUNT"].iloc[-3])
1088 st.write("")
1089
1090 with tab2:
1091 fig6 = px.scatter(
1092 df_bar_1,
1093 x="COUNT",
1094 y="WINRATE",
1095 color="WINRATE",
1096 hover_name="HERO",
1097 color_continuous_scale="redor",
1098 )
1099 fig6.update_layout(
1100 title=" Perbandingan Winrate Karakter dengan Jumlah Pertandingan",
1101 xaxis_title="Jumlah Pertandingan",
1102 yaxis_title="Persentase Kemenangan (%)",
1103 )
1104
1105 if (
1106 (exclude_tournament_popover == "No Filter")
1107 and (input_tournament_popover == "No Filter")
1108 and (input_team_popover == "No Filter")
1109 and (exclude_team_popover == "No Filter")
1110 ):
1111 fig6.add_shape(
1112 type="circle",
1113 x0=20,
1114 x1=200,
1115 y0=35,
1116 y1=66,
1117 line_width=0,
1118 opacity=0.1,
1119 fillcolor="lightcoral",
1120 )
1121 fig6.add_annotation(
1122 x=390,
1123 y=41,
1124 text="<b>Uncommon Hero</b>",
1125 font_size=20,
1126 font_color="lightcoral",
1127 showarrow=False,
1128 )
1129 fig6.add_annotation(
1130 x=390,
1131 y=39,
1132 text="<b>under 200 pick</b>",
1133 font_size=15,
1134 font_color="lightcoral",
1135 showarrow=False,
1136 )
1137
1138 fig6.add_shape(
1139 type="circle",
1140 x0=160,
1141 x1=1600,
1142 y0=42,
1143 y1=58,
1144 line_width=0,
1145 opacity=0.1,
1146 fillcolor="#b16bbf",
1147 )
1148 fig6.add_annotation(
1149 x=1650,
1150 y=57,
1151 text="<b>Common Hero</b>",
1152 font_size=20,
1153 font_color="#b16bbf",
1154 showarrow=False,
1155 )
1156 fig6.add_annotation(
1157 x=1650,
1158 y=55.2,
1159 text="<b>winrate between 45% and 55%</b>",
1160 font_size=15,
1161 font_color="#b16bbf",
1162 showarrow=False,
1163 )
1164
1165 fig6.add_shape(
1166 type="circle",
1167 x0=1700,
1168 x1=2000,
1169 y0=45,
1170 y1=52,
1171 line_width=0,
1172 opacity=0.1,
1173 fillcolor="#5872d2",
1174 )
1175 fig6.add_annotation(
1176 x=1820,
1177 y=45.3,
1178 text="<b>Contested Hero</b>",
1179 font_size=20,
1180 font_color="#5872d2",
1181 showarrow=False,
1182 )
1183 fig6.add_annotation(
1184 x=1830,
1185 y=43.3,
1186 text="<b>over 1500 pick</b>",
1187 font_size=15,
1188 font_color="#5872d2",
1189 showarrow=False,
1190 )
1191
1192 fig6.add_shape(
1193 type="circle",
1194 x0=40,
1195 x1=135,
1196 y0=62.7,
1197 y1=65.2,
1198 line_width=2.5,
1199 line_color="gold",
1200 opacity=0.5,
