Spaces:
Running
Running
James McCool
commited on
Commit
·
3573b17
1
Parent(s):
28a66aa
Implement Fantasy Football VORP Calculator with user-configurable league settings and data loading from external APIs. Added functions for calculating player rankings, replacement values, and VORP metrics. Enhanced user interface for league configuration and data display.
Browse files- src/streamlit_app.py +405 -37
src/streamlit_app.py
CHANGED
@@ -1,40 +1,408 @@
|
|
1 |
-
import altair as alt
|
2 |
-
import numpy as np
|
3 |
import pandas as pd
|
|
|
|
|
|
|
4 |
import streamlit as st
|
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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
import pandas as pd
|
2 |
+
import numpy as np
|
3 |
+
import requests
|
4 |
+
import math
|
5 |
import streamlit as st
|
6 |
|
7 |
+
Dwain_proj = 'https://sheetdb.io/api/v1/svino07zkd6j6?sheet=2025_NFL_Proj_Dist'
|
8 |
+
dwain_ranks = 'https://sheetdb.io/api/v1/ax8b1ms11bbzt?sheet=Dwain_Season'
|
9 |
+
|
10 |
+
# Default configuration dictionaries
|
11 |
+
type_flex_percentiles = {
|
12 |
+
'Half PPR': {
|
13 |
+
'RB': .40,
|
14 |
+
'WR': .55,
|
15 |
+
'TE': .05,
|
16 |
+
},
|
17 |
+
'PPR': {
|
18 |
+
'RB': .40,
|
19 |
+
'WR': .55,
|
20 |
+
'TE': .05,
|
21 |
+
},
|
22 |
+
'Standard': {
|
23 |
+
'RB': .40,
|
24 |
+
'WR': .55,
|
25 |
+
'TE': .05,
|
26 |
+
},
|
27 |
+
'Superflex': {
|
28 |
+
'QB': .95,
|
29 |
+
'RB': .02,
|
30 |
+
'WR': .03,
|
31 |
+
'TE': .00,
|
32 |
+
},
|
33 |
+
'TE Premium': {
|
34 |
+
'RB': .35,
|
35 |
+
'WR': .50,
|
36 |
+
'TE': .15,
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
pos_vorp_limiters = {
|
41 |
+
'PPR': {
|
42 |
+
'QB': .5,
|
43 |
+
'RB': .75,
|
44 |
+
'WR': .75,
|
45 |
+
'TE': .5,
|
46 |
+
},
|
47 |
+
'Standard': {
|
48 |
+
'QB': .25,
|
49 |
+
'RB': .75,
|
50 |
+
'WR': .75,
|
51 |
+
'TE': .5,
|
52 |
+
},
|
53 |
+
'Superflex': {
|
54 |
+
'QB': .5,
|
55 |
+
'RB': .75,
|
56 |
+
'WR': .75,
|
57 |
+
'TE': .5,
|
58 |
+
},
|
59 |
+
'TE Premium': {
|
60 |
+
'QB': .5,
|
61 |
+
'RB': .75,
|
62 |
+
'WR': .75,
|
63 |
+
'TE': .5,
|
64 |
+
},
|
65 |
+
'Half PPR': {
|
66 |
+
'QB': .5,
|
67 |
+
'RB': .75,
|
68 |
+
'WR': .75,
|
69 |
+
'TE': .5,
|
70 |
+
},
|
71 |
+
}
|
72 |
+
|
73 |
+
flex_multipliers = {
|
74 |
+
'Half PPR': {
|
75 |
+
'QB': 2,
|
76 |
+
'RB': 2,
|
77 |
+
'WR': 2,
|
78 |
+
'TE': 2,
|
79 |
+
},
|
80 |
+
'PPR': {
|
81 |
+
'QB': 2,
|
82 |
+
'RB': 2,
|
83 |
+
'WR': 2,
|
84 |
+
'TE': 2,
|
85 |
+
},
|
86 |
+
'Standard': {
|
87 |
+
'QB': 2,
|
88 |
+
'RB': 2,
|
89 |
+
'WR': 2,
|
90 |
+
'TE': 2,
|
91 |
+
},
|
92 |
+
'Superflex': {
|
93 |
+
'QB': 4,
|
94 |
+
'RB': 2,
|
95 |
+
'WR': 2,
|
96 |
+
'TE': 2,
|
97 |
+
},
|
98 |
+
'TE Premium': {
|
99 |
+
'QB': 2,
|
100 |
+
'RB': 2,
|
101 |
+
'WR': 2,
|
102 |
+
'TE': 2,
|
103 |
+
},
|
104 |
+
}
|
105 |
+
|
106 |
+
base_settings = {
|
107 |
+
'TEAMS': 12,
|
108 |
+
'QB': 1,
|
109 |
+
'RB': 2,
|
110 |
+
'WR': 3,
|
111 |
+
'TE': 1,
|
112 |
+
'FLEX': 1,
|
113 |
+
'BENCH': 6,
|
114 |
+
'TYPE': 'Half PPR'
|
115 |
+
}
|
116 |
+
|
117 |
+
league_settings = {
|
118 |
+
'TEAMS': 12,
|
119 |
+
'QB': 1,
|
120 |
+
'RB': 2,
|
121 |
+
'WR': 3,
|
122 |
+
'TE': 1,
|
123 |
+
'FLEX': 2,
|
124 |
+
'BENCH': 6,
|
125 |
+
'TYPE': 'Superflex'
|
126 |
+
}
|
127 |
+
|
128 |
+
def create_user_config_interface():
|
129 |
+
"""Create Streamlit interface for user configuration"""
|
130 |
+
st.sidebar.header("League Configuration")
|
131 |
+
|
132 |
+
# League Type Selection
|
133 |
+
league_type = st.sidebar.selectbox(
|
134 |
+
"League Type",
|
135 |
+
['Half PPR', 'PPR', 'Standard', 'Superflex', 'TE Premium'],
|
136 |
+
index=0
|
137 |
+
)
|
138 |
+
|
139 |
+
# League Settings
|
140 |
+
st.sidebar.subheader("League Settings")
|
141 |
+
teams = st.sidebar.number_input("Number of Teams", min_value=8, max_value=16, value=12)
|
142 |
+
qb_starters = st.sidebar.number_input("QB Starters", min_value=1, max_value=2, value=1)
|
143 |
+
rb_starters = st.sidebar.number_input("RB Starters", min_value=1, max_value=3, value=2)
|
144 |
+
wr_starters = st.sidebar.number_input("WR Starters", min_value=1, max_value=4, value=3)
|
145 |
+
te_starters = st.sidebar.number_input("TE Starters", min_value=1, max_value=2, value=1)
|
146 |
+
flex_spots = st.sidebar.number_input("Flex Spots", min_value=0, max_value=3, value=1)
|
147 |
+
bench_spots = st.sidebar.number_input("Bench Spots", min_value=0, max_value=10, value=6)
|
148 |
+
|
149 |
+
# Update league settings based on user input
|
150 |
+
user_league_settings = {
|
151 |
+
'TEAMS': teams,
|
152 |
+
'QB': qb_starters,
|
153 |
+
'RB': rb_starters,
|
154 |
+
'WR': wr_starters,
|
155 |
+
'TE': te_starters,
|
156 |
+
'FLEX': flex_spots,
|
157 |
+
'BENCH': bench_spots,
|
158 |
+
'TYPE': league_type
|
159 |
+
}
|
160 |
+
|
161 |
+
# Flex Percentiles Configuration
|
162 |
+
st.sidebar.subheader("Flex Position Percentiles")
|
163 |
+
if league_type == 'Superflex':
|
164 |
+
qb_flex_pct = st.sidebar.slider("QB Flex %", 0.0, 1.0, 0.95, 0.01)
|
165 |
+
rb_flex_pct = st.sidebar.slider("RB Flex %", 0.0, 1.0, 0.02, 0.01)
|
166 |
+
wr_flex_pct = st.sidebar.slider("WR Flex %", 0.0, 1.0, 0.03, 0.01)
|
167 |
+
te_flex_pct = st.sidebar.slider("TE Flex %", 0.0, 1.0, 0.00, 0.01)
|
168 |
+
|
169 |
+
user_flex_percentiles = {
|
170 |
+
'QB': qb_flex_pct,
|
171 |
+
'RB': rb_flex_pct,
|
172 |
+
'WR': wr_flex_pct,
|
173 |
+
'TE': te_flex_pct,
|
174 |
+
}
|
175 |
+
else:
|
176 |
+
rb_flex_pct = st.sidebar.slider("RB Flex %", 0.0, 1.0, type_flex_percentiles[league_type]['RB'], 0.01)
|
177 |
+
wr_flex_pct = st.sidebar.slider("WR Flex %", 0.0, 1.0, type_flex_percentiles[league_type]['WR'], 0.01)
|
178 |
+
te_flex_pct = st.sidebar.slider("TE Flex %", 0.0, 1.0, type_flex_percentiles[league_type]['TE'], 0.01)
|
179 |
+
|
180 |
+
user_flex_percentiles = {
|
181 |
+
'RB': rb_flex_pct,
|
182 |
+
'WR': wr_flex_pct,
|
183 |
+
'TE': te_flex_pct,
|
184 |
+
}
|
185 |
+
|
186 |
+
# Flex Multipliers Configuration
|
187 |
+
st.sidebar.subheader("Position Multipliers")
|
188 |
+
qb_mult = st.sidebar.number_input("QB Multiplier", min_value=1.0, max_value=5.0, value=float(flex_multipliers[league_type]['QB']), step=0.5)
|
189 |
+
rb_mult = st.sidebar.number_input("RB Multiplier", min_value=1.0, max_value=5.0, value=float(flex_multipliers[league_type]['RB']), step=0.5)
|
190 |
+
wr_mult = st.sidebar.number_input("WR Multiplier", min_value=1.0, max_value=5.0, value=float(flex_multipliers[league_type]['WR']), step=0.5)
|
191 |
+
te_mult = st.sidebar.number_input("TE Multiplier", min_value=1.0, max_value=5.0, value=float(flex_multipliers[league_type]['TE']), step=0.5)
|
192 |
+
|
193 |
+
user_flex_multipliers = {
|
194 |
+
'QB': qb_mult,
|
195 |
+
'RB': rb_mult,
|
196 |
+
'WR': wr_mult,
|
197 |
+
'TE': te_mult,
|
198 |
+
}
|
199 |
+
|
200 |
+
# VORP Limiters Configuration
|
201 |
+
st.sidebar.subheader("VORP Rank Adjustments")
|
202 |
+
qb_vorp_lim = st.sidebar.slider("QB VORP Limiter", 0.0, 1.0, pos_vorp_limiters[league_type]['QB'], 0.01)
|
203 |
+
rb_vorp_lim = st.sidebar.slider("RB VORP Limiter", 0.0, 1.0, pos_vorp_limiters[league_type]['RB'], 0.01)
|
204 |
+
wr_vorp_lim = st.sidebar.slider("WR VORP Limiter", 0.0, 1.0, pos_vorp_limiters[league_type]['WR'], 0.01)
|
205 |
+
te_vorp_lim = st.sidebar.slider("TE VORP Limiter", 0.0, 1.0, pos_vorp_limiters[league_type]['TE'], 0.01)
|
206 |
+
|
207 |
+
user_pos_vorp_limiters = {
|
208 |
+
'QB': qb_vorp_lim,
|
209 |
+
'RB': rb_vorp_lim,
|
210 |
+
'WR': wr_vorp_lim,
|
211 |
+
'TE': te_vorp_lim,
|
212 |
+
}
|
213 |
+
|
214 |
+
return user_league_settings, user_flex_percentiles, user_flex_multipliers, user_pos_vorp_limiters
|
215 |
+
|
216 |
+
def load_projections_data(api: str) -> pd.DataFrame:
|
217 |
+
calc_columns = ['Ru Yds', 'Ru TDs', 'Rec', 'Rec Yds', 'Rec TDs', 'P Yds', 'P TDs', 'INTs']
|
218 |
+
ppr_values = [.1, 6, 1, .1, 6, .04, 4, -1]
|
219 |
+
halfPpr_values = [.1, 6, .5, .1, 6, .04, 4, -1]
|
220 |
+
standard_values = [.1, 6, 0, .1, 6, .04, 4, -1]
|
221 |
+
init_data = requests.get(api)
|
222 |
+
proj_dataframe = pd.DataFrame(init_data.json())
|
223 |
+
for col in calc_columns:
|
224 |
+
proj_dataframe[col] = proj_dataframe[col].astype(float)
|
225 |
+
proj_dataframe['halfPpr'] = proj_dataframe[calc_columns].dot(halfPpr_values)
|
226 |
+
proj_dataframe['ppr'] = proj_dataframe[calc_columns].dot(ppr_values)
|
227 |
+
proj_dataframe['standard'] = proj_dataframe[calc_columns].dot(standard_values)
|
228 |
+
|
229 |
+
fpts_df = proj_dataframe[['Name', 'SR_ID', 'Pos', 'halfPpr', 'ppr', 'standard']]
|
230 |
+
|
231 |
+
return fpts_df
|
232 |
+
|
233 |
+
def load_ranks_data(api: str) -> pd.DataFrame:
|
234 |
+
init_data = requests.get(api)
|
235 |
+
ranks_dataframe = pd.DataFrame(init_data.json())
|
236 |
+
|
237 |
+
ranks_dict = dict(zip(ranks_dataframe['SR_ID'], ranks_dataframe['Rank']))
|
238 |
+
return ranks_dict
|
239 |
+
|
240 |
+
def create_position_frames(frame: pd.DataFrame, ranks: dict) -> pd.DataFrame:
|
241 |
+
qb_frame = frame[frame['Pos'] == 'QB'].sort_values(by='halfPpr', ascending=False)
|
242 |
+
rb_frame = frame[frame['Pos'] == 'RB'].sort_values(by='halfPpr', ascending=False)
|
243 |
+
wr_frame = frame[frame['Pos'] == 'WR'].sort_values(by='halfPpr', ascending=False)
|
244 |
+
te_frame = frame[frame['Pos'] == 'TE'].sort_values(by='halfPpr', ascending=False)
|
245 |
+
|
246 |
+
for slice in [qb_frame, rb_frame, wr_frame, te_frame]:
|
247 |
+
slice['Rank'] = slice['SR_ID'].map(ranks).replace(np.nan, 0).astype(int)
|
248 |
+
slice = slice[slice['Rank'] != 0]
|
249 |
+
slice = slice.sort_values(by='Rank', ascending=True)
|
250 |
+
|
251 |
+
overall_frame = pd.concat([qb_frame, rb_frame, wr_frame, te_frame]).reset_index(drop=True)
|
252 |
+
|
253 |
+
return overall_frame
|
254 |
+
|
255 |
+
def designate_custom_position_reqs(league_settings: dict, flex_percentiles: dict, flex_multipliers: dict) -> dict:
|
256 |
+
qb_base = league_settings['QB'] * league_settings['TEAMS']
|
257 |
+
rb_base = league_settings['RB'] * league_settings['TEAMS']
|
258 |
+
wr_base = league_settings['WR'] * league_settings['TEAMS']
|
259 |
+
te_base = league_settings['TE'] * league_settings['TEAMS']
|
260 |
+
|
261 |
+
qb_rv_index = math.ceil((qb_base) * flex_multipliers[league_settings['TYPE']]['QB'])
|
262 |
+
rb_rv_index = math.ceil((rb_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles[league_settings['TYPE']]['RB'])) * flex_multipliers[league_settings['TYPE']]['RB'])
|
263 |
+
wr_rv_index = math.ceil((wr_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles[league_settings['TYPE']]['WR'])) * flex_multipliers[league_settings['TYPE']]['WR'])
|
264 |
+
te_rv_index = math.ceil((te_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles[league_settings['TYPE']]['TE'])) * flex_multipliers[league_settings['TYPE']]['TE'])
|
265 |
+
|
266 |
+
print(f"Need {qb_rv_index} for QB in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
|
267 |
+
print(f"Need {rb_rv_index} for RB in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
|
268 |
+
print(f"Need {wr_rv_index} for WR in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
|
269 |
+
print(f"Need {te_rv_index} for TE in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
|
270 |
+
|
271 |
+
pos_reqs = {
|
272 |
+
'QB': qb_rv_index,
|
273 |
+
'RB': rb_rv_index,
|
274 |
+
'WR': wr_rv_index,
|
275 |
+
'TE': te_rv_index,
|
276 |
+
}
|
277 |
+
|
278 |
+
return pos_reqs
|
279 |
+
|
280 |
+
def designate_base_position_reqs(league_settings: dict, flex_percentiles: dict, flex_multipliers: dict) -> dict:
|
281 |
+
qb_base = league_settings['QB'] * league_settings['TEAMS']
|
282 |
+
rb_base = league_settings['RB'] * league_settings['TEAMS']
|
283 |
+
wr_base = league_settings['WR'] * league_settings['TEAMS']
|
284 |
+
te_base = league_settings['TE'] * league_settings['TEAMS']
|
285 |
+
|
286 |
+
qb_rv_index = math.ceil(qb_base * flex_multipliers[league_settings['TYPE']]['QB'])
|
287 |
+
rb_rv_index = math.ceil((rb_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles[league_settings['TYPE']]['RB'])) * flex_multipliers[league_settings['TYPE']]['RB'])
|
288 |
+
wr_rv_index = math.ceil((wr_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles[league_settings['TYPE']]['WR'])) * flex_multipliers[league_settings['TYPE']]['WR'])
|
289 |
+
te_rv_index = math.ceil((te_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles[league_settings['TYPE']]['TE'])) * flex_multipliers[league_settings['TYPE']]['TE'])
|
290 |
+
|
291 |
+
print(f"Need {qb_rv_index} for QB in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
|
292 |
+
print(f"Need {rb_rv_index} for RB in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
|
293 |
+
print(f"Need {wr_rv_index} for WR in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
|
294 |
+
print(f"Need {te_rv_index} for TE in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
|
295 |
+
|
296 |
+
pos_reqs = {
|
297 |
+
'QB': qb_rv_index,
|
298 |
+
'RB': rb_rv_index,
|
299 |
+
'WR': wr_rv_index,
|
300 |
+
'TE': te_rv_index,
|
301 |
+
}
|
302 |
+
|
303 |
+
return pos_reqs
|
304 |
+
|
305 |
+
def create_halfPpr_rv(frame: pd.DataFrame, pos_reqs: dict) -> dict:
|
306 |
+
|
307 |
+
rv_dict = {}
|
308 |
+
|
309 |
+
for positions in ['QB', 'RB', 'WR', 'TE']:
|
310 |
+
rv_dict[f'{positions}'] = frame[frame['Pos'] == positions].head(pos_reqs[positions]).reset_index(drop=True)['halfPpr'].tail(1).values[0]
|
311 |
+
|
312 |
+
return rv_dict
|
313 |
+
|
314 |
+
def create_custom_rv(frame: pd.DataFrame, pos_reqs: dict, league_settings: dict) -> dict:
|
315 |
+
|
316 |
+
if league_settings['TYPE'] == 'Half PPR':
|
317 |
+
rv_type = 'halfPpr'
|
318 |
+
elif league_settings['TYPE'] == 'PPR':
|
319 |
+
rv_type = 'ppr'
|
320 |
+
elif league_settings['TYPE'] == 'Standard':
|
321 |
+
rv_type = 'standard'
|
322 |
+
elif league_settings['TYPE'] == 'Superflex':
|
323 |
+
rv_type = 'halfPpr'
|
324 |
+
|
325 |
+
rv_dict = {}
|
326 |
+
|
327 |
+
for positions in ['QB', 'RB', 'WR', 'TE']:
|
328 |
+
rv_dict[f'{positions}'] = frame[frame['Pos'] == positions].head(pos_reqs[positions]).reset_index(drop=True)[rv_type].tail(1).values[0]
|
329 |
+
|
330 |
+
return rv_dict
|
331 |
+
|
332 |
+
def assign_vorp(frame: pd.DataFrame, halfPpr_rv: dict, custom_rv: dict, league_settings: dict, pos_vorp_limiters: dict) -> pd.DataFrame:
|
333 |
+
if league_settings['TYPE'] == 'Half PPR':
|
334 |
+
rv_type = 'halfPpr'
|
335 |
+
elif league_settings['TYPE'] == 'PPR':
|
336 |
+
rv_type = 'ppr'
|
337 |
+
elif league_settings['TYPE'] == 'Standard':
|
338 |
+
rv_type = 'standard'
|
339 |
+
elif league_settings['TYPE'] == 'Superflex':
|
340 |
+
rv_type = 'halfPpr'
|
341 |
+
|
342 |
+
vorp_frame = pd.DataFrame()
|
343 |
+
for positions in ['QB', 'RB', 'WR', 'TE']:
|
344 |
+
pos_frame = frame[frame['Pos'] == positions]
|
345 |
+
pos_frame = pos_frame[pos_frame['Rank'] != 0].reset_index(drop=True)
|
346 |
+
pos_frame = pos_frame.sort_values(by='Rank', ascending=True)
|
347 |
+
|
348 |
+
pos_frame['halfPpr_rv'] = halfPpr_rv[positions]
|
349 |
+
pos_frame['custom_rv'] = custom_rv[positions]
|
350 |
+
pos_frame['halfPpr_VORP'] = pos_frame['halfPpr'] - halfPpr_rv[positions]
|
351 |
+
pos_frame['custom_VORP'] = pos_frame[rv_type] - custom_rv[positions]
|
352 |
+
|
353 |
+
vorp_frame = pd.concat([vorp_frame, pos_frame]).reset_index(drop=True)
|
354 |
+
|
355 |
+
vorp_frame['halfPpr_vorp_rank'] = vorp_frame['halfPpr_VORP'].rank(method='max', ascending=False)
|
356 |
+
vorp_frame['custom_vorp_rank'] = vorp_frame['custom_VORP'].rank(method='max', ascending=False)
|
357 |
+
vorp_frame['vorp_diff'] = vorp_frame['halfPpr_vorp_rank'] - vorp_frame['custom_vorp_rank']
|
358 |
+
for positions in ['QB', 'RB', 'WR', 'TE']:
|
359 |
+
vorp_frame.loc[vorp_frame['Pos'] == positions, 'Rank_Adjust'] = (vorp_frame['Rank'] - (vorp_frame['vorp_diff'] * pos_vorp_limiters[league_settings['TYPE']][positions])).astype(float)
|
360 |
+
vorp_frame['custom_rank'] = vorp_frame['Rank_Adjust'].rank(method='first', ascending=True)
|
361 |
+
|
362 |
+
print(vorp_frame.sort_values(by='custom_vorp_rank', ascending=True).head(50))
|
363 |
+
|
364 |
+
return vorp_frame.sort_values(by='custom_rank', ascending=True)
|
365 |
+
|
366 |
+
def main():
|
367 |
+
st.title("Fantasy Football VORP Calculator")
|
368 |
+
st.write("Configure your league settings and analyze player values")
|
369 |
+
|
370 |
+
# Get user configuration
|
371 |
+
user_league_settings, user_flex_percentiles, user_flex_multipliers, user_pos_vorp_limiters = create_user_config_interface()
|
372 |
+
|
373 |
+
# Load data
|
374 |
+
try:
|
375 |
+
projections_df = load_projections_data(Dwain_proj)
|
376 |
+
ranks_dict = load_ranks_data(dwain_ranks)
|
377 |
+
|
378 |
+
# Create position frames
|
379 |
+
position_df = create_position_frames(projections_df, ranks_dict)
|
380 |
+
|
381 |
+
# Calculate position requirements
|
382 |
+
pos_reqs = designate_custom_position_reqs(user_league_settings, user_flex_percentiles, user_flex_multipliers)
|
383 |
+
|
384 |
+
# Calculate replacement values
|
385 |
+
halfPpr_rv = create_halfPpr_rv(position_df, pos_reqs)
|
386 |
+
custom_rv = create_custom_rv(position_df, pos_reqs, user_league_settings)
|
387 |
+
|
388 |
+
# Calculate VORP and rankings
|
389 |
+
final_df = assign_vorp(position_df, halfPpr_rv, custom_rv, user_league_settings, user_pos_vorp_limiters)
|
390 |
+
|
391 |
+
# Display results
|
392 |
+
st.header("Player Rankings")
|
393 |
+
st.dataframe(final_df[['Name', 'Pos', 'Rank', 'custom_rank', 'halfPpr', 'custom_VORP', 'halfPpr_VORP']].head(50))
|
394 |
+
|
395 |
+
# Position breakdown
|
396 |
+
st.header("Position Breakdown")
|
397 |
+
for pos in ['QB', 'RB', 'WR', 'TE']:
|
398 |
+
pos_df = final_df[final_df['Pos'] == pos].head(20)
|
399 |
+
st.subheader(f"Top {pos}s")
|
400 |
+
st.dataframe(pos_df[['Name', 'Rank', 'custom_rank', 'halfPpr', 'custom_VORP']])
|
401 |
+
|
402 |
+
except Exception as e:
|
403 |
+
st.error(f"Error loading data: {str(e)}")
|
404 |
+
st.info("Please check your internet connection and try again.")
|
405 |
+
|
406 |
+
if __name__ == "__main__":
|
407 |
+
main()
|
408 |
+
|