Spaces:
Build error
Build error
Update app.py
Browse files
app.py
CHANGED
|
@@ -4,12 +4,15 @@ st.set_page_config(layout="wide")
|
|
| 4 |
for name in dir():
|
| 5 |
if not name.startswith('_'):
|
| 6 |
del globals()[name]
|
| 7 |
-
|
| 8 |
import numpy as np
|
| 9 |
import pandas as pd
|
| 10 |
import streamlit as st
|
| 11 |
import gspread
|
| 12 |
import gc
|
|
|
|
|
|
|
|
|
|
| 13 |
|
| 14 |
@st.cache_resource
|
| 15 |
def init_conn():
|
|
@@ -78,6 +81,8 @@ def init_baselines():
|
|
| 78 |
gamelog_table['spread'] = (gamelog_table['opp_score'] - gamelog_table['team_score']).abs()
|
| 79 |
gamelog_table['GAME_DATE'] = pd.to_datetime(gamelog_table['GAME_DATE']).dt.date
|
| 80 |
|
|
|
|
|
|
|
| 81 |
gamelog_table = gamelog_table.set_axis(['Player', 'Pos', 'game_id', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
| 82 |
'FG3A', 'FG3%', 'FTM', 'FTA', 'FT%', 'OREB Chance', 'OREB', 'DREB Chance', 'DREB', 'REB Chance', 'REB',
|
| 83 |
'Passes', 'Alt Assists', 'FT Assists', 'Assists', 'Stl', 'Blk', 'Tov', 'PF', 'DD', 'TD', 'Fantasy', 'FD_Fantasy',
|
|
@@ -94,9 +99,20 @@ def init_baselines():
|
|
| 94 |
rot_table[data_cols] = rot_table[data_cols].apply(pd.to_numeric, errors='coerce')
|
| 95 |
rot_table = rot_table[rot_table['Player'] != 0]
|
| 96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 97 |
timestamp = gamelog_table['Date'].max()
|
| 98 |
|
| 99 |
-
return gamelog_table, rot_table, timestamp
|
| 100 |
|
| 101 |
@st.cache_data(show_spinner=False)
|
| 102 |
def seasonlong_build(data_sample):
|
|
@@ -197,7 +213,7 @@ def split_frame(input_df, rows):
|
|
| 197 |
def convert_df_to_csv(df):
|
| 198 |
return df.to_csv().encode('utf-8')
|
| 199 |
|
| 200 |
-
gamelog_table, rot_table, timestamp = init_baselines()
|
| 201 |
t_stamp = f"Updated through: " + str(timestamp) + f" CST"
|
| 202 |
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 203 |
basic_season_cols = ['Pos', 'Team', 'Min']
|
|
@@ -217,7 +233,7 @@ indv_players = gamelog_table.drop_duplicates(subset='Player')
|
|
| 217 |
total_players = indv_players.Player.values.tolist()
|
| 218 |
total_dates = gamelog_table.Date.values.tolist()
|
| 219 |
|
| 220 |
-
tab1, tab2, tab3, tab4 = st.tabs(['Gamelogs', 'Correlation Matrix', 'Position vs. Opp', 'Rotations'])
|
| 221 |
|
| 222 |
with tab1:
|
| 223 |
st.info(t_stamp)
|
|
@@ -225,7 +241,7 @@ with tab1:
|
|
| 225 |
with col1:
|
| 226 |
if st.button("Reset Data", key='reset1'):
|
| 227 |
st.cache_data.clear()
|
| 228 |
-
gamelog_table, rot_table = init_baselines()
|
| 229 |
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 230 |
basic_season_cols = ['Pos', 'Team', 'Min']
|
| 231 |
data_cols = ['team_score', 'opp_score', 'spread', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
|
@@ -350,7 +366,7 @@ with tab2:
|
|
| 350 |
with col1:
|
| 351 |
if st.button("Reset Data", key='reset2'):
|
| 352 |
st.cache_data.clear()
|
| 353 |
-
gamelog_table, rot_table = init_baselines()
|
| 354 |
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 355 |
basic_season_cols = ['Pos', 'Team', 'Min']
|
| 356 |
data_cols = ['team_score', 'opp_score', 'spread', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
|
@@ -441,7 +457,7 @@ with tab3:
|
|
| 441 |
with col1:
|
| 442 |
if st.button("Reset Data", key='reset3'):
|
| 443 |
st.cache_data.clear()
|
| 444 |
-
gamelog_table, rot_table = init_baselines()
|
| 445 |
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 446 |
basic_season_cols = ['Pos', 'Team', 'Min']
|
| 447 |
data_cols = ['team_score', 'opp_score', 'spread', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
|
@@ -524,7 +540,7 @@ with tab4:
|
|
| 524 |
with col1:
|
| 525 |
if st.button("Reset Data", key='reset4'):
|
| 526 |
st.cache_data.clear()
|
| 527 |
-
gamelog_table, rot_table = init_baselines()
|
| 528 |
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 529 |
basic_season_cols = ['Pos', 'Team', 'Min']
|
| 530 |
data_cols = ['team_score', 'opp_score', 'spread', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
|
@@ -563,4 +579,100 @@ with tab4:
|
|
| 563 |
data=convert_df_to_csv(rot_display),
|
| 564 |
file_name='Rotations_NBA_View.csv',
|
| 565 |
mime='text/csv',
|
| 566 |
-
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4 |
for name in dir():
|
| 5 |
if not name.startswith('_'):
|
| 6 |
del globals()[name]
|
| 7 |
+
|
| 8 |
import numpy as np
|
| 9 |
import pandas as pd
|
| 10 |
import streamlit as st
|
| 11 |
import gspread
|
| 12 |
import gc
|
| 13 |
+
import plotly.express as px
|
| 14 |
+
import plotly.io as pio
|
| 15 |
+
pio.renderers.default='browser'
|
| 16 |
|
| 17 |
@st.cache_resource
|
| 18 |
def init_conn():
|
|
|
|
| 81 |
gamelog_table['spread'] = (gamelog_table['opp_score'] - gamelog_table['team_score']).abs()
|
| 82 |
gamelog_table['GAME_DATE'] = pd.to_datetime(gamelog_table['GAME_DATE']).dt.date
|
| 83 |
|
| 84 |
+
spread_dict = dict(zip(gamelog_table['GAME_ID'], gamelog_table['spread']))
|
| 85 |
+
|
| 86 |
gamelog_table = gamelog_table.set_axis(['Player', 'Pos', 'game_id', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
| 87 |
'FG3A', 'FG3%', 'FTM', 'FTA', 'FT%', 'OREB Chance', 'OREB', 'DREB Chance', 'DREB', 'REB Chance', 'REB',
|
| 88 |
'Passes', 'Alt Assists', 'FT Assists', 'Assists', 'Stl', 'Blk', 'Tov', 'PF', 'DD', 'TD', 'Fantasy', 'FD_Fantasy',
|
|
|
|
| 99 |
rot_table[data_cols] = rot_table[data_cols].apply(pd.to_numeric, errors='coerce')
|
| 100 |
rot_table = rot_table[rot_table['Player'] != 0]
|
| 101 |
|
| 102 |
+
worksheet = sh.worksheet('Rotation_stats')
|
| 103 |
+
raw_display = pd.DataFrame(worksheet.get_values())
|
| 104 |
+
raw_display.columns = raw_display.iloc[0]
|
| 105 |
+
raw_display = raw_display[1:]
|
| 106 |
+
raw_display = raw_display.reset_index(drop=True)
|
| 107 |
+
game_rot = raw_display[raw_display['PLAYER_NAME'] != ""]
|
| 108 |
+
data_cols = game_rot.columns.drop(['PLAYER_NAME', 'POS', 'TEAM_ABBREVIATION', 'OPP_ABBREVIATION', 'TEAM_NAME', 'OPP_NAME', 'GAME_DATE',
|
| 109 |
+
'MATCHUP', 'WL', 'backlog_lookup', 'Task', 'game_players'])
|
| 110 |
+
game_rot[data_cols] = game_rot[data_cols].apply(pd.to_numeric, errors='coerce')
|
| 111 |
+
game_rot['spread'] = game_rot['GAME_ID'].map(spread_dict)
|
| 112 |
+
|
| 113 |
timestamp = gamelog_table['Date'].max()
|
| 114 |
|
| 115 |
+
return gamelog_table, rot_table, game_rot, timestamp
|
| 116 |
|
| 117 |
@st.cache_data(show_spinner=False)
|
| 118 |
def seasonlong_build(data_sample):
|
|
|
|
| 213 |
def convert_df_to_csv(df):
|
| 214 |
return df.to_csv().encode('utf-8')
|
| 215 |
|
| 216 |
+
gamelog_table, rot_table, game_rot, timestamp = init_baselines()
|
| 217 |
t_stamp = f"Updated through: " + str(timestamp) + f" CST"
|
| 218 |
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 219 |
basic_season_cols = ['Pos', 'Team', 'Min']
|
|
|
|
| 233 |
total_players = indv_players.Player.values.tolist()
|
| 234 |
total_dates = gamelog_table.Date.values.tolist()
|
| 235 |
|
| 236 |
+
tab1, tab2, tab3, tab4, tab5 = st.tabs(['Gamelogs', 'Correlation Matrix', 'Position vs. Opp', 'Positional Percentages', 'Game Rotations'])
|
| 237 |
|
| 238 |
with tab1:
|
| 239 |
st.info(t_stamp)
|
|
|
|
| 241 |
with col1:
|
| 242 |
if st.button("Reset Data", key='reset1'):
|
| 243 |
st.cache_data.clear()
|
| 244 |
+
gamelog_table, rot_table, game_rot, timestamp = init_baselines()
|
| 245 |
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 246 |
basic_season_cols = ['Pos', 'Team', 'Min']
|
| 247 |
data_cols = ['team_score', 'opp_score', 'spread', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
|
|
|
| 366 |
with col1:
|
| 367 |
if st.button("Reset Data", key='reset2'):
|
| 368 |
st.cache_data.clear()
|
| 369 |
+
gamelog_table, rot_table, game_rot, timestamp = init_baselines()
|
| 370 |
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 371 |
basic_season_cols = ['Pos', 'Team', 'Min']
|
| 372 |
data_cols = ['team_score', 'opp_score', 'spread', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
|
|
|
| 457 |
with col1:
|
| 458 |
if st.button("Reset Data", key='reset3'):
|
| 459 |
st.cache_data.clear()
|
| 460 |
+
gamelog_table, rot_table, game_rot, timestamp = init_baselines()
|
| 461 |
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 462 |
basic_season_cols = ['Pos', 'Team', 'Min']
|
| 463 |
data_cols = ['team_score', 'opp_score', 'spread', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
|
|
|
| 540 |
with col1:
|
| 541 |
if st.button("Reset Data", key='reset4'):
|
| 542 |
st.cache_data.clear()
|
| 543 |
+
gamelog_table, rot_table, game_rot, timestamp = init_baselines()
|
| 544 |
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 545 |
basic_season_cols = ['Pos', 'Team', 'Min']
|
| 546 |
data_cols = ['team_score', 'opp_score', 'spread', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
|
|
|
| 579 |
data=convert_df_to_csv(rot_display),
|
| 580 |
file_name='Rotations_NBA_View.csv',
|
| 581 |
mime='text/csv',
|
| 582 |
+
)
|
| 583 |
+
|
| 584 |
+
with tab1:
|
| 585 |
+
st.info(t_stamp)
|
| 586 |
+
col1, col2 = st.columns([1, 9])
|
| 587 |
+
with col1:
|
| 588 |
+
if st.button("Reset Data", key='reset5'):
|
| 589 |
+
st.cache_data.clear()
|
| 590 |
+
gamelog_table, rot_table, game_rot, timestamp = init_baselines()
|
| 591 |
+
basic_cols = ['Player', 'Pos', 'Team', 'Opp', 'Season', 'Date', 'Matchup', 'Min']
|
| 592 |
+
basic_season_cols = ['Pos', 'Team', 'Min']
|
| 593 |
+
data_cols = ['team_score', 'opp_score', 'spread', 'Touches', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M',
|
| 594 |
+
'FG3A', 'FG3%', 'FTM', 'FTA', 'FT%', 'OREB Chance', 'OREB', 'DREB Chance', 'DREB', 'REB Chance', 'REB',
|
| 595 |
+
'Passes', 'Alt Assists', 'FT Assists', 'Assists', 'Stl', 'Blk', 'Tov', 'PF', 'DD', 'TD', 'Fantasy', 'FD_Fantasy',
|
| 596 |
+
'Rebound%', 'Assists/Pass', 'Touch_per_min', 'Fantasy/Touch', 'FD Fantasy/Touch']
|
| 597 |
+
season_data_cols = ['Touches', 'Touch/Min', 'Pts', 'FGM', 'FGA', 'FG%', 'FG3M', 'FG3A',
|
| 598 |
+
'FG3%', 'FTM', 'FTA', 'FT%', 'OREB Chance', 'OREB', 'DREB Chance', 'DREB', 'REB Chance', 'REB',
|
| 599 |
+
'Passes', 'Alt Assists', 'FT Assists', 'Assists', 'Stl', 'Blk', 'Tov', 'PF', 'DD', 'TD', 'Fantasy', 'FD_Fantasy',
|
| 600 |
+
'Rebound%', 'Assists/Pass', 'Fantasy/Touch', 'FD Fantasy/Touch']
|
| 601 |
+
indv_teams = gamelog_table.drop_duplicates(subset='Team')
|
| 602 |
+
total_teams = indv_teams.Team.values.tolist()
|
| 603 |
+
indv_rot_teams = rot_table.drop_duplicates(subset='Team')
|
| 604 |
+
total_rot_teams = indv_rot_teams.Team.values.tolist()
|
| 605 |
+
indv_players = gamelog_table.drop_duplicates(subset='Player')
|
| 606 |
+
total_players = indv_players.Player.values.tolist()
|
| 607 |
+
total_dates = gamelog_table.Date.values.tolist()
|
| 608 |
+
|
| 609 |
+
game_rot_view = st.radio("What set would you like to view?", ('Team Rotations', 'Player Rotations'), key='game_rot_view')
|
| 610 |
+
|
| 611 |
+
if game_rot_view == 'Team Rotations':
|
| 612 |
+
game_rot_team = st.selectbox("What team would you like to work with?", options = total_teams, key='game_rot_team')
|
| 613 |
+
team_backlog = game_rot[game_rot['TEAM_ABBREVIATION'] == game_rot_team]
|
| 614 |
+
|
| 615 |
+
game_id_var = st.selectbox("What game would you like to view?", options = team_backlog['backlog_lookup'], key='game_id_var')
|
| 616 |
+
|
| 617 |
+
game_rot_spread = st.slider("Is there a certain spread range you want to view?", 0, 100, (0, 100), key='game_rot_spread')
|
| 618 |
+
|
| 619 |
+
game_rot_min = st.slider("Is there a certain minutes range you want to view?", 0, 60, (0, 60), key='game_rot_min')
|
| 620 |
+
|
| 621 |
+
game_rot_dates = st.radio("Would you like to view all dates or specific ones?", ('All', 'Specific Dates'), key='game_rot_dates')
|
| 622 |
+
|
| 623 |
+
if game_rot_dates == 'Specific Dates':
|
| 624 |
+
game_rot_low_date = st.date_input('Min Date:', value=None, format="YYYY-MM-DD", key='game_rot_low_date')
|
| 625 |
+
if game_rot_low_date is not None:
|
| 626 |
+
game_rot_low_date = pd.to_datetime(low_date).date()
|
| 627 |
+
game_rot_high_date = st.date_input('Max Date:', value=None, format="YYYY-MM-DD", key='game_rot_high_date')
|
| 628 |
+
if game_rot_high_date is not None:
|
| 629 |
+
game_rot_high_date = pd.to_datetime(high_date).date()
|
| 630 |
+
elif game_rot_dates == 'All':
|
| 631 |
+
game_rot_low_date = gamelog_table['Date'].min()
|
| 632 |
+
game_rot_high_date = gamelog_table['Date'].max()
|
| 633 |
+
|
| 634 |
+
|
| 635 |
+
|
| 636 |
+
with col2:
|
| 637 |
+
working_data = game_rot
|
| 638 |
+
if game_rot_view == 'Player Rotations':
|
| 639 |
+
display = st.container()
|
| 640 |
+
working_data = working_data[working_data['GAME_DATE'] >= game_rot_low_date]
|
| 641 |
+
working_data = working_data[working_data['GAME_DATE'] <= game_rot_high_date]
|
| 642 |
+
working_data = working_data[working_data['MIN'] >= game_rot_min[0]]
|
| 643 |
+
working_data = working_data[working_data['MIN'] <= game_rot_min[1]]
|
| 644 |
+
working_data = working_data[working_data['spread'] >= game_rot_spread[0]]
|
| 645 |
+
working_data = working_data[working_data['spread'] <= game_rot_spread[1]]
|
| 646 |
+
check_rotation = working_data[working_data['backlog_lookup'] == game_id_var]
|
| 647 |
+
|
| 648 |
+
fig = px.timeline(check_rotation, x_start="Start", x_end="Finish", y="Task", range_x=[0,check_rotation["Finish"].max()], text='minutes')
|
| 649 |
+
fig.update_yaxes(autorange="reversed")
|
| 650 |
+
|
| 651 |
+
fig.layout.xaxis.type = 'linear'
|
| 652 |
+
fig.data[0].x = check_rotation.delta.tolist()
|
| 653 |
+
fig.add_vline(x=12, line_width=3, line_dash="dash", line_color="green")
|
| 654 |
+
fig.add_vline(x=24, line_width=3, line_dash="dash", line_color="green")
|
| 655 |
+
fig.add_vline(x=36, line_width=3, line_dash="dash", line_color="green")
|
| 656 |
+
# pages = pages.set_index('Player')
|
| 657 |
+
display.plotly_chart(fig, use_container_width=True)
|
| 658 |
+
|
| 659 |
+
elif game_rot_view == 'Team Rotations':
|
| 660 |
+
display = st.container()
|
| 661 |
+
working_data = working_data[working_data['GAME_DATE'] >= game_rot_low_date]
|
| 662 |
+
working_data = working_data[working_data['GAME_DATE'] <= game_rot_high_date]
|
| 663 |
+
working_data = working_data[working_data['MIN'] >= game_rot_min[0]]
|
| 664 |
+
working_data = working_data[working_data['MIN'] <= game_rot_min[1]]
|
| 665 |
+
working_data = working_data[working_data['spread'] >= game_rot_spread[0]]
|
| 666 |
+
working_data = working_data[working_data['spread'] <= game_rot_spread[1]]
|
| 667 |
+
check_rotation = working_data[working_data['backlog_lookup'] == game_id_var]
|
| 668 |
+
|
| 669 |
+
fig = px.timeline(check_rotation, x_start="Start", x_end="Finish", y="Task", range_x=[0,check_rotation["Finish"].max()], text='minutes')
|
| 670 |
+
fig.update_yaxes(autorange="reversed")
|
| 671 |
+
|
| 672 |
+
fig.layout.xaxis.type = 'linear'
|
| 673 |
+
fig.data[0].x = check_rotation.delta.tolist()
|
| 674 |
+
fig.add_vline(x=12, line_width=3, line_dash="dash", line_color="green")
|
| 675 |
+
fig.add_vline(x=24, line_width=3, line_dash="dash", line_color="green")
|
| 676 |
+
fig.add_vline(x=36, line_width=3, line_dash="dash", line_color="green")
|
| 677 |
+
# pages = pages.set_index('Player')
|
| 678 |
+
display.plotly_chart(fig, use_container_width=True)
|