Skip to content

Releases: PySport/kloppy

v3.18.0 - IMPECT data

23 Oct 09:14
369a9b5

Choose a tag to compare

✨ Highlights ✨

This release introduces support for loading IMPECT event data. We’re excited to share that this feature was sponsored by IMPECT, who also made a public open dataset available at https://github.com/ImpectAPI/open-data.

from kloppy import impect

dataset = impect.load_open_data(match_id=122976)
print(dataset.to_df().head())

Implementation by @DriesDeprest, @koenvo and @UnravelSports in #504. A huge thank-you to IMPECT for sponsoring and supporting this contribution to the open-source community!

🚀 Other updates

This makes it easier to check a player’s top-level position group:

player = dataset.metadata.teams[0].get_player_by_id("3089")
assert player.starting_position == PositionType.RightAttackingMidfield
assert player.starting_position.position_group == PositionType.Midfielder

🪲 Fixes

  • [SkillCorner] Updated URLs for open data loader by @koenvo in #510

Full Changelog: v3.17.1...v3.18.0

v3.17.1

19 Aug 15:02
ccf9b91

Choose a tag to compare

This minor release patches bugs in the Sportec and Tracab tracking data parsers.

🪲 Fixes

🚀 Other updates

Full Changelog: v3.17.0...v3.17.1

v3.17.0

28 May 10:16
ed74515

Choose a tag to compare

✨ Highlights ✨

Major Documentation Overhaul by @probberechts in #346

We’ve completely rewritten and reorganized the documentation from scratch to make it clearer and easier to use. Explore the new docs here: https://kloppy.pysport.org/.

💡 We’d love your help to continue improving it! If something confuses you, update it once you figure it out. It’s a great way to pay it forward. Check out #465 for a list of open documentation tasks where your contributions are welcome.

New Tracking Data Providers

We've added support for three more tracking data providers:

Detailed instructions on how to load data from these providers can be found here.

Attach Statistics to Events & Frames by @DriesDeprest in #302

Events and tracking frames now support a .statistics attribute for attaching metrics like xG, possession value, and pitch control.

Example:

>>> from kloppy import statsbomb
>>> dataset = statsbomb.load_open_data(match_id="3794687")
>>> goal = dataset.find("shot.goal")
>>> print(goal.statistics)
[ExpectedGoals(name='xG', value=0.0232)]

Currently, xG and PSxG are parsed from StatsBomb, Stats Perform, Opta (F73) and Wyscout (v3) datasets.

New "Under Pressure" Event Qualifier by @DriesDeprest in #296

StatsBomb events now include a boolean UnderPressureQualifier.

>>> from kloppy import statsbomb
>>> dataset = statsbomb.load_open_data(match_id="3794687")
>>> event = dataset.get_event_by_id("c2a03c46-c936-4f7b-9b26-72d470a892ef")
>>> print(event.qualifiers)
[UnderPressureQualifier(value=True)]

Support Creating Custom Coordinate Systems by @probberechts in #422

Apart from the ones used by the supported data providers, kloppy now also provides support to create a custom coordinate system using the CustomCoordinateSystem class.

from kloppy.domain import CustomCoordinateSystem, Origin, VerticalOrientation, NormalizedPitchDimensions, Dimension

my_coordinate_system = CustomCoordinateSystem(
    origin=Origin.TOP_LEFT,
    vertical_orientation=VerticalOrientation.TOP_TO_BOTTOM,
    pitch_dimensions=NormalizedPitchDimensions(
        pitch_length=105,
        pitch_width=68,
    ),
)

Our new documentation contains a detailed guide.

🚀 Other updates

🪲 Fixes

  • Use correct attributes in AngleToGoalTransformer by @lodevt in #416
  • Fix transforming pitch dimensions when dataset has a coordinate system by @probberechts in #422
  • Disassociate sample_rate and limit by @UnravelSports in #431
  • Incorrect MinutesPlayed aggregation by @UnravelSports in #411
  • Reset positions and formations during EventDataset creation by @DriesDeprest in #389
  • [PFF] Changes to metadata and rosters by @razor3598 in #426
  • [PFF] Fix orientation recognition to accomodate bad data by @UnravelSports in #462
  • [PFF] Missing Attacking Midfielder by @UnravelSports in #449
  • [SecondSpectrum] Fix reversed pitch dimensions by @SportsDynamicsDS in #404
  • [SecondSpectrum] Align position mapping + add PositionType.Unknown to StatsPerform & Metrica by @UnravelSports in #432
  • [SkillCorner] Fix data loading error for game ids 2269 and 3442 by @probberechts in #376
  • [Skillcorner] Avoid crash if coaches are missing by @UnravelSports in #428
  • [Sportec] Fixed vertical orientation of event data coordinate system by @UnravelSports in #447
  • [Sportec] Fix missing players_data by @UnravelSports in #468
  • [StatsBomb] Insert synthetic ball out events at the correct position by @probberechts in #380
  • [StatsBomb] Fix player identity inference issues in freeze frame data by @AndrewRook in #386
  • [StatsBomb] Deserialize failed recoveries as loose ball duels by @probberechts in #391
  • [Stats Perform] Fallback to parsing player's full name from MA1 file when short name is unavailable by @DriesDeprest in #402
  • [Stats Perform/Opta] Add FormationType.UNKNOWN and PostionType.Unknown handling by @UnravelSports in #456
  • [Wyscout v3] Handle unrecognized players gracefully to prevent crashes by @DriesDeprest in #358
  • [Wyscout v3] Set formation to FormationType.UNKNOWN when a 10 player formation is recognized by @DriesDeprest in #330
  • [Wyscout v3] Create periods prior to creating events by @DriesDeprest in #441

