--- title: MLB Pregame Dashboard emoji: ⚾ colorFrom: blue colorTo: indigo sdk: gradio sdk_version: "5.23.3" python_version: "3.10" app_file: app.py pinned: false --- # MLB Pregame Dashboard A compact, data-dense Gradio web app for pregame analysis. ## Quick Start ```bash pip install -r requirements.txt python app.py # → open http://localhost:7860 ``` ## File Structure ``` pregame_dashboard/ ├── app.py # Gradio UI — layout, callbacks, HTML builders ├── chart_builder.py # Plotly figure factories (innings, pitch count, velo) ├── data_fetcher.py # All data sources: pybaseball, StatsAPI, RotoGrinders ├── requirements.txt └── README.md ``` ## Data Sources & What Each Provides | Source | What | How | |--------|------|-----| | **MLB StatsAPI** (`MLB-StatsAPI` pkg) | Schedule, confirmed lineups, live game state, score, inning | `statsapi.schedule()`, `statsapi.boxscore_data()` | | **Baseball Savant** (`pybaseball`) | Statcast: xwOBA splits, FB velocity, pitcher pitch-by-pitch | `pyb.statcast_batter()`, `pyb.statcast_pitcher()` | | **FanGraphs** (`pybaseball`) | Pitcher game logs (IP, pitches, GS flag), bullpen roster | `pyb.pitching_stats_range()`, `pyb.pitching_stats()` | | **RotoGrinders** (scraped) | Today's weather (temp, wind), projected lineups | `requests` GET → regex parse | ## Graceful Degradation Every data function has a `_mock_*` fallback. If a package is missing or a network call fails, mock data is returned and a `warnings.warn()` is emitted — the UI never crashes. ## Performance - All fetches are wrapped in `@_cached()` with a 5-minute TTL. - `pybaseball.cache.enable()` adds a disk cache layer on top. - Heavy Statcast pulls (full season per pitcher) happen once per player/date combo. - To increase cache TTL, edit `_CACHE_TTL` in `data_fetcher.py`. ## Extending ### Adding live game tracking - Poll `statsapi.game(game_pk)` on a timer; Gradio supports `gr.Timer`. ### Adding RotoGrinders lineup parsing - RotoGrinders serves lineups via an internal JSON endpoint. Try: `GET https://rotogrinders.com/api/lineups?sport=mlb&date=YYYY-MM-DD` Parse the JSON and map to the `player_dict` format in `data_fetcher.get_lineups()`. ### Adding Baseball Reference splits - `pyb.split_stats()` or scrape `https://www.baseball-reference.com/players/split.fcgi?id=PLAYER_ID` ### Updating league averages - Edit the `LEAGUE_AVG` dict at the top of `data_fetcher.py` each season. ## Known Limitations - **RotoGrinders** is JS-rendered; the weather scraper uses a regex heuristic and may break if their HTML changes. Consider Playwright for more robustness. - **Projected lineups** (non-confirmed) come from RotoGrinders projected data or default to empty with a ⚠ flag if unavailable. - **Game card selection** uses a JS workaround to update a hidden Gradio number input. If Gradio internals change, revisit `app.py` → `selectGame()`. ## League Average Constants (2024) Update yearly in `data_fetcher.py → LEAGUE_AVG`: - `xwOBA`: 0.318 - `K_pct`: 0.226 - `BB_pct`: 0.082 - `SP_FB_velo`: 93.9 mph - `RP_FB_velo`: 95.2 mph