testing_vorp_logic / src /streamlit_app.py
James McCool
Add TE Premium logic to flex multiplier calculations in Streamlit app, adjusting maximum index limits for QB, RB, WR, and TE based on league settings to enhance player evaluation accuracy.
3221a02
import pandas as pd
import numpy as np
import requests
import math
import streamlit as st
st.set_page_config(layout="wide")
Dwain_proj = 'https://sheetdb.io/api/v1/svino07zkd6j6?sheet=2025_NFL_Proj_Dist'
dwain_ranks = 'https://sheetdb.io/api/v1/ax8b1ms11bbzt?sheet=Dwain_Season'
# Default configuration dictionaries
type_flex_percentiles = {
'Half PPR': {
'RB': .40,
'WR': .55,
'TE': .05,
},
'PPR': {
'RB': .40,
'WR': .55,
'TE': .05,
},
'Standard': {
'RB': .40,
'WR': .55,
'TE': .05,
},
'Superflex': {
'QB': .95,
'RB': .02,
'WR': .03,
'TE': .00,
},
'TE Premium': {
'RB': .35,
'WR': .50,
'TE': .15,
}
}
pos_vorp_limiters = {
'PPR': {
'QB': .27,
'RB': .440,
'WR': .460,
'TE': .27,
},
'Standard': {
'QB': .27,
'RB': .50,
'WR': .50,
'TE': .27,
},
'Superflex': {
'QB': .99,
'RB': .27,
'WR': .27,
'TE': .27,
},
'TE Premium': {
'QB': .27,
'RB': .440,
'WR': .460,
'TE': .27,
},
'Half PPR': {
'QB': .27,
'RB': .440,
'WR': .460,
'TE': .27,
},
}
flex_multipliers = {
'Half PPR': {
'QB': 1,
'RB': 1,
'WR': 1,
'TE': 1,
},
'PPR': {
'QB': 1,
'RB': 1,
'WR': 1,
'TE': 1,
},
'Standard': {
'QB': 1,
'RB': 1,
'WR': 1,
'TE': 1,
},
'Superflex': {
'QB': 4,
'RB': 1,
'WR': 1,
'TE': 1,
},
'TE Premium': {
'QB': 1,
'RB': 1,
'WR': 1,
'TE': 2,
},
}
base_settings = {
'TEAMS': 12,
'QB': 1,
'RB': 2,
'WR': 3,
'TE': 1,
'FLEX': 1,
'BENCH': 6,
'TYPE': 'Half PPR'
}
league_settings = {
'TEAMS': 12,
'QB': 1,
'RB': 2,
'WR': 3,
'TE': 1,
'FLEX': 1,
'BENCH': 6,
'TYPE': 'PPR'
}
def create_user_config_interface():
"""Create Streamlit interface for user configuration"""
st.sidebar.header("League Configuration")
# League Type Selection
league_type = st.sidebar.selectbox(
"League Type",
['Half PPR', 'PPR', 'Standard', 'Superflex', 'TE Premium'],
index=0
)
# League Settings
st.sidebar.subheader("League Settings")
teams = st.sidebar.number_input("Number of Teams", min_value=8, max_value=16, value=12)
qb_starters = st.sidebar.number_input("QB Starters", min_value=1, max_value=2, value=1)
rb_starters = st.sidebar.number_input("RB Starters", min_value=1, max_value=3, value=2)
wr_starters = st.sidebar.number_input("WR Starters", min_value=1, max_value=4, value=3)
te_starters = st.sidebar.number_input("TE Starters", min_value=1, max_value=2, value=1)
flex_spots = st.sidebar.number_input("Flex Spots", min_value=0, max_value=3, value=1)
bench_spots = st.sidebar.number_input("Bench Spots", min_value=0, max_value=10, value=6)
# Update league settings based on user input
user_league_settings = {
'TEAMS': teams,
'QB': qb_starters,
'RB': rb_starters,
'WR': wr_starters,
'TE': te_starters,
'FLEX': flex_spots,
'BENCH': bench_spots,
'TYPE': league_type
}
# Flex Percentiles Configuration
st.sidebar.subheader("Flex Position Percentiles")
if league_type == 'Superflex':
qb_flex_pct = st.sidebar.slider("QB Flex %", 0.0, 1.0, 0.95, 0.01)
rb_flex_pct = st.sidebar.slider("RB Flex %", 0.0, 1.0, 0.02, 0.01)
wr_flex_pct = st.sidebar.slider("WR Flex %", 0.0, 1.0, 0.03, 0.01)
te_flex_pct = st.sidebar.slider("TE Flex %", 0.0, 1.0, 0.00, 0.01)
user_flex_percentiles = {
'QB': qb_flex_pct,
'RB': rb_flex_pct,
'WR': wr_flex_pct,
'TE': te_flex_pct,
}
else:
# Get default values for the selected league type
default_rb = type_flex_percentiles.get(league_type, {}).get('RB', 0.4)
default_wr = type_flex_percentiles.get(league_type, {}).get('WR', 0.55)
default_te = type_flex_percentiles.get(league_type, {}).get('TE', 0.05)
rb_flex_pct = st.sidebar.slider("RB Flex %", 0.0, 1.0, default_rb, 0.01)
wr_flex_pct = st.sidebar.slider("WR Flex %", 0.0, 1.0, default_wr, 0.01)
te_flex_pct = st.sidebar.slider("TE Flex %", 0.0, 1.0, default_te, 0.01)
user_flex_percentiles = {
'RB': rb_flex_pct,
'WR': wr_flex_pct,
'TE': te_flex_pct,
}
# Flex Multipliers Configuration
st.sidebar.subheader("Position Multipliers")
default_qb_mult = flex_multipliers.get(league_type, {}).get('QB', 2.0)
default_rb_mult = flex_multipliers.get(league_type, {}).get('RB', 2.0)
default_wr_mult = flex_multipliers.get(league_type, {}).get('WR', 2.0)
default_te_mult = flex_multipliers.get(league_type, {}).get('TE', 2.0)
qb_mult = st.sidebar.number_input("QB Multiplier", min_value=1.0, max_value=5.0, value=float(default_qb_mult), step=0.5)
rb_mult = st.sidebar.number_input("RB Multiplier", min_value=1.0, max_value=5.0, value=float(default_rb_mult), step=0.5)
wr_mult = st.sidebar.number_input("WR Multiplier", min_value=1.0, max_value=5.0, value=float(default_wr_mult), step=0.5)
te_mult = st.sidebar.number_input("TE Multiplier", min_value=1.0, max_value=5.0, value=float(default_te_mult), step=0.5)
user_flex_multipliers = {
'QB': qb_mult,
'RB': rb_mult,
'WR': wr_mult,
'TE': te_mult,
}
# VORP Limiters Configuration
st.sidebar.subheader("VORP Rank Adjustments")
default_qb_vorp = pos_vorp_limiters.get(league_type, {}).get('QB', 0.5)
default_rb_vorp = pos_vorp_limiters.get(league_type, {}).get('RB', 0.75)
default_wr_vorp = pos_vorp_limiters.get(league_type, {}).get('WR', 0.75)
default_te_vorp = pos_vorp_limiters.get(league_type, {}).get('TE', 0.5)
qb_vorp_lim = st.sidebar.slider("QB VORP Limiter", 0.0, 1.0, default_qb_vorp, 0.01)
rb_vorp_lim = st.sidebar.slider("RB VORP Limiter", 0.0, 1.0, default_rb_vorp, 0.01)
wr_vorp_lim = st.sidebar.slider("WR VORP Limiter", 0.0, 1.0, default_wr_vorp, 0.01)
te_vorp_lim = st.sidebar.slider("TE VORP Limiter", 0.0, 1.0, default_te_vorp, 0.01)
user_pos_vorp_limiters = {
'QB': qb_vorp_lim,
'RB': rb_vorp_lim,
'WR': wr_vorp_lim,
'TE': te_vorp_lim,
}
return user_league_settings, user_flex_percentiles, user_flex_multipliers, user_pos_vorp_limiters
def load_projections_data(api: str) -> pd.DataFrame:
calc_columns = ['Ru Yds', 'Ru TDs', 'Rec', 'Rec Yds', 'Rec TDs', 'P Yds', 'P TDs', 'INTs']
ppr_values = [.1, 6, 1, .1, 6, .04, 4, -1]
halfPpr_values = [.1, 6, .5, .1, 6, .04, 4, -1]
standard_values = [.1, 6, 0, .1, 6, .04, 4, -1]
init_data = requests.get(api)
proj_dataframe = pd.DataFrame(init_data.json())
for col in calc_columns:
proj_dataframe[col] = proj_dataframe[col].astype(float)
proj_dataframe['halfPpr'] = proj_dataframe[calc_columns].dot(halfPpr_values)
proj_dataframe['ppr'] = proj_dataframe[calc_columns].dot(ppr_values)
proj_dataframe['standard'] = proj_dataframe[calc_columns].dot(standard_values)
fpts_df = proj_dataframe[['Name', 'SR_ID', 'Pos', 'halfPpr', 'ppr', 'standard']]
return fpts_df
def load_ranks_data(api: str) -> pd.DataFrame:
init_data = requests.get(api)
ranks_dataframe = pd.DataFrame(init_data.json())
ranks_dict = dict(zip(ranks_dataframe['SR_ID'], ranks_dataframe['Rank']))
return ranks_dict
def create_position_frames(frame: pd.DataFrame, ranks: dict) -> pd.DataFrame:
qb_frame = frame[frame['Pos'] == 'QB'].sort_values(by='halfPpr', ascending=False)
rb_frame = frame[frame['Pos'] == 'RB'].sort_values(by='halfPpr', ascending=False)
wr_frame = frame[frame['Pos'] == 'WR'].sort_values(by='halfPpr', ascending=False)
te_frame = frame[frame['Pos'] == 'TE'].sort_values(by='halfPpr', ascending=False)
for slice in [qb_frame, rb_frame, wr_frame, te_frame]:
slice['Rank'] = slice['SR_ID'].map(ranks).replace(np.nan, 0).astype(int)
slice = slice[slice['Rank'] != 0]
slice = slice.sort_values(by='Rank', ascending=True)
overall_frame = pd.concat([qb_frame, rb_frame, wr_frame, te_frame]).reset_index(drop=True)
return overall_frame
def designate_custom_position_reqs(league_settings: dict, flex_percentiles: dict, flex_multipliers: dict) -> dict:
qb_base = league_settings['QB'] * league_settings['TEAMS']
rb_base = league_settings['RB'] * league_settings['TEAMS']
wr_base = league_settings['WR'] * league_settings['TEAMS']
te_base = league_settings['TE'] * league_settings['TEAMS']
if league_settings['TYPE'] == 'Superflex':
qb_flex_mult = flex_multipliers['QB'] * (12 / league_settings['TEAMS'])
rb_flex_mult = flex_multipliers['RB']
wr_flex_mult = flex_multipliers['WR']
te_flex_mult = flex_multipliers['TE']
qb_rv_index = min(math.ceil((qb_base) * qb_flex_mult), 48)
rb_rv_index = min(math.ceil((rb_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles['RB'])) * rb_flex_mult), 60)
wr_rv_index = min(math.ceil((wr_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles['WR'])) * wr_flex_mult), 96)
te_rv_index = min(math.ceil((te_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles['TE'])) * te_flex_mult), 30)
elif league_settings['TYPE'] == 'TE Premium':
qb_flex_mult = flex_multipliers['QB']
rb_flex_mult = flex_multipliers['RB']
wr_flex_mult = flex_multipliers['WR']
te_flex_mult = flex_multipliers['TE'] * (12 / league_settings['TEAMS'])
qb_rv_index = min(math.ceil((qb_base) * qb_flex_mult), 30)
rb_rv_index = min(math.ceil((rb_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles['RB'])) * rb_flex_mult), 60)
wr_rv_index = min(math.ceil((wr_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles['WR'])) * wr_flex_mult), 96)
te_rv_index = min(math.ceil((te_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles['TE'])) * te_flex_mult), 48)
else:
qb_flex_mult = flex_multipliers['QB'] * (league_settings['TEAMS'] / 12)
rb_flex_mult = flex_multipliers['RB']
wr_flex_mult = flex_multipliers['WR']
te_flex_mult = flex_multipliers['TE'] * (league_settings['TEAMS'] / 12)
if league_settings['QB'] > 1:
qb_rv_index = min(math.ceil((qb_base) * 4), 48)
elif league_settings['QB'] == 1:
qb_rv_index = min(math.ceil((qb_base) * qb_flex_mult), 30)
rb_rv_index = min(math.ceil((rb_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles['RB'])) * rb_flex_mult), 60)
wr_rv_index = min(math.ceil((wr_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles['WR'])) * wr_flex_mult), 96)
te_rv_index = min(math.ceil((te_base + ((league_settings['TEAMS'] * league_settings['FLEX']) * flex_percentiles['TE'])) * te_flex_mult), 30)
print(f"Need {qb_rv_index} for QB in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
print(f"Need {rb_rv_index} for RB in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
print(f"Need {wr_rv_index} for WR in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
print(f"Need {te_rv_index} for TE in {league_settings['TEAMS']} teams with type {league_settings['TYPE']}")
pos_reqs = {
'QB': qb_rv_index,
'RB': rb_rv_index,
'WR': wr_rv_index,
'TE': te_rv_index,
}
return pos_reqs
def designate_base_position_reqs() -> dict:
qb_base = 1 * 12
rb_base = 2 * 12
wr_base = 3 * 12
te_base = 1 * 12
qb_rv_index = min(math.ceil(qb_base * 1), 30)
rb_rv_index = min(math.ceil((rb_base + ((12 * 1) * .40)) * 1), 60)
wr_rv_index = min(math.ceil((wr_base + ((12 * 1) * .55)) * 1), 96)
te_rv_index = min(math.ceil((te_base + ((12 * 1) * .05)) * 1), 30)
print(f"Need {qb_rv_index} for QB in {12} teams with type {league_settings['TYPE']}")
print(f"Need {rb_rv_index} for RB in {12} teams with type {league_settings['TYPE']}")
print(f"Need {wr_rv_index} for WR in {12} teams with type {league_settings['TYPE']}")
print(f"Need {te_rv_index} for TE in {12} teams with type {league_settings['TYPE']}")
pos_reqs = {
'QB': qb_rv_index,
'RB': rb_rv_index,
'WR': wr_rv_index,
'TE': te_rv_index,
}
return pos_reqs
def create_halfPpr_rv(frame: pd.DataFrame, pos_reqs: dict) -> dict:
rv_dict = {}
for positions in ['QB', 'RB', 'WR', 'TE']:
rv_dict[f'{positions}'] = frame[frame['Pos'] == positions].head(pos_reqs[positions]).reset_index(drop=True)['halfPpr'].tail(1).values[0]
return rv_dict
def create_custom_rv(frame: pd.DataFrame, pos_reqs: dict, league_settings: dict) -> dict:
if league_settings['TYPE'] == 'Half PPR':
rv_type = 'halfPpr'
elif league_settings['TYPE'] == 'PPR':
rv_type = 'ppr'
elif league_settings['TYPE'] == 'Standard':
rv_type = 'standard'
elif league_settings['TYPE'] == 'Superflex':
rv_type = 'halfPpr'
elif league_settings['TYPE'] == 'TE Premium':
rv_type = 'ppr'
rv_dict = {}
for positions in ['QB', 'RB', 'WR', 'TE']:
rv_dict[f'{positions}'] = frame[frame['Pos'] == positions].head(pos_reqs[positions]).reset_index(drop=True)[rv_type].tail(1).values[0]
return rv_dict
def assign_vorp_scoring(frame: pd.DataFrame, halfPpr_rv: dict, custom_rv: dict, league_settings: dict, pos_vorp_limiters: dict) -> pd.DataFrame:
if league_settings['TYPE'] == 'Half PPR':
rv_type = 'halfPpr'
elif league_settings['TYPE'] == 'PPR':
rv_type = 'ppr'
elif league_settings['TYPE'] == 'Standard':
rv_type = 'standard'
elif league_settings['TYPE'] == 'Superflex':
rv_type = 'halfPpr'
elif league_settings['TYPE'] == 'TE Premium':
rv_type = 'ppr'
if league_settings['QB'] > 1:
pos_vorp_limiters['QB'] = .9
if league_settings['TE'] > 1:
pos_vorp_limiters['TE'] = .9
vorp_frame = pd.DataFrame()
for positions in ['QB', 'RB', 'WR', 'TE']:
pos_frame = frame[frame['Pos'] == positions]
pos_frame = pos_frame[pos_frame['Rank'] != 0]
pos_frame = pos_frame.sort_values(by='Rank', ascending=True).reset_index(drop=True)
pos_frame['halfPpr_rv'] = halfPpr_rv[positions]
pos_frame['custom_rv'] = custom_rv[positions]
pos_frame['halfPpr_VORP'] = pos_frame['halfPpr'] - halfPpr_rv[positions]
pos_frame['custom_VORP'] = pos_frame[rv_type] - custom_rv[positions]
print(pos_frame[['Name', 'halfPpr', 'custom_rv', 'halfPpr_VORP', 'custom_VORP']].head(20))
vorp_frame = pd.concat([vorp_frame, pos_frame]).reset_index(drop=True)
vorp_frame['halfPpr_vorp_rank'] = vorp_frame['halfPpr_VORP'].rank(method='max', ascending=False)
vorp_frame['custom_vorp_rank'] = vorp_frame['custom_VORP'].rank(method='max', ascending=False)
vorp_frame['vorp_diff'] = np.where(vorp_frame['halfPpr_VORP'] == vorp_frame['custom_VORP'], 0, vorp_frame['halfPpr_vorp_rank'] - vorp_frame['custom_vorp_rank'])
for positions in ['QB', 'RB', 'WR', 'TE']:
vorp_frame.loc[vorp_frame['Pos'] == positions, 'Rank_Adjust'] = (vorp_frame['Rank'] - (vorp_frame['vorp_diff'] * pos_vorp_limiters[positions])).astype(float)
vorp_frame['custom_rank'] = vorp_frame['Rank_Adjust'].rank(method='first', ascending=True).astype(int)
vorp_frame['pos_rank'] = vorp_frame.groupby('Pos')['custom_rank'].rank(method='first', ascending=True).astype(int)
vorp_frame['pos_designation'] = vorp_frame['Pos'] + vorp_frame['pos_rank'].astype(str)
pos_des_dict = dict(zip(vorp_frame['pos_designation'], vorp_frame['Name']))
orig_rank_dict = dict(zip(vorp_frame['Name'], vorp_frame['pos_designation']))
half_ppr_match_dict = dict(zip(vorp_frame['pos_designation'], vorp_frame['halfPpr']))
custom_match_dict = dict(zip(vorp_frame['pos_designation'], vorp_frame[rv_type]))
for pos in ['QB', 'RB', 'WR', 'TE']:
print(vorp_frame[vorp_frame['Pos'] == pos].head(20))
return pos_des_dict, orig_rank_dict, half_ppr_match_dict, custom_match_dict
def assign_vorp_roster(frame: pd.DataFrame, halfPpr_rv: dict, custom_rv: dict, pos_vorp_limiters: dict, half_ppr_match_dict: dict, custom_match_dict: dict, orig_rank_dict: dict) -> pd.DataFrame:
vorp_frame = pd.DataFrame()
for positions in ['QB', 'RB', 'WR', 'TE']:
pos_frame = frame[frame['Pos'] == positions]
pos_frame = pos_frame[pos_frame['Rank'] != 0]
pos_frame = pos_frame.sort_values(by='Rank', ascending=True).reset_index(drop=True)
pos_frame['ranker_rank'] = pos_frame['Rank'].rank(method='first', ascending=True).astype(int)
pos_frame['pos_rank_init'] = pos_frame['Pos'] + pos_frame['ranker_rank'].astype(str)
pos_frame['scoring_rank'] = pos_frame['Name'].map(orig_rank_dict)
pos_frame['halfPpr_lu'] = pos_frame['pos_rank_init'].map(half_ppr_match_dict)
pos_frame['custom_lu'] = pos_frame['pos_rank_init'].map(custom_match_dict)
pos_frame['halfPpr_rv'] = halfPpr_rv[positions]
pos_frame['custom_rv'] = custom_rv[positions]
pos_frame['halfPpr_VORP'] = pos_frame['halfPpr_lu'] - pos_frame['halfPpr_rv']
pos_frame['custom_VORP'] = pos_frame['custom_lu'] - pos_frame['custom_rv']
vorp_frame = pd.concat([vorp_frame, pos_frame]).reset_index(drop=True)
vorp_frame['halfPpr_vorp_rank'] = vorp_frame['halfPpr_VORP'].rank(method='max', ascending=False)
vorp_frame['custom_vorp_rank'] = vorp_frame['custom_VORP'].rank(method='max', ascending=False)
vorp_frame['vorp_diff'] = np.where(vorp_frame['halfPpr_VORP'] == vorp_frame['custom_VORP'], 0, vorp_frame['halfPpr_vorp_rank'] - vorp_frame['custom_vorp_rank'])
for positions in ['QB', 'RB', 'WR', 'TE']:
vorp_frame.loc[vorp_frame['Pos'] == positions, 'Rank_Adjust'] = (vorp_frame['Rank'] - (vorp_frame['vorp_diff'] * pos_vorp_limiters[positions])).astype(float)
vorp_frame['custom_rank'] = vorp_frame['Rank_Adjust'].rank(method='first', ascending=True).astype(int)
vorp_frame['pos_rank'] = vorp_frame.groupby('Pos')['custom_rank'].rank(method='first', ascending=True).astype(int)
vorp_frame['pos_des'] = vorp_frame['Pos'] + vorp_frame['pos_rank'].astype(str)
return vorp_frame.sort_values(by='custom_rank', ascending=True)
def main():
st.title("Fantasy Football VORP Calculator")
st.write("Configure your league settings and analyze player values")
# Get user configuration
user_league_settings, user_flex_percentiles, user_flex_multipliers, user_pos_vorp_limiters = create_user_config_interface()
projections_df = load_projections_data(Dwain_proj)
ranks_dict = load_ranks_data(dwain_ranks)
# Create position frames
position_df = create_position_frames(projections_df, ranks_dict)
# Calculate position requirements
base_pos_reqs = designate_base_position_reqs()
custom_pos_reqs = designate_custom_position_reqs(user_league_settings, user_flex_percentiles, user_flex_multipliers)
# Calculate replacement values
halfPpr_rv = create_halfPpr_rv(position_df, base_pos_reqs)
custom_scoring_rv = create_custom_rv(position_df, base_pos_reqs, user_league_settings)
custom_roster_rv = create_custom_rv(position_df, custom_pos_reqs, user_league_settings)
# Calculate VORP and rankings
pos_des_dict, orig_rank_dict, half_ppr_match_dict, custom_match_dict = assign_vorp_scoring(position_df, halfPpr_rv, custom_scoring_rv, user_league_settings, user_pos_vorp_limiters)
final_df = assign_vorp_roster(position_df, halfPpr_rv, custom_roster_rv, user_pos_vorp_limiters, half_ppr_match_dict, custom_match_dict, orig_rank_dict)
final_df = final_df.drop(columns=['SR_ID'], axis=1)
final_df.insert(1, 'new_name', final_df['pos_des'].map(pos_des_dict))
final_df = final_df.drop(columns=['pos_rank', 'pos_des', 'pos_rank_init'], axis=1)
final_df = final_df.reset_index(drop=True)
# Display results
st.header("Player Rankings")
st.dataframe(final_df, use_container_width=True)
blank_left, qb_count_col, rb_count_col, wr_count_col, te_count_col, blank_right = st.columns(6)
with qb_count_col:
st.subheader("QB Counts")
st.write(f"Total QB top 12: {(final_df.loc[0:11, 'Pos'] == 'QB').sum()}, {(((final_df.loc[0:11, 'Pos'] == 'QB').sum() / 12) * 100):.2f}%")
st.write(f"Total QB 13 - 24: {(final_df.loc[12:23, 'Pos'] == 'QB').sum()}, {(((final_df.loc[12:23, 'Pos'] == 'QB').sum() / 12) * 100):.2f}%")
st.write(f"Total QB 25 - 36: {(final_df.loc[24:35, 'Pos'] == 'QB').sum()}, {(((final_df.loc[24:35, 'Pos'] == 'QB').sum() / 12) * 100):.2f}%")
st.write(f"Total QB 37 - 48: {(final_df.loc[36:47, 'Pos'] == 'QB').sum()}, {(((final_df.loc[36:47, 'Pos'] == 'QB').sum() / 12) * 100):.2f}%")
with rb_count_col:
st.subheader("RB Counts")
st.write(f"Total RB top 12: {(final_df.loc[0:11, 'Pos'] == 'RB').sum()}, {(((final_df.loc[0:11, 'Pos'] == 'RB').sum() / 12) * 100):.2f}%")
st.write(f"Total RB 13 - 24: {(final_df.loc[12:23, 'Pos'] == 'RB').sum()}, {(((final_df.loc[12:23, 'Pos'] == 'RB').sum() / 12) * 100):.2f}%")
st.write(f"Total RB 25 - 36: {(final_df.loc[24:35, 'Pos'] == 'RB').sum()}, {(((final_df.loc[24:35, 'Pos'] == 'RB').sum() / 12) * 100):.2f}%")
st.write(f"Total RB 37 - 48: {(final_df.loc[36:47, 'Pos'] == 'RB').sum()}, {(((final_df.loc[36:47, 'Pos'] == 'RB').sum() / 12) * 100):.2f}%")
with wr_count_col:
st.subheader("WR Counts")
st.write(f"Total WR top 12: {(final_df.loc[0:11, 'Pos'] == 'WR').sum()}, {(((final_df.loc[0:11, 'Pos'] == 'WR').sum() / 12) * 100):.2f}%")
st.write(f"Total WR 13 - 24: {(final_df.loc[12:23, 'Pos'] == 'WR').sum()}, {(((final_df.loc[12:23, 'Pos'] == 'WR').sum() / 12) * 100):.2f}%")
st.write(f"Total WR 25 - 36: {(final_df.loc[24:35, 'Pos'] == 'WR').sum()}, {(((final_df.loc[24:35, 'Pos'] == 'WR').sum() / 12) * 100):.2f}%")
st.write(f"Total WR 37 - 48: {(final_df.loc[36:47, 'Pos'] == 'WR').sum()}, {(((final_df.loc[36:47, 'Pos'] == 'WR').sum() / 12) * 100):.2f}%")
with te_count_col:
st.subheader("TE Counts")
st.write(f"Total TE top 12: {(final_df.loc[0:11, 'Pos'] == 'TE').sum()}, {(((final_df.loc[0:11, 'Pos'] == 'TE').sum() / 12) * 100):.2f}%")
st.write(f"Total TE 13 - 24: {(final_df.loc[12:23, 'Pos'] == 'TE').sum()}, {(((final_df.loc[12:23, 'Pos'] == 'TE').sum() / 12) * 100):.2f}%")
st.write(f"Total TE 25 - 36: {(final_df.loc[24:35, 'Pos'] == 'TE').sum()}, {(((final_df.loc[24:35, 'Pos'] == 'TE').sum() / 12) * 100):.2f}%")
st.write(f"Total TE 37 - 48: {(final_df.loc[36:47, 'Pos'] == 'TE').sum()}, {(((final_df.loc[36:47, 'Pos'] == 'TE').sum() / 12) * 100):.2f}%")
# Position breakdown
st.header("Position Breakdown")
for pos in ['QB', 'RB', 'WR', 'TE']:
pos_df = final_df[final_df['Pos'] == pos].head(50)
st.subheader(f"Top {pos}s")
st.dataframe(pos_df, use_container_width=True)
if __name__ == "__main__":
main()