Spaces:
				
			
			
	
			
			
		Sleeping
		
	
	
	
			
			
	
	
	
	
		
		
		Sleeping
		
	| 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 (KPH)': None, 'Avg. Velo (MPH)': None, 'League Avg. Velo (KPH)': None, 'League Avg. Velo (MPH)': 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 | |
| ) | |