patrickramos commited on
Commit
c6f6b34
·
1 Parent(s): a504793

Fix Z-Swing% and Chase% and arrange player and batter columns into tabs

Browse files
Files changed (2) hide show
  1. player_team_leaderboard.py +81 -54
  2. stats.py +3 -3
player_team_leaderboard.py CHANGED
@@ -58,16 +58,36 @@ def create_player_team_leaderboard_app(player_team_type):
58
  # stats
59
  if pitching:
60
  pct_stats = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
61
- stats_with_pctls = ['FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'F-Str%', 'PAR%', 'Ball%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Behind%']
62
- cols = ['Pitcher', 'Team', 'Throws', 'IP', 'TBF', 'FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
 
 
 
 
 
 
 
 
 
63
  if team:
64
- cols = [col for col in cols if col not in ('Pitcher', 'Throws')]
 
65
  else:
66
  pct_stats = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
67
  stats_with_pctls = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%'] # , 'OBP']
68
- cols = ['Batter', 'Team', 'Bats', 'PA', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%']#, 'AB', 'H', 'BB', 'HBP', 'SF', 'OBP']
 
 
 
 
 
 
 
 
69
  if team:
70
- cols = [col for col in cols if col not in ('Batter', 'Bats')]
 
 
71
 
72
  # col names
73
  player_type = 'pitcher' if pitching else 'batter'
@@ -119,44 +139,47 @@ def create_player_team_leaderboard_app(player_team_type):
119
  if include_teams is not None:
120
  pitcher_stats = pitcher_stats.filter(pl.col('Team').is_in(include_teams))
121
 
122
- styling = []
123
- for i, row in enumerate(pitcher_stats[cols].iter_rows()):
124
- styling_row = []
125
- for col, item in zip(pitcher_stats[cols].columns, row):
126
- # _styling = 'font-size: 0.75em; '
127
- if col in stats_with_pctls:
128
- r, g, b = (stat_cmap([pitcher_stats[f'{col}_pctl'][i]])[0, :3]*255).astype(np.uint8)
129
- styling_row.append(f'color: black; background-color: rgba({r}, {g}, {b})')
130
- elif col == 'Team':
131
- styling_row.append(f'color: {get_text_color_from_team(item)}; background-color: {team_names_short_to_color[item]}')
132
- else:
133
- styling_row.append('')
134
- styling.append(styling_row)
135
-
136
- display_value = []
137
- for row in pitcher_stats[cols].iter_rows():
138
- display_value_row = []
139
- for col, item in zip(cols, row):
140
- if col in pct_stats:
141
- display_value_row.append(f'{item:.1f}%')
142
- elif col in ['OBP']:
143
- display_value_row.append(f'{item:.3f}')
144
- elif isinstance(item, float):
145
- display_value_row.append(f'{item:.1f}')
146
- else:
147
- display_value_row.append(item)
148
- display_value.append(display_value_row)
149
-
150
- value = {
151
- 'data': pitcher_stats[cols].rows(),
152
- 'headers': cols,
153
- 'metadata': {
154
- 'styling': styling,
155
- 'display_value': display_value,
156
- }
157
- }
158
-
159
- return value
 
 
 
160
 
161
 
162
  now = datetime.now()
@@ -184,25 +207,29 @@ def create_player_team_leaderboard_app(player_team_type):
184
 
185
  search = gr.Button('Search')
186
  pin_columns = gr.Checkbox(True, label='Pin columns')
187
- leaderboard = gr.DataFrame(
188
- pl.DataFrame({'Pitcher': [], 'Pitch': []}),
189
- column_widths=[get_col_width(col, player_team_type) for col in cols],
190
- show_copy_button=True,
191
- show_search='filter',
192
- pinned_columns=1,
193
- elem_id='leaderboard'
194
- )
 
 
 
 
195
 
196
  gr.Markdown(notes)
197
 
198
- search.click(gr_create_player_team_leaderboard, inputs=[start_date, end_date, min_ip, qualified, pitcher_lr, batter_lr, include_teams], outputs=leaderboard)
199
  # gr.api(gr_create_player_team_leaderboard, api_name=f'gr_create_{player_team_type.replace(" ", "_")}_leaderboard')
200
  all_teams.click(lambda _teams : [] if _teams == TEAMS else TEAMS, inputs=include_teams, outputs=include_teams)
201
  qualified.change(lambda qualified: gr.Number(interactive=not qualified), inputs=qualified, outputs=min_ip)
202
  pin_columns.input(
203
- lambda pin: gr.DataFrame(pinned_columns=1 if pin else None),
204
  inputs=pin_columns,
205
- outputs=leaderboard
206
  )
207
 
208
  return app
 
58
  # stats
59
  if pitching:
60
  pct_stats = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
61
+ stats_with_pctls = ['FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Behind%']
62
+ # cols = ['Pitcher', 'Team', 'Throws', 'IP', 'TBF', 'FB Velo', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'Strike%', 'Ball%', 'F-Str%', 'PAR%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
63
+ prefix_cols = ['Pitcher', 'Team', 'Throws', 'IP', 'TBF', 'FB Velo', 'K%', 'BB%']
64
+ plate_disc_cols = ['Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%']
65
+ batted_ball_cols = ['GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%']
66
+ approach_cols = ['Strike%', 'Ball%', 'F-Str%', 'PAR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%', 'Behind%']
67
+ all_cols = {
68
+ theme: prefix_cols + cols
69
+ for theme, cols
70
+ in {'Plate Discipline': plate_disc_cols, 'Batted Ball': batted_ball_cols, 'Approach': approach_cols}.items()
71
+ }
72
  if team:
73
+ # cols = [col for col in cols if col not in ('Pitcher', 'Throws')]
74
+ prefix_cols = [col for col in prefix_cols if col not in ('Pitcher', 'Throws')]
75
  else:
76
  pct_stats = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%', 'Arm%', 'Glove%', 'High%', 'Low%', 'MM%']
77
  stats_with_pctls = ['K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%', 'Zone%'] # , 'OBP']
78
+ # cols = ['Batter', 'Team', 'Bats', 'PA', 'K%', 'BB%', 'Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%', 'GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%']#, 'AB', 'H', 'BB', 'HBP', 'SF', 'OBP']
79
+ prefix_cols = ['Batter', 'Team', 'Bats', 'PA', 'K%', 'BB%']
80
+ plate_disc_cols = ['Swing%', 'Z-Swing%', 'Chase%', 'Contact%', 'Z-Contact%', 'O-Contact%', 'SwStr%', 'Whiff%', 'CSW%']
81
+ batted_ball_cols = ['GB%', 'FB%', 'LD%', 'OFFB%', 'IFFB%', 'AIR%']
82
+ all_cols = {
83
+ theme: prefix_cols + cols
84
+ for theme, cols
85
+ in {'Plate Discipline': plate_disc_cols, 'Batted Ball': batted_ball_cols}.items()
86
+ }
87
  if team:
88
+ # cols = [col for col in cols if col not in ('Batter', 'Bats')]
89
+ prefix_cols = [col for col in prefix_cols if col not in ('Batter', 'Bats')]
90
+
91
 
92
  # col names
93
  player_type = 'pitcher' if pitching else 'batter'
 
139
  if include_teams is not None:
140
  pitcher_stats = pitcher_stats.filter(pl.col('Team').is_in(include_teams))
141
 
142
+ def create_df_value(cols):
143
+ styling = []
144
+ for i, row in enumerate(pitcher_stats[cols].iter_rows()):
145
+ styling_row = []
146
+ for col, item in zip(pitcher_stats[cols].columns, row):
147
+ # _styling = 'font-size: 0.75em; '
148
+ if col in stats_with_pctls:
149
+ r, g, b = (stat_cmap([pitcher_stats[f'{col}_pctl'][i]])[0, :3]*255).astype(np.uint8)
150
+ styling_row.append(f'color: black; background-color: rgba({r}, {g}, {b})')
151
+ elif col == 'Team':
152
+ styling_row.append(f'color: {get_text_color_from_team(item)}; background-color: {team_names_short_to_color[item]}')
153
+ else:
154
+ styling_row.append('')
155
+ styling.append(styling_row)
156
+
157
+ display_value = []
158
+ for row in pitcher_stats[cols].iter_rows():
159
+ display_value_row = []
160
+ for col, item in zip(cols, row):
161
+ if col in pct_stats:
162
+ display_value_row.append(f'{item:.1f}%')
163
+ elif col in ['OBP']:
164
+ display_value_row.append(f'{item:.3f}')
165
+ elif isinstance(item, float):
166
+ display_value_row.append(f'{item:.1f}')
167
+ else:
168
+ display_value_row.append(item)
169
+ display_value.append(display_value_row)
170
+
171
+ value = {
172
+ 'data': pitcher_stats[cols].rows(),
173
+ 'headers': cols,
174
+ 'metadata': {
175
+ 'styling': styling,
176
+ 'display_value': display_value,
177
+ }
178
+ }
179
+
180
+ return value
181
+
182
+ return [create_df_value(cols) for cols in all_cols.values()]
183
 
184
 
185
  now = datetime.now()
 
207
 
208
  search = gr.Button('Search')
209
  pin_columns = gr.Checkbox(True, label='Pin columns')
210
+ leaderboards = []
211
+ for theme, cols in all_cols.items():
212
+ with gr.Tab(theme):
213
+ leaderboard = gr.DataFrame(
214
+ pl.DataFrame({'Pitcher': [], 'Pitch': []}),
215
+ column_widths=[get_col_width(col, player_team_type) for col in cols],
216
+ show_copy_button=True,
217
+ show_search='filter',
218
+ pinned_columns=1,
219
+ elem_id='leaderboard'
220
+ )
221
+ leaderboards.append(leaderboard)
222
 
223
  gr.Markdown(notes)
224
 
225
+ search.click(gr_create_player_team_leaderboard, inputs=[start_date, end_date, min_ip, qualified, pitcher_lr, batter_lr, include_teams], outputs=leaderboards)
226
  # gr.api(gr_create_player_team_leaderboard, api_name=f'gr_create_{player_team_type.replace(" ", "_")}_leaderboard')
227
  all_teams.click(lambda _teams : [] if _teams == TEAMS else TEAMS, inputs=include_teams, outputs=include_teams)
228
  qualified.change(lambda qualified: gr.Number(interactive=not qualified), inputs=qualified, outputs=min_ip)
229
  pin_columns.input(
230
+ lambda pin: [gr.DataFrame(pinned_columns=1 if pin else None)]*len(all_cols),
231
  inputs=pin_columns,
232
+ outputs=leaderboards
233
  )
234
 
235
  return app
stats.py CHANGED
@@ -9,8 +9,8 @@ from convert import verify_and_return_presult
9
  valid_pitch = pl.col('x').is_not_null() & pl.col('y').is_not_null() & (pl.col('ballSpeed') > 0)
10
 
11
  swing = (pl.col('swing').sum() / pl.col('pitch').sum()).alias('Swing%')
12
- z_swing = ((pl.col('swing') & pl.col('zone')).sum() / pl.col('pitch').sum()).alias('Z-Swing%')
13
- chase = ((pl.col('swing') & ~pl.col('zone')).sum() / pl.col('pitch').sum()).alias('Chase%')
14
  contact = ((pl.col('swing') & ~pl.col('whiff')).sum()/pl.col('swing').sum()).alias('Contact%')
15
  z_con = ((pl.col('zone') & pl.col('swing') & ~pl.col('whiff')).sum()/(pl.col('zone') & pl.col('swing')).sum()).alias('Z-Contact%')
16
  o_con = ((~pl.col('zone') & pl.col('swing') & ~pl.col('whiff')).sum()/(~pl.col('zone') & pl.col('swing')).sum()).alias('O-Contact%')
@@ -23,7 +23,7 @@ ball = (is_ball.sum() / pl.col('pitch').sum()).alias('Ball%')
23
  strike = (is_non_ball.sum() / pl.col('pitch').sum()).alias('Strike%')
24
  is_two_str = pl.col('before_s') == 2 # named this way in case I use two_str for 2-Str%
25
  first_count = (pl.col('before_s') == 0) & (pl.col('before_b') == 0)
26
- f_strike = ((is_non_ball & first_count).sum() / first_count.sum()).alias('F-Str%')
27
  par = (((is_two_str & pl.col('presult').str.contains('strikeout')).sum()) / is_two_str.sum()).alias('PAR%')
28
  behind = (((pl.col('before_b') > pl.col('before_s')) & (pl.col('before_s') < 2) & (pl.col('before_b') > 1)).sum() / pl.len()).alias('Behind%')
29
  zone = (pl.col('zone').sum() / pl.col('pitch').sum()).alias('Zone%')
 
9
  valid_pitch = pl.col('x').is_not_null() & pl.col('y').is_not_null() & (pl.col('ballSpeed') > 0)
10
 
11
  swing = (pl.col('swing').sum() / pl.col('pitch').sum()).alias('Swing%')
12
+ z_swing = ((pl.col('swing') & pl.col('zone')).sum() / pl.col('zone').sum()).alias('Z-Swing%')
13
+ chase = ((pl.col('swing') & ~pl.col('zone')).sum() / (~pl.col('zone')).sum()).alias('Chase%')
14
  contact = ((pl.col('swing') & ~pl.col('whiff')).sum()/pl.col('swing').sum()).alias('Contact%')
15
  z_con = ((pl.col('zone') & pl.col('swing') & ~pl.col('whiff')).sum()/(pl.col('zone') & pl.col('swing')).sum()).alias('Z-Contact%')
16
  o_con = ((~pl.col('zone') & pl.col('swing') & ~pl.col('whiff')).sum()/(~pl.col('zone') & pl.col('swing')).sum()).alias('O-Contact%')
 
23
  strike = (is_non_ball.sum() / pl.col('pitch').sum()).alias('Strike%')
24
  is_two_str = pl.col('before_s') == 2 # named this way in case I use two_str for 2-Str%
25
  first_count = (pl.col('before_s') == 0) & (pl.col('before_b') == 0)
26
+ f_strike = ((is_non_ball & first_count).sum() / first_count.sum()).alias('F-Str%')
27
  par = (((is_two_str & pl.col('presult').str.contains('strikeout')).sum()) / is_two_str.sum()).alias('PAR%')
28
  behind = (((pl.col('before_b') > pl.col('before_s')) & (pl.col('before_s') < 2) & (pl.col('before_b') > 1)).sum() / pl.len()).alias('Behind%')
29
  zone = (pl.col('zone').sum() / pl.col('pitch').sum()).alias('Zone%')