👷 Refactoring

🚨 Testing

🔋 Dependencies

📚 Docs

👋 New Contributors

Full Changelog: v3.16.0...v3.17.0

v3.16.0

17 Dec 23:58

Choose a tag to compare

✨ Highlights ✨

Load DFL Open Data by @UnravelSports in #365

We've added support for loading a new public dataset! The dataset contains seven full matches of raw event and position data collected by Sportec Solutions from the German Men's Bundesliga season 2022/23 first and second division.

from kloppy import sportec

event_dataset = sportec.load_open_event_data(match_id="J03WMX")
tracking_dataset = sportec.load_open_tracking_data(match_id="J03WMX")

For more info about the dataset, see

Bassek, M., Weber, H., Rein, R., & Memmert, D. (2024). "An integrated dataset of synchronized spatiotemporal and event data in elite soccer." In Submission.

Standardized player positions by @DriesDeprest in #334

Instead of relying on provider-specific player positions, kloppy now implements a standardized PositionType.

>>> from kloppy import statsbomb

>>> event_dataset = statsbomb.load_open_data(match_id="15946")
>>> event = event_dataset.get_event_by_id("549567bd-36de-4ac8-b8dc-6b5d3f1e4be8")
>>> event.player.starting_position
<PositionType.LeftMidfield: ('Left Midfield', 'LM', 'WideMidfield')>

The positions are ordered hierarchically.

>>> from kloppy.domain import PositionType

>>> print(PositionType.LeftBack.parent) 
FullBack

>>> print(PositionType.Defender.is_subtype_of(PositionType.Defender))
True
>>> print(PositionType.LeftCenterBack.is_subtype_of(PositionType.Defender))  
True
>>> print(PositionType.LeftBack.is_subtype_of(PositionType.Midfielder))  
False

>>> print(PositionType.LeftCenterBack) 
Left Center Back
>>> print(PositionType.LeftCenterBack.code) 
LCB

Team formation changes by @DriesDeprest in #332

In addition to a starting_formation attribute, a Team entity now also has a formations attribute that holds the team's formation changes throughout the game.

>>> from kloppy import statsbomb

>>> event_dataset = statsbomb.load_open_data(match_id="15946")
>>> event = event_dataset.get_event_by_id("549567bd-36de-4ac8-b8dc-6b5d3f1e4be8")
>>> event.team.starting_formation
<FormationType.FOUR_FIVE_ONE: '4-5-1'>
>>> event.team.formations
TimeContainer[FormationType]({'P2T22:53': <FormationType.FOUR_FOUR_TWO: '4-4-2'>})

🚀 Other updates

🪲 Fixes

  • Fix common bug in parsing of UTC datetimes by @probberechts in #373
  • [Stats Perform - Event] Fix creation of goalkeeper events for event type 10/Save when an outfield player blocks a shot (qualifier 94) by @DriesDeprest in #335
  • [Stats Perform - Tracking] Recognize referee player type and handle accordingly by @DriesDeprest in #357
  • [Stats Perform - Tracking] Support frames with no player data by @DriesDeprest in #349
  • [Stats Perform - Tracking] Handle missing end period for abandoned matches by @DriesDeprest in #355
  • [SkillCorner] Support renaming "time" → "timestamp" by @UnravelSports in #338
  • [Tracab] Support new meta data format by @UnravelSports in #353
  • [Wyscout v3] Fix location for blocked crosses by @DriesDeprest in #343
  • Use positions in get_player_by_position by @DriesDeprest in #342

👷 Refactoring

🚨 Testing

  • [Wyscout v3] Use publicly available Wyscout v3 event data in tests by @DriesDeprest in #350

👋 New Contributors

Full Changelog: v3.15.0...v3.16.0

v3.15.0

17 Dec 23:59

Choose a tag to compare

What's Changed

Full Changelog: v3.14.0...v3.15.0

v3.14.0

18 Dec 00:00

Choose a tag to compare

What's Changed

Full Changelog: v3.13.0...v3.14.0

v3.13.0

18 Dec 00:01

Choose a tag to compare

  • Add MiscontrolEvent (#207)
  • Add GoalkeeperEvent (#196)

v3.12.0

18 Dec 00:01

Choose a tag to compare

  • Add ClearanceEvent (#195)
  • Fixed foot left/right typo in shot parsing for WyScout v3 (#197)
  • Improvements to Opta and Wyscout deserializers (#198)
  • Fix issue with automated tests on macos (#199)
  • Add speed parsing for SecondSpectrum (#201)
  • Add DuelEvent (#204)
  • Sportec tracking (#208)

v3.11.0

18 Dec 00:01

Choose a tag to compare

  • Fix datatype of SkillCorner metadata.periods (#189)
  • Fix inputs of kloppy.helpers.transform (#186)
  • Refactor pathlib tests (#193)
  • StatsPerform deserializer (#191)
  • Allow chaining of operators on a Dataset (filter + map) (#183)
  • Opta remove deleted (#182)

v3.10.0

18 Dec 00:01

Choose a tag to compare

  • Add support for corner shots (#176)
  • Fix S3Adapter.read_to_stream (#179)
  • Add pandas pyarrow support + better performance on to_df (#180)