From d3c4e4b5757ce40271682cb94ac996c657285c53 Mon Sep 17 00:00:00 2001 From: Cal Corum Date: Fri, 27 Oct 2023 12:54:54 -0500 Subject: [PATCH] Added Reaction to basic ratings --- app/routers_v2/battingcardratings.py | 198 +++++++++++++++++++++++++-- 1 file changed, 184 insertions(+), 14 deletions(-) diff --git a/app/routers_v2/battingcardratings.py b/app/routers_v2/battingcardratings.py index 3f16fc1..2a7aa0d 100644 --- a/app/routers_v2/battingcardratings.py +++ b/app/routers_v2/battingcardratings.py @@ -1,11 +1,13 @@ from fastapi import APIRouter, Depends, HTTPException, Query, Response +from scipy import stats from typing import Literal, Optional, List import logging import pandas as pd import pydantic from pydantic import validator, root_validator -from ..db_engine import db, BattingCardRatings, model_to_dict, chunked, BattingCard, Player, query_to_csv, Team +from ..db_engine import db, BattingCardRatings, model_to_dict, chunked, BattingCard, Player, query_to_csv, Team, \ + CardPosition from ..dependencies import oauth2_scheme, valid_token, LOG_DATA logging.basicConfig( @@ -138,17 +140,7 @@ async def get_card_ratings( return return_val -@router.get('/scouting') -async def get_card_scouting(team_id: int, ts: str, cardset_id: list = Query(default=None)): - this_team = Team.get_or_none(Team.id == team_id) - logging.debug(f'Team: {this_team} / has_guide: {this_team.has_guide}') - if this_team is None or ts != this_team.team_hash() or this_team.has_guide != 1: - logging.warning(f'Team_id {team_id} attempted to pull ratings') - db.close() - return 'Your team does not have the ratings guide enabled. If you have purchased a copy ping Cal to ' \ - 'make sure it is enabled on your team. If you are interested you can pick it up here (thank you!): ' \ - 'https://ko-fi.com/manticorum/shop' - +def get_scouting_dfs(cardset_id: list = None): all_ratings = BattingCardRatings.select() if cardset_id is not None: set_players = Player.select(Player.player_id).where(Player.cardset_id << cardset_id) @@ -178,14 +170,192 @@ async def get_card_scouting(team_id: int, ts: str, cardset_id: list = Query(defa vr = pd.DataFrame(vr_vals) db.close() - output = pd.merge(vl, vr, on='player_id', suffixes=('_vl', '_vr')) + bat_df = pd.merge(vl, vr, on='player_id', suffixes=('_vl', '_vr')).set_index('player_id', drop=False) + # output['Range P'] = '' + # output['Range C'] = '' + # output['Range 1B'] = '' + # output['Range 2B'] = '' + # output['Range 3B'] = '' + # output['Range SS'] = '' + # output['Range LF'] = '' + # output['Range CF'] = '' + # output['Range RF'] = '' + # output['Error P'] = '' + # output['Error C'] = '' + # output['Error 1B'] = '' + # output['Error 2B'] = '' + # output['Error 3B'] = '' + # output['Error SS'] = '' + # output['Error LF'] = '' + # output['Error CF'] = '' + # output['Error RF'] = '' + # output['Arm C'] = '' + # output['Throw C'] = '' + # output['PB C'] = '' + # output['Arm OF'] = '' + + logging.info(f'bat_df: {bat_df}') + + positions = CardPosition.select() + if cardset_id is not None: + set_players = Player.select(Player.player_id).where(Player.cardset_id << cardset_id) + positions = positions.where(CardPosition.player << set_players) + + series_list = [] + for pos_code in ['P', 'C', '1B', '2B', '3B', 'SS', 'LF', 'CF', 'RF']: + series_list.append(pd.Series( + dict([(x.player.player_id, x.range) for x in positions.where(CardPosition.position == pos_code)]), + name=f'Range {pos_code}' + )) + series_list.append(pd.Series( + dict([(x.player.player_id, x.error) for x in positions.where(CardPosition.position == pos_code)]), + name=f'Error {pos_code}' + )) + # bat_df.join(pd.Series( + # dict([(x.player.player_id, x.range) for x in positions.where(CardPosition.position == pos_code)]), + # name=f'Range {pos_code}' + # )) + # bat_df.join(pd.Series( + # dict([(x.player.player_id, x.error) for x in positions.where(CardPosition.position == pos_code)]), + # name=f'Error {pos_code}' + # )) + + series_list.append(pd.Series( + dict([(x.player.player_id, x.arm) for x in positions.where(CardPosition.position << ['LF', 'CF', 'RF'])]), + name=f'Arm OF' + )) + series_list.append(pd.Series( + dict([(x.player.player_id, x.arm) for x in positions.where(CardPosition.position == 'C')]), + name=f'Arm C' + )) + series_list.append(pd.Series( + dict([(x.player.player_id, x.pb) for x in positions.where(CardPosition.position == 'C')]), + name=f'PB C' + )) + series_list.append(pd.Series( + dict([(x.player.player_id, x.overthrow) for x in positions.where(CardPosition.position == 'C')]), + name=f'Throw C' + )) + + logging.info(f'series_list: {series_list}') + + # for x in positions: + # if x.position != 'DH': + # output.at[f'{x.player.player_id}', f'Range {x.position}'] = x.range # vals in .at list are reversed + # output.at[f'{x.player.player_id}', f'Error {x.position}'] = x.error + # if x.position in ['LF', 'CF', 'RF']: + # output.at[f'{x.player.player_id}', f'Arm OF'] = x.arm + # if x.position == 'C': + # output.at[f'{x.player.player_id}', f'Arm C'] = x.arm + # output.at[f'{x.player.player_id}', f'PB C'] = x.pb + # output.at[f'{x.player.player_id}', f'Throw C'] = x.overthrow + + return bat_df.join(series_list) + + +@router.get('/scouting') +async def get_card_scouting(team_id: int, ts: str, cardset_id: list = Query(default=None)): + this_team = Team.get_or_none(Team.id == team_id) + logging.debug(f'Team: {this_team} / has_guide: {this_team.has_guide}') + if this_team is None or ts != this_team.team_hash() or this_team.has_guide != 1: + logging.warning(f'Team_id {team_id} attempted to pull ratings') + db.close() + return 'Your team does not have the ratings guide enabled. If you have purchased a copy ping Cal to ' \ + 'make sure it is enabled on your team. If you are interested you can pick it up here (thank you!): ' \ + 'https://ko-fi.com/manticorum/shop' + + # all_ratings = BattingCardRatings.select() + # if cardset_id is not None: + # set_players = Player.select(Player.player_id).where(Player.cardset_id << cardset_id) + # set_cards = BattingCard.select(BattingCard.id).where(BattingCard.player << set_players) + # all_ratings = all_ratings.where(BattingCardRatings.battingcard << set_cards) + # + # vl_query = all_ratings.where(BattingCardRatings.vs_hand == 'L') + # vr_query = all_ratings.where(BattingCardRatings.vs_hand == 'R') + # + # vl_vals = [model_to_dict(x) for x in vl_query] + # for x in vl_vals: + # x.update(x['battingcard']) + # x['player_id'] = x['battingcard']['player']['player_id'] + # x['player_name'] = x['battingcard']['player']['p_name'] + # x['rarity'] = x['battingcard']['player']['rarity']['name'] + # x['cardset_id'] = x['battingcard']['player']['cardset']['id'] + # x['cardset_name'] = x['battingcard']['player']['cardset']['name'] + # del x['battingcard'] + # del x['player'] + # + # vr_vals = [model_to_dict(x) for x in vr_query] + # for x in vr_vals: + # x['player_id'] = x['battingcard']['player']['player_id'] + # del x['battingcard'] + # + # vl = pd.DataFrame(vl_vals) + # vr = pd.DataFrame(vr_vals) + # db.close() + + output = get_scouting_dfs(cardset_id) first = ['player_id', 'player_name', 'cardset_name', 'rarity', 'hand', 'variant'] exclude = first + ['id_vl', 'id_vr', 'vs_hand_vl', 'vs_hand_vr'] - output = output[first + [col for col in output.columns if col not in exclude]].sort_values(by=['player_id']) + output = output[first + [col for col in output.columns if col not in exclude]] # output = output.sort_values(by=['player_id']) return Response(content=pd.DataFrame(output).to_csv(index=False), media_type='text/csv') +@router.get('/basic') +async def get_basic_scouting(cardset_id: list = Query(default=None)): + raw_data = get_scouting_dfs(cardset_id) + logging.info(f'output: {raw_data}') + + def get_raw_speed(df_data): + speed_raw = df_data['running'] / 20 + df_data['steal_jump'] + if df_data['steal_auto']: + speed_raw += 0.5 + return speed_raw + + raw_data['speed_raw'] = raw_data.apply(get_raw_speed, axis=1) + raw_data['speed_rank'] = raw_data['speed_raw'].rank(pct=True) + raw_data['Speed'] = round(raw_data['speed_rank'] * 100) + + def get_raw_steal(df_data): + return ( + ((df_data['steal_high'] / 20) + (df_data['steal_low'] / 20)) * df_data['steal_jump'] + ) + + raw_data['steal_raw'] = raw_data.apply(get_raw_steal, axis=1) + raw_data['steal_rank'] = raw_data['steal_raw'].rank(pct=True) + raw_data['Steal'] = round(raw_data['steal_rank'] * 100) + + def get_raw_reaction(df_data): + raw_total = 0 + for pos_range in [df_data['Range C'], df_data['Range 1B'], df_data['Range 2B'], df_data['Range 3B'], + df_data['Range SS'], df_data['Range LF'], df_data['Range CF'], df_data['Range RF']]: + if pd.notna(pos_range): + raw_total += 10 ** (5 - pos_range) + return raw_total + + raw_data['reaction_raw'] = raw_data.apply(get_raw_reaction, axis=1) + raw_data['reaction_rank'] = raw_data['reaction_raw'].rank(pct=True) + raw_data['Reaction'] = round(raw_data['reaction_rank'] * 100) + + def get_raw_arm(df_data): + of_arm = None + # get top of pos + # Neg arm * -5 / (6 - Pos arm) * 3 + # apply pos multiplier (rf: 1.5, cf: 1, lf: 0.5) + # add value by pos (rf: (6-rf_range) * 4, cf: (6-cf_range) * 3,lf: (6-lf_range) * 2) + + if_arm = None + # 100 - (50 - ((6-3b_range) * 5) + (6-ss_range) * 4 + (6-2b_range) * 3 + (6-1b_range) ) + + c_arm = None + # -5: 100 + # (10 - c_arm) * 3 + (20 - c_pb) + (20 - c_overthrow) - c_error + 20 + + output = raw_data[['player_id', 'player_name', 'cardset_name', 'Speed', 'Steal', 'Reaction']] + # raw_data.sort_values(by=['player_id'], inplace=True) + return Response(content=output.to_csv(index=True), media_type='text/csv') + + @router.get('/{ratings_id}') async def get_one_rating(ratings_id: int, token: str = Depends(oauth2_scheme)): if not valid_token(token):