-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathteam.py
189 lines (153 loc) · 7.22 KB
/
team.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
import streamlit as st
from utils.data_loader import load_player_data_from_api, load_gameweek_data_from_github
from utils.team_selection import adjust_selected_players, select_players_for_position
from utils.team_computation import get_top_players_by_position, adjust_team_to_budget
from visualizations import (
draw_soccer_field,
plot_total_points_comparison,
plot_team_radar_chart,
plot_cost_breakdown_by_position,
total_points_vs_cost_yearly,
ownership_vs_points_bubble_chart_with_dropdown
)
from utils.constants import FORMATION_MAP, BUDGET, COLOR_PALETTE, SECTION_ICONS, POSITION_FULL_NAMES
import pandas as pd
players_pred_df = pd.read_csv("data/predicted_df.csv")
def get_player_pred(name, team):
try:
name_clean = name.strip().split(".")[-1]
x = players_pred_df[players_pred_df.web_name.str.contains(name_clean)][players_pred_df.team == team]
return int(x.sort_values(['gw'], ascending=False).pred_points_rounded.iloc[0])
except:
return 0
st.markdown(
f"<h2 style='text-align: center; color: {COLOR_PALETTE['App Title']};'>{SECTION_ICONS['App Title']} Ultimate FPL Manager<br> GW {load_gameweek_data_from_github('2024-25').GW.max() + 1}</h1>",
unsafe_allow_html=True
)
player_data = load_player_data_from_api()
if player_data.empty:
st.stop()
# Initialize session state
if 'selected_players' not in st.session_state:
st.session_state.selected_players = {pos: [] for pos in ['GKP', 'DEF', 'MID', 'FWD']}
if 'best_team' not in st.session_state:
st.session_state.best_team = None
if 'formation' not in st.session_state:
st.session_state.formation = None
st.sidebar.markdown(
f"<h3 style='color: {COLOR_PALETTE['Sidebar Pick']};'>{SECTION_ICONS['Pick Players']} Build Your Dream Team</h3>",
unsafe_allow_html=True
)
formation = st.sidebar.selectbox("Choose Your Formation", list(FORMATION_MAP.keys()), index=0)
position_counts = FORMATION_MAP[formation]
formation_changed = (formation != st.session_state.formation)
st.session_state.formation = formation
# If formation changed, ensure selected players match new formation limits
if formation_changed:
adjust_selected_players(position_counts, player_data)
st.session_state.best_team = None # Reset best team since formation changed
# Now select players for each position according to formation
selected_players = []
total_cost = 0
for position, count in position_counts.items():
position_players = select_players_for_position(position, count, player_data)
total_cost += sum(int(p['now_cost']) for p in position_players)
selected_players.extend(position_players)
remaining_budget = BUDGET - total_cost
all_positions_complete = all(
len(st.session_state.selected_players.get(position, [])) >= count
for position, count in position_counts.items()
)
if not all_positions_complete:
st.sidebar.error("Please ensure you have selected all required players for each position.")
if total_cost > BUDGET:
st.sidebar.error("Budget exceeded!")
if st.session_state.best_team is None or formation_changed:
best_team = get_top_players_by_position(player_data, formation)
best_team = adjust_team_to_budget(best_team, BUDGET, player_data)
st.session_state.best_team = best_team
else:
best_team = st.session_state.best_team
col1, col2 = st.columns([2, 1])
with col1:
team_to_display = st.radio("Select Team to View", ['Your Team', 'Best Team'])
if team_to_display == 'Your Team':
team_to_show = selected_players
else:
team_to_show = best_team
if not team_to_show:
st.write("**No players selected. Please select your team to view the field.**")
field_fig = draw_soccer_field([], formation)
else:
field_fig = draw_soccer_field(team_to_show, formation)
st.plotly_chart(field_fig, use_container_width=True)
with col2:
user_total_cost = sum(p['now_cost'] for p in selected_players)
best_total_cost = sum(p['now_cost'] for p in best_team)
user_xp_next_gw = sum(get_player_pred(p['web_name'], p['team_name']) for p in selected_players)
best_xp_next_gw = sum(get_player_pred(p['web_name'], p['team_name']) for p in best_team)
st.markdown(
f"<h3 style='color: {COLOR_PALETTE['Sidebar Budget']};'>{SECTION_ICONS['Budget Overview']} Budget Overview</h3>",
unsafe_allow_html=True
)
st.write(f"**Your Team Cost:** £{user_total_cost / 10:.1f}m / £{BUDGET / 10:.1f}m")
st.write(f"**Best Team Cost:** £{best_total_cost / 10:.1f}m / £{BUDGET / 10:.1f}m")
st.markdown(
f"<h3 style='color: {COLOR_PALETTE['Predicted Points']};'>{SECTION_ICONS['Target']} Points Prediction</h3>",
unsafe_allow_html=True
)
st.write(f"**Your Team Predicted Points next GW:** {user_xp_next_gw}")
st.write(f"**Best Team Predicted Points next GW:** {best_xp_next_gw}")
if user_total_cost > BUDGET:
st.error("Your team's budget is exceeded!")
if best_total_cost > BUDGET:
st.warning("The best team exceeds the budget constraints.")
st.markdown(
f"<h4 style='color: {COLOR_PALETTE['Performance Analysis']};'>{SECTION_ICONS['Performance Analysis']} {team_to_display} Players</h4>",
unsafe_allow_html=True
)
if team_to_show:
positions_order = ['FWD', 'MID', 'DEF', 'GKP']
for pos in positions_order:
pos_players = [p for p in team_to_show if p['position'] == pos]
if pos_players:
cols = st.columns(len(pos_players))
for idx, player in enumerate(pos_players):
with cols[idx]:
photo_url = player.get('photo_url', 'https://via.placeholder.com/100')
# Center-align photo and caption using HTML
st.markdown(
f"""
<div style="text-align: center;">
<img src="{photo_url}" style="width:80px; border-radius:40%;">
<p style="margin-top:5px;">{player['web_name']}</p>
</div>
""",
unsafe_allow_html=True
)
else:
st.write("**Please select your team or best team to view players.**")
st.divider()
st.markdown(
f"<h3 align='center' style='color: {COLOR_PALETTE['Performance Analysis']};'>{SECTION_ICONS['Performance Analysis']} Team & Player Performance, Cost, and Ownership Insights</h3>",
unsafe_allow_html=True
)
tab1, tab2 = st.columns(2)
with tab1:
plot_total_points_comparison(selected_players, best_team)
st.divider()
plot_team_radar_chart(selected_players, best_team)
with tab2:
total_points_vs_cost_yearly(player_data, 500)
st.divider()
ownership_vs_points_bubble_chart_with_dropdown(player_data, min_ownership_pct=10.0)
st.divider()
plot_cost_breakdown_by_position(selected_players, best_team)
user_player_names = set(p['web_name'] for p in selected_players)
best_player_names = set(p['web_name'] for p in best_team)
common_players = user_player_names & best_player_names
if common_players:
st.write(f"**{SECTION_ICONS['Shared Players']} Shared Players Spotlight:** {', '.join(common_players)}")
else:
st.write("**No common players between your team and the best team.**")
st.divider()