Skip to content

agostino-code/IOT-Project

Repository files navigation

Football Match Analytics Dashboard

A Flask-based web application for visualizing and analyzing professional football matches using Opta event data and optical tracking data. The app provides real-time pitch control, player heatmaps, timeline events, Voronoi diagrams, and player enrichment via the Transfermarkt API.


Features

  • Multi-game management — load and switch between multiple matches via a folder browser; recent games are persisted in a history file
  • Player heatmaps — per-player positional heatmaps generated from tracking data, with in-memory and on-disk caching and a background warmup system
  • Pitch control timeline — raster-based (nearest-neighbour / Voronoi) territorial dominance computed across all available tracking frames
  • Voronoi diagrams — spatial control visualisation rendered with mplsoccer
  • Match timeline & events — Opta live event data exposed as a versioned JSON API
  • Player enrichment — market values, nationalities, and biographical details fetched from a companion Transfermarkt microservice and cached locally
  • Team colours — automatic colour selection based on team details for consistent visual identity across views
  • Stats view — dedicated statistics page per match with team colour theming

Project Structure

project-root/
├── app.py                     # Main Flask application
├── games_history.json         # Persisted list of recently loaded game paths
├── data/
│   └── cache/
│       └── heatmaps/          # On-disk heatmap PNG cache (per game / per player)
├── games/                     # Default games root (optional, configurable)
│   └── <game-folder>/
│       ├── <*opta_match*.json>          # Opta match file (events + lineup)
│       ├── tracking/                    # One JSON file per tracking frame
│       ├── players_enrichments.json     # Generated player enrichment cache
│       ├── teams_details.json           # Generated team enrichment cache
│       └── transfermarkt_data.json      # Raw Transfermarkt API response cache
└── templates/
    └── stats.html             # Stats page template

Requirements

  • Python 3.10+
  • Flask
  • NumPy / SciPy
  • Matplotlib
  • mplsoccer
  • requests

Install dependencies:

pip install flask numpy scipy matplotlib mplsoccer requests

Configuration

The application is configured via environment variables:

Variable Default Description
DEFAULT_GAME (none) Game ID to load on startup
TRANSFERMARKT_API_URL http://localhost:8000/match-data URL of the Transfermarkt enrichment microservice
PORT 5000 HTTP port
FLASK_DEBUG 1 Enable Flask debug mode (1 = on)

Running the Application

python app.py

The server starts on http://0.0.0.0:<PORT> (default: 5000).

In a Docker container, the host binding ensures port-forwarding works out of the box.


Data Format

Opta Match File

A JSON file whose name contains opta_match, placed inside the game folder. Must include:

  • matchInfo — teams, contestants, date, competition
  • liveData.lineUp — squad lists with player IDs and shirt numbers
  • liveData — event stream

Tracking Files

One JSON file per frame inside the tracking/ sub-folder. Each file contains a list with at least one frame object structured as:

[
  {
    "players": [
      { "id": "...", "team": "team_id", "x": 12.3, "y": -5.1 }
    ]
  }
]

Coordinates follow the standard tracking convention: X ∈ [-52.5, 52.5], Y ∈ [-34, 34].


Key API Endpoints

Method Path Description
GET /api/browse-folder Browse the server filesystem to find game folders
POST /api/load-game Load a game folder and trigger Transfermarkt enrichment
POST /api/settings/clear-history Clear the games history
GET /heatmap/<opta_id> Retrieve (or trigger generation of) a player heatmap
POST /api/heatmap/warmup Start background heatmap pre-generation for all players
GET /api/heatmap/warmup/status Poll warmup progress
GET /api/stats/pitch-control Get the pitch-control timeline for the selected game
GET /stats Stats HTML view

Most endpoints accept a ?game=<game_id> query parameter to target a specific loaded match.


Caching Strategy

The application uses a layered caching approach to minimise redundant computation:

  1. In-memory caches — Python dicts keyed by game ID or player ID; cleared on application restart
  2. On-disk heatmap cache — PNG files stored under data/cache/heatmaps/<game_id>/; versioned with HEATMAP_CACHE_VERSION
  3. Transfermarkt raw response cachetransfermarkt_data.json inside the game folder; prevents repeated API calls on reload
  4. Enrichment file cacheplayers_enrichments.json / teams_details.json; generated once and reused on subsequent loads

Background heatmap generation is managed via a ThreadPoolExecutor (8 workers) with in-flight deduplication, ensuring that concurrent requests for the same player map do not trigger redundant computation.


License

This project is provided as-is for internal/research use. See your organisation's licensing terms for Opta and Transfermarkt data usage.

About

A Flask-based web application for visualizing and analyzing professional football matches using Opta event data and optical tracking data.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors