1023 lines
30 KiB
Python
1023 lines
30 KiB
Python
import csv
|
||
import datetime
|
||
import logging
|
||
import math
|
||
from decimal import Decimal
|
||
|
||
import pandas as pd
|
||
import pybaseball as pb
|
||
import random
|
||
import requests
|
||
import time
|
||
|
||
from db_calls import db_get
|
||
from db_calls_card_creation import *
|
||
from bs4 import BeautifulSoup
|
||
|
||
D20_CHANCES = {
|
||
'2': {
|
||
'chances': 1,
|
||
'inc': .05
|
||
},
|
||
'3': {
|
||
'chances': 2,
|
||
'inc': .1
|
||
},
|
||
'4': {
|
||
'chances': 3,
|
||
'inc': .15
|
||
},
|
||
'5': {
|
||
'chances': 4,
|
||
'inc': .2
|
||
},
|
||
'6': {
|
||
'chances': 5,
|
||
'inc': .25
|
||
},
|
||
'7': {
|
||
'chances': 6,
|
||
'inc': .3
|
||
},
|
||
'8': {
|
||
'chances': 5,
|
||
'inc': .25
|
||
},
|
||
'9': {
|
||
'chances': 4,
|
||
'inc': .2
|
||
},
|
||
'10': {
|
||
'chances': 3,
|
||
'inc': .15
|
||
},
|
||
'11': {
|
||
'chances': 2,
|
||
'inc': .1
|
||
},
|
||
'12': {
|
||
'chances': 1,
|
||
'inc': .05
|
||
}
|
||
}
|
||
BLANK_RESULTS = {
|
||
'vL': {
|
||
'1': {
|
||
'2': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'3': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'4': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'5': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'6': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'7': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'8': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'9': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'10': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'11': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'12': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'splits': 0
|
||
},
|
||
'2': {
|
||
'2': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'3': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'4': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'5': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'6': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'7': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'8': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'9': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'10': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'11': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'12': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'splits': 0
|
||
},
|
||
'3': {
|
||
'2': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'3': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'4': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'5': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'6': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'7': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'8': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'9': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'10': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'11': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'12': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'splits': 0
|
||
}
|
||
},
|
||
'vR': {
|
||
'1': {
|
||
'2': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'3': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'4': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'5': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'6': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'7': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'8': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'9': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'10': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'11': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'12': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'splits': 0
|
||
},
|
||
'2': {
|
||
'2': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'3': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'4': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'5': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'6': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'7': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'8': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'9': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'10': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'11': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'12': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'splits': 0
|
||
},
|
||
'3': {
|
||
'2': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'3': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'4': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'5': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'6': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'7': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'8': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'9': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'10': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'11': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'12': {
|
||
'result': None,
|
||
'splits': None,
|
||
'2d6': None
|
||
},
|
||
'splits': 0
|
||
}
|
||
}
|
||
}
|
||
TESTING = False
|
||
YES = ['y', 'yes', 'yeet', 'please', 'yeah']
|
||
CLUB_LIST = {
|
||
'ARI': 'Arizona Diamondbacks',
|
||
'ATL': 'Atlanta Braves',
|
||
'BAL': 'Baltimore Orioles',
|
||
'BOS': 'Boston Red Sox',
|
||
'CHC': 'Chicago Cubs',
|
||
'CHW': 'Chicago White Sox',
|
||
'CIN': 'Cincinnati Reds',
|
||
'CLE': 'Cleveland Guardians',
|
||
'COL': 'Colorado Rockies',
|
||
'DET': 'Detroit Tigers',
|
||
'HOU': 'Houston Astros',
|
||
'KCR': 'Kansas City Royals',
|
||
'LAA': 'Los Angeles Angels',
|
||
'LAD': 'Los Angeles Dodgers',
|
||
'FLA': 'Florida Marlins',
|
||
'MIA': 'Miami Marlins',
|
||
'MIL': 'Milwaukee Brewers',
|
||
'MIN': 'Minnesota Twins',
|
||
'NYM': 'New York Mets',
|
||
'NYY': 'New York Yankees',
|
||
'OAK': 'Oakland Athletics',
|
||
'PHI': 'Philadelphia Phillies',
|
||
'PIT': 'Pittsburgh Pirates',
|
||
'SDP': 'San Diego Padres',
|
||
'SEA': 'Seattle Mariners',
|
||
'SFG': 'San Francisco Giants',
|
||
'STL': 'St Louis Cardinals',
|
||
'TBR': 'Tampa Bay Rays',
|
||
'TEX': 'Texas Rangers',
|
||
'TOR': 'Toronto Blue Jays',
|
||
'WSN': 'Washington Nationals',
|
||
'TOT': 'None',
|
||
'2 Tms': 'None',
|
||
'3 Tms': 'None',
|
||
'4 Tms': 'None'
|
||
}
|
||
FRANCHISE_LIST = {
|
||
'ARI': 'Arizona Diamondbacks',
|
||
'ATL': 'Atlanta Braves',
|
||
'BAL': 'Baltimore Orioles',
|
||
'BOS': 'Boston Red Sox',
|
||
'CHC': 'Chicago Cubs',
|
||
'CHW': 'Chicago White Sox',
|
||
'CIN': 'Cincinnati Reds',
|
||
'CLE': 'Cleveland Guardians',
|
||
'COL': 'Colorado Rockies',
|
||
'DET': 'Detroit Tigers',
|
||
'HOU': 'Houston Astros',
|
||
'KCR': 'Kansas City Royals',
|
||
'LAA': 'Los Angeles Angels',
|
||
'LAD': 'Los Angeles Dodgers',
|
||
'FLA': 'Miami Marlins',
|
||
'MIA': 'Miami Marlins',
|
||
'MIL': 'Milwaukee Brewers',
|
||
'MIN': 'Minnesota Twins',
|
||
'NYM': 'New York Mets',
|
||
'NYY': 'New York Yankees',
|
||
'OAK': 'Oakland Athletics',
|
||
'PHI': 'Philadelphia Phillies',
|
||
'PIT': 'Pittsburgh Pirates',
|
||
'SDP': 'San Diego Padres',
|
||
'SEA': 'Seattle Mariners',
|
||
'SFG': 'San Francisco Giants',
|
||
'STL': 'St Louis Cardinals',
|
||
'TBR': 'Tampa Bay Rays',
|
||
'TEX': 'Texas Rangers',
|
||
'TOR': 'Toronto Blue Jays',
|
||
'WSN': 'Washington Nationals',
|
||
'TOT': 'None',
|
||
'2 Tms': 'None',
|
||
'3 Tms': 'None',
|
||
'4 Tms': 'None'
|
||
}
|
||
|
||
|
||
def get_args(args):
|
||
logging.info(f'Process arguments: {args}')
|
||
final_args = {}
|
||
for x in args:
|
||
if "=" not in x:
|
||
raise TypeError(f'Invalid <key>=<value> argument: {x}')
|
||
|
||
key, value = x.split("=")
|
||
logging.info(f'key: {key} / value: {value}')
|
||
|
||
if key in final_args:
|
||
raise ValueError(f'Duplicate argument: {key}')
|
||
|
||
final_args[key] = value
|
||
return final_args
|
||
|
||
|
||
async def pd_players_df(cardset_id: int):
|
||
p_query = await db_get(
|
||
'players',
|
||
params=[('inc_dex', False), ('cardset_id', cardset_id), ('short_output', True)]
|
||
)
|
||
if p_query['count'] == 0:
|
||
return pd.DataFrame({
|
||
'player_id': [], 'p_name': [], 'cost': [], 'image': [], 'image2': [], 'mlbclub': [], 'franchise': [],
|
||
'cardset': [], 'set_num': [], 'rarity': [], 'pos_1': [], 'pos_2': [], 'pos_3': [], 'pos_4': [], 'pos_5': [],
|
||
'pos_6': [], 'pos_7': [], 'pos_8': [], 'headshot': [], 'vanity_card': [], 'strat_code': [], 'bbref_id': [],
|
||
'fangr_id': [], 'description': [], 'quantity': [], 'mlbplayer': []
|
||
})
|
||
return pd.DataFrame(p_query['players'])
|
||
|
||
|
||
async def pd_positions_df(cardset_id: int):
|
||
pos_query = await db_get(
|
||
'cardpositions', params=[('cardset_id', cardset_id), ('short_output', True), ('sort', 'innings-desc')])
|
||
if pos_query['count'] == 0:
|
||
raise ValueError('No position ratings returned from Paper Dynasty API')
|
||
all_pos = pd.DataFrame(pos_query['positions']).rename(columns={'player': 'player_id'})
|
||
|
||
return all_pos
|
||
|
||
|
||
def get_pitching_peripherals(season: int):
|
||
url = f'https://www.baseball-reference.com/leagues/majors/{season}-standard-pitching.shtml'
|
||
soup = BeautifulSoup(requests.get(url).text, 'html.parser')
|
||
time.sleep(3)
|
||
table = soup.find('table', {'id': 'players_standard_pitching'})
|
||
headers = []
|
||
data = []
|
||
indeces = []
|
||
for row in table.find_all('tr'):
|
||
row_data = []
|
||
col_names = []
|
||
for cell in row.find_all('td'):
|
||
try:
|
||
player_id = cell['data-append-csv']
|
||
row_data.append(player_id)
|
||
if len(headers) == 0:
|
||
col_names.append('key_bbref')
|
||
except Exception as e:
|
||
pass
|
||
row_data.append(cell.text)
|
||
if len(headers) == 0:
|
||
col_names.append(cell['data-stat'])
|
||
if len(row_data) > 0:
|
||
data.append(row_data)
|
||
indeces.append(row_data[0])
|
||
if len(headers) == 0:
|
||
headers.extend(col_names)
|
||
pit_frame = pd.DataFrame(data, index=indeces, columns=headers).query('key_bbref == key_bbref')
|
||
return pit_frame.drop_duplicates(subset=['key_bbref'], keep='first')
|
||
|
||
|
||
def mround(x, prec=2, base=.05):
|
||
return round(base * round(float(x) / base), prec)
|
||
|
||
|
||
def chances_from_row(row_num):
|
||
if row_num == '2' or row_num == '12':
|
||
return 1
|
||
if row_num == '3' or row_num == '11':
|
||
return 2
|
||
if row_num == '4' or row_num == '10':
|
||
return 3
|
||
if row_num == '5' or row_num == '9':
|
||
return 4
|
||
if row_num == '6' or row_num == '8':
|
||
return 5
|
||
if row_num == '7':
|
||
return 6
|
||
raise ValueError(f'No chance count found for row_num {row_num}')
|
||
|
||
|
||
def legal_splits(tot_chances):
|
||
legal_2d6 = []
|
||
for x in D20_CHANCES:
|
||
num_incs = mround(tot_chances) / D20_CHANCES[x]['inc']
|
||
if num_incs - int(num_incs) == 0 and int(20 - num_incs) > 0:
|
||
legal_2d6.append({
|
||
'2d6': int(x),
|
||
'incs': int(num_incs),
|
||
'bad_chances': mround(D20_CHANCES[x]['chances'] * (int(20 - num_incs) / 20)),
|
||
'bad_incs': int(20 - num_incs)
|
||
})
|
||
|
||
random.shuffle(legal_2d6)
|
||
# if TESTING: print(f'tot_chances: {myround(tot_chances)}')
|
||
# if TESTING: print(f'legal_2d6: {legal_2d6}')
|
||
return legal_2d6
|
||
|
||
|
||
def result_string(tba_data, row_num, split_min=None, split_max=None):
|
||
bold1 = f'{"<b>" if tba_data["bold"] else ""}'
|
||
bold2 = f'{"</b>" if tba_data["bold"] else ""}'
|
||
row_string = f'{"<b> </b>" if int(row_num) < 10 else ""}{row_num}'
|
||
if TESTING: print(f'adding {tba_data["string"]} to row {row_num} / '
|
||
f'split_min: {split_min} / split_max: {split_max}')
|
||
|
||
# No splits; standard result
|
||
if not split_min:
|
||
return f'{bold1}{row_string}-{tba_data["string"]}{bold2}'
|
||
|
||
# With splits
|
||
split_nums = f'{split_min if split_min != 20 else ""}{"-" if split_min != 20 else ""}{split_max}'
|
||
data_string = tba_data["sm-string"] if "sm-string" in tba_data.keys() else tba_data["string"]
|
||
spaces = 18 - len(data_string) - len(split_nums)
|
||
if 'WALK' in data_string:
|
||
spaces -= 3
|
||
elif 'SI**' in data_string:
|
||
spaces += 1
|
||
elif 'DO*' in data_string:
|
||
spaces -= 1
|
||
elif 'DO*' in data_string:
|
||
spaces -= 2
|
||
elif 'so' in data_string:
|
||
spaces += 3
|
||
elif 'gb' in data_string:
|
||
spaces -= 3
|
||
|
||
if TESTING: print(f'len(tba_data["string"]): {len(data_string)} / len(split_nums): {len(split_nums)} '
|
||
f'spaces: {spaces}')
|
||
if split_min == 1 or split_min is None:
|
||
row_output = f'{row_string}-'
|
||
else:
|
||
row_output = '<b> </b>'
|
||
if TESTING: print(f'row_output: {row_output}')
|
||
return f'{bold1}{row_output}{data_string}{" " * spaces}{split_nums}{bold2}'
|
||
|
||
|
||
def result_data(tba_data, row_num, tba_data_bottom=None, top_split_max=None, fatigue=False):
|
||
ret_data = {}
|
||
top_bold1 = f'{"<b>" if tba_data["bold"] else ""}'
|
||
top_bold2 = f'{"</b>" if tba_data["bold"] else ""}'
|
||
bot_bold1 = None
|
||
bot_bold2 = None
|
||
if tba_data_bottom:
|
||
bot_bold1 = f'{"<b>" if tba_data_bottom["bold"] else ""}'
|
||
bot_bold2 = f'{"</b>" if tba_data_bottom["bold"] else ""}'
|
||
|
||
if tba_data_bottom is None:
|
||
ret_data['2d6'] = f'{top_bold1}{int(row_num)}-{top_bold2}'
|
||
ret_data['splits'] = f'{top_bold1}{top_bold2}'
|
||
ret_data['result'] = f'{top_bold1}' \
|
||
f'{tba_data["string"]}{" •" if fatigue else ""}' \
|
||
f'{top_bold2}'
|
||
else:
|
||
ret_data['2d6'] = f'{top_bold1}{int(row_num)}-{top_bold2}\n'
|
||
ret_data['splits'] = f'{top_bold1}1{"-" if top_split_max != 1 else ""}' \
|
||
f'{top_split_max if top_split_max != 1 else ""}{top_bold2}\n' \
|
||
f'{bot_bold1}{top_split_max+1}{"-20" if top_split_max != 19 else ""}{bot_bold2}'
|
||
ret_data['result'] = \
|
||
f'{top_bold1}{tba_data["sm-string"] if "sm-string" in tba_data.keys() else tba_data["string"]}' \
|
||
f'{top_bold2}\n' \
|
||
f'{bot_bold1}' \
|
||
f'{tba_data_bottom["sm-string"] if "sm-string" in tba_data_bottom.keys() else tba_data_bottom["string"]}' \
|
||
f'{bot_bold2}'
|
||
|
||
return ret_data
|
||
|
||
|
||
def get_of(batter_hand, pitcher_hand, pull_side=True):
|
||
if batter_hand == 'R':
|
||
return 'lf' if pull_side else 'rf'
|
||
|
||
if batter_hand == 'L':
|
||
return 'rf' if pull_side else 'lf'
|
||
|
||
if batter_hand == 'S':
|
||
if pitcher_hand == 'L':
|
||
return 'rf' if pull_side else 'rf'
|
||
else:
|
||
return 'lf' if pull_side else 'lf'
|
||
|
||
|
||
def get_col(col_num):
|
||
if col_num == '1':
|
||
return 'one'
|
||
if col_num == '2':
|
||
return 'two'
|
||
if col_num == '3':
|
||
return 'three'
|
||
|
||
|
||
def write_to_csv(output_path, file_name: str, row_data: list):
|
||
# Build the csv output
|
||
fpath = (output_path / f'{file_name}').with_suffix('.csv')
|
||
# logging.info(f'Printing following data to {file_name}:\n\n{row_data}')
|
||
with fpath.open(mode='w+', newline='', encoding='utf-8') as csv_File:
|
||
writer = csv.writer(csv_File)
|
||
writer.writerows(row_data)
|
||
|
||
|
||
def get_position_string(all_pos: list, inc_p: bool):
|
||
if len(all_pos) == 0:
|
||
return 'dh'
|
||
|
||
of_arm = None
|
||
of_error = None
|
||
of_innings = None
|
||
lf_range = None
|
||
lf_innings = 0
|
||
cf_range = None
|
||
cf_innings = 0
|
||
rf_range = None
|
||
rf_innings = 0
|
||
|
||
all_def = []
|
||
|
||
for x in all_pos:
|
||
if x.position == 'OF':
|
||
of_arm = f'{"+" if "-" not in x.arm else ""}{x.arm}'
|
||
of_error = x.error
|
||
of_innings = x.innings
|
||
elif x.position == 'CF':
|
||
cf_range = x.range
|
||
cf_innings = x.innings
|
||
elif x.position == 'LF':
|
||
lf_range = x.range
|
||
lf_innings = x.innings
|
||
elif x.position == 'RF':
|
||
rf_range = x.range
|
||
rf_innings = x.innings
|
||
elif x.position == 'C':
|
||
all_def.append(
|
||
(f'c-{x.range}({"+" if int(x.arm) >= 0 else ""}{x.arm}) e{x.error} T-{x.overthrow}(pb-{x.pb})', x.innings)
|
||
)
|
||
elif 'P' in x.position and not inc_p:
|
||
pass
|
||
else:
|
||
all_def.append((f'{x.position.lower()}-{x.range}e{x.error}', x.innings))
|
||
|
||
if of_arm is not None:
|
||
logging.info(
|
||
f'\n\nProcessing OF player ID {all_pos[0].player_id}\nlf-{lf_range} / cf-{cf_range} / rf-{rf_range}'
|
||
)
|
||
all_of = []
|
||
if lf_innings > 0:
|
||
all_of.append((lf_range, lf_innings, 'lf'))
|
||
if cf_innings > 0:
|
||
all_of.append((cf_range, cf_innings, 'cf'))
|
||
if rf_innings > 0:
|
||
all_of.append((rf_range, rf_innings, 'rf'))
|
||
|
||
logging.info(f'all_of: {all_of}')
|
||
if len(all_of) > 0:
|
||
all_of.sort(key=lambda y: y[1], reverse=True)
|
||
logging.info(f'sorted of: {all_of}')
|
||
out_string = f'{all_of[0][2]}-{all_of[0][0]}({of_arm})e{of_error}'
|
||
if len(all_of) >= 2:
|
||
out_string += f', {all_of[1][2]}-{all_of[1][0]}e{of_error}'
|
||
if len(all_of) >= 3:
|
||
out_string += f', {all_of[2][2]}-{all_of[2][0]}e{of_error}'
|
||
logging.info(f'of string: {out_string}')
|
||
all_def.append((out_string, of_innings))
|
||
|
||
all_def.sort(key=lambda z: z[1], reverse=True)
|
||
|
||
final_defense = ''
|
||
for x in all_def:
|
||
if len(final_defense) > 0:
|
||
final_defense += f', '
|
||
final_defense += f'{x[0]}'
|
||
|
||
return final_defense
|
||
|
||
|
||
def ordered_positions(all_pos: list) -> list:
|
||
if len(all_pos) == 0:
|
||
return ['DH']
|
||
|
||
all_def = []
|
||
|
||
for x in all_pos:
|
||
if x.position not in ['OF', 'P', 'SP', 'RP', 'CP']:
|
||
all_def.append((x.innings, x.position))
|
||
|
||
all_def.sort(key=lambda y: y[0], reverse=True)
|
||
return [x[1] for x in all_def]
|
||
|
||
|
||
def ordered_pitching_positions(all_pos: list) -> list:
|
||
all_def = []
|
||
|
||
for x in all_pos:
|
||
if x.position in ['SP', 'RP', 'CP']:
|
||
all_def.append((x.innings, x.position))
|
||
|
||
all_def.sort(key=lambda y: y[0], reverse=True)
|
||
return [x[1] for x in all_def]
|
||
|
||
|
||
def defense_rg(all_pos: list) -> list:
|
||
rg_data = [
|
||
None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None,
|
||
None, None, None, None, None, None
|
||
]
|
||
all_pitcher = True
|
||
for line in all_pos:
|
||
if 'P' not in line.position:
|
||
all_pitcher = False
|
||
break
|
||
|
||
for line in all_pos:
|
||
if line.position == 'P' and all_pitcher:
|
||
this_pit = PitcherData.get_or_none(PitcherData.player == line.player, PitcherData.cardset == line.cardset)
|
||
if this_pit:
|
||
rg_data[0] = line.range
|
||
rg_data[9] = line.error
|
||
rg_data[22] = this_pit.wild_pitch
|
||
rg_data[23] = this_pit.balk
|
||
elif line.position == 'C':
|
||
rg_data[1] = line.range
|
||
rg_data[10] = line.error
|
||
rg_data[19] = line.arm
|
||
rg_data[20] = line.overthrow
|
||
rg_data[21] = line.pb
|
||
elif line.position == '1B':
|
||
rg_data[2] = line.range
|
||
rg_data[11] = line.error
|
||
elif line.position == '2B':
|
||
rg_data[3] = line.range
|
||
rg_data[12] = line.error
|
||
elif line.position == '3B':
|
||
rg_data[4] = line.range
|
||
rg_data[13] = line.error
|
||
elif line.position == 'SS':
|
||
rg_data[5] = line.range
|
||
rg_data[14] = line.error
|
||
elif line.position == 'LF':
|
||
rg_data[6] = line.range
|
||
elif line.position == 'CF':
|
||
rg_data[7] = line.range
|
||
elif line.position == 'RF':
|
||
rg_data[8] = line.range
|
||
elif line.position == 'OF':
|
||
rg_data[15] = line.error
|
||
rg_data[16] = line.error
|
||
rg_data[17] = line.error
|
||
rg_data[18] = line.arm
|
||
|
||
return rg_data
|
||
|
||
|
||
def sanitize_chance_output(total_chances, min_chances=1.0, rounding=0.05):
|
||
# r_val = mround(total_chances) if total_chances >= min_chances else 0
|
||
r_val = Decimal(total_chances) if total_chances >= min_chances else Decimal(0)
|
||
logging.debug(f'r_val: {r_val}')
|
||
rounded_val = Decimal(float(math.floor(r_val / Decimal(rounding)) * Decimal(rounding))).quantize(Decimal("0.05"))
|
||
if math.floor(rounded_val) == rounded_val:
|
||
return rounded_val
|
||
|
||
exact_chances = [
|
||
Decimal('1.05'), Decimal('1.1'), Decimal('1.2'), Decimal('1.25'), Decimal('1.3'), Decimal('1.35'),
|
||
Decimal('1.4'), Decimal('1.5'), Decimal('1.6'), Decimal('1.65'), Decimal('1.7'), Decimal('1.75'),
|
||
Decimal('1.8'), Decimal('1.9'), Decimal('1.95'), Decimal('2.1'), Decimal('2.2'), Decimal('2.25'),
|
||
Decimal('2.4'), Decimal('2.5'), Decimal('2.55'), Decimal('2.6'), Decimal('2.7'), Decimal('2.75'),
|
||
Decimal('2.8'), Decimal('2.85'), Decimal('3.2'), Decimal('3.25'), Decimal('3.3'), Decimal('3.4'),
|
||
Decimal('3.5'), Decimal('3.6'), Decimal('3.75'), Decimal('3.8'), Decimal('3.9'), Decimal('4.2'),
|
||
Decimal('4.25'), Decimal('4.5'), Decimal('4.75'), Decimal('4.8'), Decimal('5.1'), Decimal('5.4'),
|
||
Decimal('5.7')
|
||
]
|
||
if rounded_val > exact_chances[-1]:
|
||
return rounded_val
|
||
|
||
for x in exact_chances:
|
||
if rounded_val <= x:
|
||
return x
|
||
|
||
|
||
def mlbteam_and_franchise(mlbam_playerid):
|
||
api_url = f'https://statsapi.mlb.com/api/v1/people/{mlbam_playerid}?hydrate=currentTeam'
|
||
logging.info(f'Calling {api_url}')
|
||
p_data = {'mlbclub': None, 'franchise': None}
|
||
# club_list = [
|
||
# 'Arizona Diamondbacks',
|
||
# 'Atlanta Braves',
|
||
# 'Baltimore Orioles',
|
||
# 'Boston Red Sox',
|
||
# 'Chicago Cubs',
|
||
# 'Chicago White Sox',
|
||
# 'Cincinnati Reds',
|
||
# 'Cleveland Guardians',
|
||
# 'Colorado Rockies',
|
||
# 'Detroit Tigers',
|
||
# 'Houston Astros',
|
||
# 'Kansas City Royals',
|
||
# 'Los Angeles Angels',
|
||
# 'Los Angeles Dodgers',
|
||
# 'Miami Marlins',
|
||
# 'Milwaukee Brewers',
|
||
# 'Minnesota Twins',
|
||
# 'New York Mets',
|
||
# 'New York Yankees',
|
||
# 'Oakland Athletics',
|
||
# 'Philadelphia Phillies',
|
||
# 'Pittsburgh Pirates',
|
||
# 'San Diego Padres',
|
||
# 'Seattle Mariners',
|
||
# 'San Francisco Giants',
|
||
# 'St Louis Cardinals',
|
||
# 'Tampa Bay Rays',
|
||
# 'Texas Rangers',
|
||
# 'Toronto Blue Jays',
|
||
# 'Washington Nationals'
|
||
# ]
|
||
|
||
try:
|
||
resp = requests.get(api_url, timeout=2)
|
||
except requests.ReadTimeout as e:
|
||
logging.error(f'mlbteam_and_franchise - ReadTimeout pull MLB team for MLB AM player ID {mlbam_playerid}')
|
||
return p_data
|
||
|
||
if resp.status_code == 200:
|
||
data = resp.json()
|
||
data = data['people'][0]
|
||
logging.debug(f'data: {data}')
|
||
if data['currentTeam']['name'] in CLUB_LIST.values():
|
||
p_data['mlbclub'] = data['currentTeam']['name']
|
||
p_data['franchise'] = data['currentTeam']['name']
|
||
else:
|
||
logging.error(f'Could not set team for {mlbam_playerid}; received {data["currentTeam"]["name"]}')
|
||
else:
|
||
logging.error(f'mlbteam_and_franchise - Bad response from mlbstatsapi: {resp.status_code}')
|
||
|
||
return p_data
|
||
|
||
|
||
def get_all_pybaseball_ids(player_id: list, key_type: str, is_custom: bool = False):
|
||
if is_custom:
|
||
try:
|
||
long_player_id = int(player_id[0])
|
||
if long_player_id >= 999942001:
|
||
backyard_players = [
|
||
'akhan',
|
||
'amkhan',
|
||
'adelvecchio',
|
||
'afrazier',
|
||
'awebber',
|
||
'bblackwood',
|
||
'drobinson',
|
||
'dpetrovich',
|
||
'esteele',
|
||
'ghasselhoff',
|
||
'jsmith',
|
||
'jgarcia',
|
||
'kkawaguchi',
|
||
'kphillips',
|
||
'keckman',
|
||
'lcrocket',
|
||
'llui',
|
||
'mluna',
|
||
'mdubois',
|
||
'mthomas',
|
||
'psanchez',
|
||
'pwheeler',
|
||
'rworthington',
|
||
'rjohnson',
|
||
'rdobbs',
|
||
'sdobbs',
|
||
'swebber',
|
||
'smorgan',
|
||
'tdelvecchio',
|
||
'vkawaguchi'
|
||
]
|
||
return pd.Series(
|
||
{'key_bbref': backyard_players[long_player_id - 999942001],
|
||
'key_fangraphs': player_id[0],
|
||
'key_mlbam': player_id[0],
|
||
'bat_hand': 'L' if long_player_id in [
|
||
999942004, 999942007, 999942010, 999942018, 999942019, 999942020, 999942022
|
||
] else 'R'
|
||
},
|
||
)
|
||
except Exception as e:
|
||
logging.warning(e)
|
||
|
||
q = pb.playerid_reverse_lookup(player_id, key_type=key_type)
|
||
if len(q.values) > 0:
|
||
return_val = q.loc[0]
|
||
else:
|
||
logging.error(f'get_all_pybaseball_ids - Could not find id {player_id} / {key_type} in pybaseball')
|
||
return_val = None
|
||
|
||
return return_val
|
||
|
||
|
||
def sanitize_name(start_name: str) -> str:
|
||
return (start_name
|
||
.replace("é", "e")
|
||
.replace("á", "a")
|
||
.replace(".", "")
|
||
.replace("Á", "A")
|
||
.replace("ñ", "n")
|
||
.replace("ó", "o")
|
||
.replace("í", "i")
|
||
.replace("ú", "u")
|
||
.replace("'", "")
|
||
.replace('-', ' '))
|
||
|
||
|
||
def get_hand(df_data):
|
||
if df_data['Name'][-1] == '*':
|
||
return 'L'
|
||
elif df_data['Name'][-1] == '#':
|
||
return 'S'
|
||
else:
|
||
return 'R'
|
||
|