File size: 4,853 Bytes
41bdb13
 
26e0ac6
 
41bdb13
9d7970d
cf5350e
41bdb13
5f04844
 
cf5350e
41bdb13
cf5350e
41bdb13
26c325e
 
 
 
 
 
 
024b191
26c325e
aaf4937
5f04844
26c325e
 
5f04844
 
 
41bdb13
 
 
 
5f04844
024b191
5f04844
 
 
 
 
e7a5154
 
 
5f04844
 
cf5350e
5f04844
43049df
 
5f04844
 
 
f101223
5f04844
 
 
9d7970d
26c325e
 
 
024b191
 
 
 
26c325e
5f04844
26c325e
9d7970d
 
26c325e
5f04844
9d7970d
5f04844
 
 
 
 
 
 
26c325e
 
 
 
26e0ac6
13a3a28
5f04844
43049df
 
26e0ac6
9d7970d
5f04844
 
024b191
5f04844
 
024b191
5f04844
 
 
 
 
 
 
 
 
 
 
 
 
 
 
024b191
5f04844
 
9d7970d
 
 
26c325e
43049df
9d7970d
 
 
 
cf5350e
 
9d7970d
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

import gradio as gr
# import pandas as pd
import polars as pl

from math import ceil
import os

from data import df, pitch_stats, league_pitch_stats, player_df
from gradio_function import *
from translate import jp_pitch_to_en_pitch, max_pitch_types

os.makedirs('files', exist_ok=True)

css = '''
.pitch-usage {height: 256px}
.pitch-usage .js-plotly-plot {height: 100%}

.pitch-velo {height: 100px}
.pitch-velo .js-plotly-plot {height: 100%}

.pitch-loc {height: 320px}
.pitch-loc .js-plotly-plot {height: 100%}

.pitch-velo-summary div.plotly-notifier {visibility: hidden}
'''

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')
    handedness = gr.Radio(value='Both', choices=['Both', 'Left', 'Right'], type='value', interactive=False, label='Batter Handedness')

  # 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')

  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))

  gr.Markdown('## Pitch Velocity')
  velo_stats = gr.DataFrame(pl.DataFrame([{'Avg. Velo': None, 'League Avg. Velo': None}]), interactive=False, label='Pitch Velocity')

  (
      player
      .input(update_dfs, inputs=[player, handedness, source_df], outputs=[app_df, app_league_df, app_pitch_stats, app_league_pitch_stats])
      .then(lambda : gr.update(value='Both', interactive=True), outputs=handedness)
  )
  handedness.input(update_dfs, inputs=[player, handedness, source_df], outputs=[app_df, app_league_df, app_pitch_stats, app_league_pitch_stats])

  # 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(set_download_file, 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)
  )

  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
    '''
    )

demo.launch(
    share=True,
    debug=True
)