Skip to content

v3.19.0

Choose a tag to compare

@probberechts probberechts released this 07 Jun 11:30
· 41 commits to master since this release
99f76f0

✨ Highlights ✨

  • Write Support: Added comprehensive write capabilities to kloppy. You can now write data to local files or S3 URIs with automatic support for compression formats (.gz, .bz2, .xz). This feature is a first step towards implementing the Common Data Format (CDF) exporter (#519), which will allow users to output tracking data in the CDF specification. (#515)
import json

from kloppy import io, statsbomb

# 1. Load StatsBomb data
dataset = statsbomb.load_open_data(match_id="3788741")

# 2. Use the low-level 'open_as_file' with write mode
with io.open_as_file("event_data_export.json.gz", mode="wb") as f:
    # Extract just the event names and IDs for this example
    data_to_save = [
        {"id": event.event_id, "type": event.event_name}
        for event in dataset.records[:100]
    ]

    # Serialize to JSON and write to the stream
    # The '.gz' extension triggers automatic compression
    f.write(json.dumps(data_to_save).encode("utf-8"))
  • Sportscode Serializer Enhancement: The Sportscode serializer can now handle multiple labels per group. This allows for generating multiple XML elements for a single group by using a list of label values, making serialized data richer and more structured. (#499)
code = Code(
    period=period,
    timestamp=timedelta(seconds=10),
    statistics=[],
    ball_owning_team=None,
    ball_state=None,
    code_id="1",
    code="Shot",
    end_timestamp=timedelta(seconds=12),
    labels={
        "Player": "Lionel Messi",
        "Action": ["Goal", "Left Foot", "Outside Box"]  # Multiple labels for 'Action' group
    }
)

When serialized, each item in the list becomes its own element while maintaining the same name:

<?xml version='1.0' encoding='utf-8'?>
<file>
  <ALL_INSTANCES>
    <instance>
      <ID>1</ID>
      <start>10.0</start>
      <end>12.0</end>
      <code>Shot</code>
      <label>
        <group>Player</group>
        <text>Lionel Messi</text>
      </label>
      <label>
        <group>Action</group>
        <text>Goal</text>
      </label>
      <label>
        <group>Action</group>
        <text>Left Foot</text>
      </label>
      <label>
        <group>Action</group>
        <text>Outside Box</text>
      </label>
    </instance>
  </ALL_INSTANCES>
</file>
  • Switch to uv & ruff: We've overhauled our internal tooling, switching from pip to uv for dependency management and adopting ruff for linting and formatting. The development environment setup and CI pipelines are now significantly faster and more reliable. (#487, #517)

⚠️ Breaking Changes

  • Changed only_alive default to False for all providers: Previously, the only_alive parameter defaulted to True for StatsPerform, SecondSpectrum and Skillcorner, meaning that only frames for which the ball was in play were included in the output. This default has now been changed to False across all providers. If your code relies on the old behavior, you should now explicitly pass only_alive=True when loading data. (#556)

🚀 Features

  • SkillCorner: Improved the mapping of SkillCorner position IDs to kloppy's internal PositionType enum, adding support for previously missing IDs like Goalkeeper and LeftBack. (#516)
  • Metadata Restructuring: Moved coach information from the top-level Metadata object to the Team object (accessible via team.coach). For backward compatibility, the old home_coach and away_coach properties are deprecated but still work. (#520)
  • Sequence State Builder: Improved the builder to create more logical action sequences by including more events (like goalkeeper pickups and successful interceptions) as sequence starters and correctly handling duels and defensive actions. (#484)

🪲 Fixes

  • Tracab: Fixed an issue where player names were being parsed as StringElement objects instead of standard Python strings. (#505)
  • SecondSpectrum: Resolved an issue with JSONL files containing a UTF-8 BOM (Byte Order Mark) by using the utf-8-sig encoding, ensuring they are parsed correctly. (#522)
  • Sportec IDSSE: Updated the source for the IDSSE open dataset from Figshare to HuggingFace, as the original Figshare URLs were broken. Also updated the documentation to reflect the dataset's publication status. (#529, #542)
  • StatsBomb:
    • Fixed two bugs in the coordinate transformation for freeze frames, which prevented correct transformation when no orientation change was needed and caused the ball's coordinates to be transformed twice. (#526)
    • Added missing formation mappings, including the 3-2-4-1 formation, to prevent KeyError exceptions when deserializing tactical shift events. (#553, #554)
  • HTTP Basic Auth: The configuration for HTTP Basic Auth now accepts both a dictionary and a tuple, making it easier to use. The documentation has also been corrected to reflect the proper login and password keys. (#534)
  • General:
    • Made end_timestamp and end_coordinates optional fields for CarryEvent and end_timestamp optional for PressureEvent, aligning them with other event classes and preventing TypeError exceptions when these fields are missing. (#557)
    • Added support for XML feeds containing a BOM (Byte Order Mark) by correctly handling the encoding. (#540)
    • Fixed an issue in the SkillCorrener adapter where a coordinate value of exactly 0.0 was being handled incorrectly. (#538)

📚 Documentation

  • A brand new and improved Contributor's Guide is now available to help new developers get started. (#488)
  • Fixed numerous typos and grammatical errors across the documentation for a smoother reading experience. (#558)
  • Corrected typos and an incorrect function call (load_open_data → load) in the Jupyter notebooks that demonstrate how to load data. (#547)

👷 Refactoring

  • Removed the deprecated to_pandas method. (#518)
  • Refactored dataset filtering and event deserialization logic for better maintainability. (#521)

⚙️ CI/CD

  • Switched from pip to uv for faster and more reliable dependency management. (#487)
  • Replaced the black code formatter with ruff, which is faster and also handles linting. (#517)
  • Made the release workflow more robust. (#560)

Contributors

This release was made possible by the following contributors:

Full Changelog: v3.18.0...v3.19.0