Spaces:
Sleeping
Sleeping
| 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 | |