Spaces:
Build error
Build error
File size: 6,616 Bytes
3d0c0d1 eaf2663 3d0c0d1 eaf2663 3d0c0d1 eaf2663 3d0c0d1 b260f20 3a007f9 3d0c0d1 eaf2663 3d0c0d1 eaf2663 3d0c0d1 306970a 3d0c0d1 65393ab 79797b0 65393ab 79797b0 65393ab eaf2663 3d0c0d1 eaf2663 3d0c0d1 eaf2663 3d0c0d1 eaf2663 3d0c0d1 65393ab 3d0c0d1 3a007f9 3d0c0d1 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
import gradio as gr
# import pandas as pd
from gradio_calendar import Calendar
import polars as pl
from math import ceil
import datetime
import os
from data import df, pitch_stats, league_pitch_stats, player_df
from gradio_function import *
from seasons import LATEST_SEASON
from translate import jp_pitch_to_en_pitch, max_pitch_types
from css import css
os.makedirs('files', exist_ok=True)
def create_pitcher_dashboard():
with gr.Blocks(
css=css
) as demo:
gr.Markdown('''
# NPB data visualization demo
[Data from SportsNavi](https://sports.yahoo.co.jp/)
''')
source_df = gr.State(df)
app_df = gr.State(df)
app_league_df = gr.State(df)
app_pitch_stats = gr.State(pitch_stats)
app_league_pitch_stats = gr.State(league_pitch_stats)
with gr.Row():
player = gr.Dropdown(value=None, choices=sorted(player_df.filter(pl.col('name').is_not_null())['name'].to_list()), label='Player')
start_date = Calendar(value=f'{LATEST_SEASON}-03-01', type='datetime', label='Start Date')
end_date = Calendar(value=f'{LATEST_SEASON}-11-30', type='datetime', label='End Date')
handedness = gr.Radio(value='Both', choices=['Both', 'Left', 'Right'], type='value', interactive=False, label='Batter Handedness')
gr.Markdown('Note: We do not have spring training data, or 2024 postseason data')
# preview = gr.DataFrame()
download_file = gr.DownloadButton(label='Download player data')
with gr.Group():
with gr.Row():
usage = gr.Plot(label='Pitch usage')
velo_summary = gr.Plot(label='Velocity summary', elem_classes='pitch-velo-summary')
loc_summary = gr.Plot(label='Overall location')
gr.Markdown('## Pitch Velocity')
velo_stats = gr.DataFrame(pl.DataFrame([{'Avg. Velo': None, 'League Avg. Velo': None}]), interactive=False, label='Pitch Velocity')
max_locs = len(jp_pitch_to_en_pitch)
locs_per_row = 4
max_rows = ceil(max_locs/locs_per_row)
gr.Markdown('''
## Pitch Locations
Pitcher's persective
<br>
`NPB` refers to the top 10% of pitches thrown across the league with the current search constraints e.g. handedness
<br>
Note: To speed up the KDE, we restrict the league-wide pitches to 5,000 pitches
''')
pitch_rows = []
pitch_groups = []
pitch_names = []
pitch_infos = []
pitch_velos = []
pitch_locs = []
for row in range(max_rows):
visible = row==0
pitch_row = gr.Row(visible=visible)
pitch_rows.append(pitch_row)
with pitch_row:
_locs_per_row = locs_per_row if row < max_rows-1 else max_locs - locs_per_row * (max_rows - 1)
for col in range(_locs_per_row):
with gr.Column(min_width=256):
pitch_group = gr.Group(visible=visible)
pitch_groups.append(pitch_group)
with pitch_group:
pitch_names.append(gr.Markdown(f'### Pitch {col+1}', visible=visible))
pitch_infos.append(gr.DataFrame(pl.DataFrame([{'Whiff%': None, 'CSW%': None}]), interactive=False, visible=visible))
pitch_velos.append(gr.Plot(show_label=False, elem_classes='pitch-velo', visible=visible))
pitch_locs.append(gr.Plot(label='Pitch Location', elem_classes='pitch-loc', visible=visible))
download_file_fn = create_set_download_file_fn('files/player.csv')
plot_loc_summary = lambda df, handedness: plot_loc(df, handedness)
fn_configs = {
download_file_fn: dict(inputs=[], outputs=download_file),
plot_usage: dict(inputs=[player], outputs=usage),
plot_velo_summary: dict(inputs=[app_league_df, player], outputs=velo_summary),
plot_loc_summary: dict(inputs=[handedness], outputs=loc_summary),
plot_pitch_cards: dict(inputs=[app_league_df, app_pitch_stats, handedness], outputs=pitch_rows+pitch_groups+pitch_names+pitch_infos+pitch_velos+pitch_locs)
}
for k in fn_configs.keys():
fn_configs[k]['df'] = gr.State(df)
fn_configs[k]['inputs'] = [fn_configs[k]['df']] + fn_configs[k]['inputs']
update_dfs_kwargs = dict(
fn=update_dfs,
inputs=[player, handedness, start_date, end_date, source_df],
outputs=[app_df, app_league_df, app_pitch_stats, app_league_pitch_stats]
)
non_player_search_inputs = [handedness, start_date, end_date]
(
player
.input(**update_dfs_kwargs)
.then(lambda : gr.update(value='Both', interactive=True), outputs=handedness)
# .then(lambda: [gr.update(interactive=True) for _ in range(len(non_player_search_inputs))], outputs=non_player_search_inputs) # breaks Calendar for some reason
)
for component in non_player_search_inputs:
component.input(**update_dfs_kwargs)
# start_date.input(**update_dfs_kwargs)
# app_df.change(preview_df, inputs=app_df, outputs=preview)
# app_df.change(set_download_file, inputs=app_df, outputs=download_file)
# app_df.change(plot_usage, inputs=[app_df, player], outputs=usage)
# app_df.change(plot_velo_summary, inputs=[app_df, app_league_df, player], outputs=velo_summary)
# app_df.change(lambda df: plot_loc(df), inputs=app_df, outputs=loc_summary)
# app_df.change(plot_pitch_cards, inputs=[app_df, app_pitch_stats], outputs=pitch_rows+pitch_groups+pitch_names+pitch_infos+pitch_velos+pitch_locs)
app_pitch_stats.change(update_velo_stats, inputs=[app_pitch_stats, app_league_pitch_stats], outputs=velo_stats)
# (
# app_df
# .change(create_set_download_file_fn('files/player.csv'), inputs=app_df, outputs=download_file)
# .then(plot_usage, inputs=[app_df, player], outputs=usage)
# .then(plot_velo_summary, inputs=[app_df, app_league_df, player], outputs=velo_summary)
# .then(lambda df: plot_loc(df), inputs=app_df, outputs=loc_summary)
# .then(plot_pitch_cards, inputs=[app_df, app_league_df, app_pitch_stats], outputs=pitch_rows+pitch_groups+pitch_names+pitch_infos+pitch_velos+pitch_locs)
# )
app_df.change(lambda df: copy_dataframe(df, len(fn_configs)), inputs=app_df, outputs=[config['df'] for config in fn_configs.values()])
for fn, config in fn_configs.items():
config['df'].change(fn, inputs=config['inputs'], outputs=config['outputs'])
gr.Markdown('## Bugs and other notes')
with gr.Accordion('Click to open', open=False):
gr.Markdown('''
- Y axis ticks messy when no velocity distribution is plotted
- DataFrame precision inconsistent
'''
)
return demo
if __name__ == '__main__':
create_pitcher_dashboard().launch(
share=True,
debug=True
)
|