Skip to content

Commit 2020459

Browse files
DriesDeprestkoenvo
andauthored
feat(impect): add support for Impect event data (#504)
--------- Co-authored-by: Koen Vossen <info@koenvossen.nl>
1 parent 6fc5c48 commit 2020459

File tree

21 files changed

+227470
-27
lines changed

21 files changed

+227470
-27
lines changed

README.md

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,26 +23,30 @@ Each data provider uses its own proprietary formats, event definitions, and coor
2323
## Supported data providers
2424
Kloppy provides support for loading data from the following providers:
2525

26-
| Provider | Event Data | Tracking Data | Public Data | Docs | Notes |
27-
|---------------------|:----------:|:-------------:|:------------:|:-----:|:-----|
28-
| [DataFactory][datafactory] || | | [][datafactory-doc] | |
29-
| [Hawkeye (2D)][hawkeye] | || | [][hawkeye-doc] | Joint tracking data is not yet supported |
30-
| [Metrica][metrica] ||| [][metrica-data] | [][metrica-doc] | |
31-
| [PFF][pff] ||| [][pff-data] | [][pff-doc] | |
32-
| [SecondSpectrum][ss] | [][ss-pr] || | [][ss-doc] | |
33-
| [Signality][signality] | || | [][signality-doc] | |
34-
| [SkillCorner][skillcorner] | || [][skillcorner-data] | [][skillcorner-doc] | |
35-
| [Sportec][sportec] ||| [][sportec-data] | [][sportec-doc] | |
36-
| [StatsBomb][statsbomb] || | [][statsbomb-data] | [][statsbomb-doc] | Includes 360 freeze frame data support |
37-
| [Stats Perform][statsperform] ||| | [][statsperform-doc] | Includes support for MA1, MA3, and MA25 data feeds |
38-
| [Opta][opta] || | | [][opta-doc] | Includes support for F7, F24 and F73 XML data feeds |
39-
| [Tracab][tracab] | || | [][tracab-doc] | |
40-
| [Wyscout][wyscout] || | [][wyscout-data] | [][wyscout-doc] | Includes support for v2 and v3 data |
26+
| Provider | Event Data | Tracking Data | Public Data | Docs | Notes |
27+
|-------------------------------|:----------:|:-------------:|:---------------------:|:---------------------:|:------|
28+
| [DataFactory][datafactory] || | | [][datafactory-doc] | |
29+
| [Hawkeye (2D)][hawkeye] | || | [][hawkeye-doc] | Joint tracking data is not yet supported |
30+
| [Impect][impect] || | [][impect-data] | [][impect-doc] | |
31+
| [Metrica][metrica] ||| [][metrica-data] | [][metrica-doc] | |
32+
| [PFF][pff] ||| [][pff-data] | [][pff-doc] | |
33+
| [SecondSpectrum][ss] | [][ss-pr] || | [][ss-doc] | |
34+
| [Signality][signality] | || | [][signality-doc] | |
35+
| [SkillCorner][skillcorner] | || [][skillcorner-data] | [][skillcorner-doc] | |
36+
| [Sportec][sportec] ||| [][sportec-data] | [][sportec-doc] | |
37+
| [StatsBomb][statsbomb] || | [][statsbomb-data] | [][statsbomb-doc] | Includes 360 freeze frame data support |
38+
| [Stats Perform][statsperform] ||| | [][statsperform-doc] | Includes support for MA1, MA3, and MA25 data feeds |
39+
| [Opta][opta] || | | [][opta-doc] | Includes support for F7, F24 and F73 XML data feeds |
40+
| [Tracab][tracab] | || | [][tracab-doc] | |
41+
| [Wyscout][wyscout] || | [][wyscout-data] | [][wyscout-doc] | Includes support for v2 and v3 data |
4142

4243
[datafactory]: https://www.datafactory.la/en/
4344
[datafactory-doc]: https://kloppy.pysport.org/user-guide/loading-data/datafactory
4445
[hawkeye]: https://www.hawkeyeinnovations.com/data
4546
[hawkeye-doc]: https://kloppy.pysport.org/user-guide/loading-data/hawkeye
47+
[impect]: https://www.impect.com/en/
48+
[impect-doc]: https://kloppy.pysport.org/user-guide/loading-data/impect
49+
[impect-data]: https://github.com/ImpectAPI/open-data
4650
[metrica]: https://www.metrica-sports.com/
4751
[metrica-data]: https://github.com/metrica-sports/sample-data
4852
[metrica-doc]: https://kloppy.pysport.org/user-guide/loading-data/metrica

docs/reference/domain/models/common/coordinate-system/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
::: kloppy.domain.KloppyCoordinateSystem
99
::: kloppy.domain.DatafactoryCoordinateSystem
1010
::: kloppy.domain.HawkEyeCoordinateSystem
11+
::: kloppy.domain.ImpectCoordinateSystem
1112
::: kloppy.domain.MetricaCoordinateSystem
1213
::: kloppy.domain.OptaCoordinateSystem
1314
::: kloppy.domain.PFFCoordinateSystem

docs/reference/event-data/spec.yaml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ event_types:
1515
status: parsed
1616
metrica_json:
1717
status: parsed
18+
impect:
19+
status: parsed
1820
attributes:
1921
time:
2022
providers:
@@ -80,6 +82,9 @@ event_types:
8082
metrica_json:
8183
status: parsed
8284
implementation: event type 1/'PASS'
85+
impect:
86+
status: parsed
87+
implementation: event type 'PASS', 'KICK_OFF', 'THROW_IN', 'FREE_KICK', 'PENALTY_KICK', 'GOAL_KICK', or 'CORNER'
8388
attributes:
8489
receive_timestamp:
8590
providers:
@@ -187,6 +192,9 @@ event_types:
187192
metrica_json:
188193
status: parsed
189194
implementation: event type 2/'SHOT'
195+
impect:
196+
status: parsed
197+
implementation: event type 'SHOT'
190198
attributes:
191199
result_coordinates:
192200
providers:
@@ -339,6 +347,9 @@ event_types:
339347
metrica_json:
340348
status: parsed
341349
implementation: event type 10/'CARRY'
350+
impect:
351+
status: parsed
352+
implementation: event type 'DRIBBLE'
342353
attributes:
343354
end_timestamp:
344355
providers:
@@ -397,6 +408,9 @@ event_types:
397408
metrica_json:
398409
status: not implemented
399410
implementation: null
411+
impect:
412+
status: parsed
413+
implementation: event type 'CLEARANCE'
400414
kloppy.domain.InterceptionEvent:
401415
providers:
402416
statsbomb:
@@ -417,6 +431,9 @@ event_types:
417431
metrica_json:
418432
status: not implemented
419433
implementation: null
434+
impect:
435+
status: parsed
436+
implementation: event type 'INTERCEPTION'
420437
attributes:
421438
result:
422439
providers:
@@ -458,6 +475,9 @@ event_types:
458475
metrica_json:
459476
status: not supported
460477
implementation: null
478+
impect:
479+
status: parsed
480+
implementation: event type 'GROUND_DUEL' or 'AERIAL_DUEL'
461481
attributes:
462482
result:
463483
providers:
@@ -498,6 +518,9 @@ event_types:
498518
metrica_json:
499519
status: not supported
500520
implementation: null
521+
impect:
522+
status: parsed
523+
implementation: parsed from metadata
501524
attributes:
502525
replacement_player:
503526
providers:
@@ -524,6 +547,9 @@ event_types:
524547
metrica_json:
525548
status: not implemented
526549
implementation: null
550+
impect:
551+
status: parsed
552+
implementation: event type 'YELLOW_CARD', 'SECOND_YELLOW_CARD', or 'RED_CARD'
527553
attributes:
528554
card_type:
529555
providers:
@@ -597,6 +623,9 @@ event_types:
597623
metrica_json:
598624
status: parsed
599625
implementation: event type 3/'RECOVERY'
626+
impect:
627+
status: parsed
628+
implementation: event type 'LOOSE_BALL_REGAIN'
600629
kloppy.domain.MiscontrolEvent:
601630
providers:
602631
statsbomb:
@@ -654,6 +683,9 @@ event_types:
654683
metrica_json:
655684
status: parsed
656685
implementation: event type 4/'FAULT RECEIVED'
686+
impect:
687+
status: parsed
688+
implementation: event type 'FOUL'
657689
kloppy.domain.GoalkeeperEvent:
658690
providers:
659691
statsbomb:
@@ -674,6 +706,9 @@ event_types:
674706
metrica_json:
675707
status: not supported
676708
implementation: null
709+
impect:
710+
status: parsed
711+
implementation: event type 'GK_SAVE' or 'GK_CATCH'
677712
kloppy.domain.PressureEvent:
678713
providers:
679714
statsbomb:

docs/reference/providers/impect.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
::: kloppy.impect
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "3a953d55",
6+
"metadata": {},
7+
"source": [
8+
"# Impect\n",
9+
"\n",
10+
"- [Load local files](#load-local-files)"
11+
]
12+
},
13+
{
14+
"cell_type": "markdown",
15+
"id": "d2d34bd2",
16+
"metadata": {},
17+
"source": [
18+
"## Load local files\n"
19+
]
20+
},
21+
{
22+
"cell_type": "code",
23+
"id": "12ec8092",
24+
"metadata": {},
25+
"source": [
26+
"from kloppy import impect\n",
27+
"\n",
28+
"dataset = impect.load(\n",
29+
" event_data=\"../../kloppy/tests/files/impect_events.json\",\n",
30+
" lineup_data=\"../../kloppy/tests/files/impect_lineups.json\",\n",
31+
" \n",
32+
" # Optional arguments\n",
33+
" coordinates=\"impect\",\n",
34+
" event_types=[\"pass\", \"shot\"]\n",
35+
")\n",
36+
"\n",
37+
"dataset.to_df().head()"
38+
],
39+
"outputs": [],
40+
"execution_count": null
41+
},
42+
{
43+
"cell_type": "markdown",
44+
"id": "8fa1e495",
45+
"metadata": {},
46+
"source": ""
47+
}
48+
],
49+
"metadata": {
50+
"kernelspec": {
51+
"display_name": ".venv",
52+
"language": "python",
53+
"name": "python3"
54+
},
55+
"language_info": {
56+
"codemirror_mode": {
57+
"name": "ipython",
58+
"version": 3
59+
},
60+
"file_extension": ".py",
61+
"mimetype": "text/x-python",
62+
"name": "python",
63+
"nbconvert_exporter": "python",
64+
"pygments_lexer": "ipython3",
65+
"version": "3.11.11"
66+
}
67+
},
68+
"nbformat": 4,
69+
"nbformat_minor": 5
70+
}

docs/user-guide/loading-data/index.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ Below is an overview of all currently supported providers, along with links to d
2020
| Provider | Event Data | Tracking Data | Code Data | Public Data |
2121
| :----------------------------------------- | :----------------------------------------------------------------------: | :--------------: | :--------------: | :--------------------------------------------------------------------------------------------: |
2222
| [DataFactory](datafactory.ipynb) | :material-check: | :material-minus: | :material-minus: | |
23-
| [HawkEye (2D)](hawkeye.ipynb) | :material-minus: | :material-check: | :material-minus: | |
23+
| [HawkEye (2D)](hawkeye.ipynb) | :material-check: | :material-minus: | :material-minus: | |
24+
| [Impect](impect.ipynb) | :material-minus: | :material-check: | :material-minus: | [:material-eye:](https://github.com/ImpectAPI/open-data) |
2425
| [Metrica](metrica.ipynb) | :material-minus: | :material-check: | :material-minus: | [:material-eye:](https://github.com/metrica-sports/sample-data) |
2526
| [PFF FC](pff.ipynb) | :material-minus: | :material-check: | :material-minus: | [:material-eye:](https://drive.google.com/drive/u/0/folders/1_a_q1e9CXeEPJ3GdCv_3-rNO3gPqacfa) |
26-
| [SecondSpectrum](secondspectrum.ipynb) | [:material-progress-wrench:](https://github.com/PySport/kloppy/pull/437) | :material-check: | :material-minus: |
27+
| [SecondSpectrum](secondspectrum.ipynb) | [:material-progress-wrench:](https://github.com/PySport/kloppy/pull/437) | :material-check: | :material-minus: | |
2728
| [Signality](signality.ipynb) | :material-minus: | :material-check: | :material-minus: | |
2829
| [SkillCorner](skillcorner.ipynb) | :material-minus: | :material-check: | :material-minus: | [:material-eye:](https://github.com/SkillCorner/opendata) |
2930
| [Sportec](sportec.ipynb) | :material-check: | :material-check: | :material-minus: | [:material-eye:](https://www.nature.com/articles/s41597-025-04505-y) |

kloppy/_providers/impect.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import warnings
2+
from typing import Union
3+
4+
from kloppy.config import get_config
5+
from kloppy.infra.serializers.event.impect import (
6+
ImpectDeserializer,
7+
ImpectInputs,
8+
)
9+
from kloppy.domain import EventDataset, Optional, List, EventFactory
10+
from kloppy.io import open_as_file, FileLike, Source
11+
12+
13+
def load(
14+
event_data: FileLike,
15+
lineup_data: FileLike,
16+
squads_data: Optional[FileLike] = None,
17+
players_data: Optional[FileLike] = None,
18+
event_types: Optional[List[str]] = None,
19+
coordinates: Optional[str] = None,
20+
event_factory: Optional[EventFactory] = None,
21+
) -> EventDataset:
22+
"""
23+
Load Impect event data into a [`EventDataset`][kloppy.domain.models.event.EventDataset]
24+
25+
Args:
26+
event_data: JSON feed with the raw event data of a game.
27+
lineup_data: JSON feed with the corresponding lineup information of the game.
28+
squads_data: Optional JSON feed with squad information for team names.
29+
players_data: Optional JSON feed with player information for player names.
30+
event_types: A list of event types to load. When set, only the specified event types will be loaded.
31+
coordinates: The coordinate system to use. Defaults to "impect". See [`kloppy.domain.models.common.Provider`][kloppy.domain.models.common.Provider] for available options.
32+
event_factory: A custom event factory. When set, the factory is used to create event instances.
33+
34+
Returns:
35+
The parsed event data.
36+
"""
37+
deserializer = ImpectDeserializer(
38+
event_types=event_types,
39+
coordinate_system=coordinates,
40+
event_factory=event_factory or get_config("event_factory"),
41+
)
42+
with open_as_file(event_data) as event_data_fp, open_as_file(
43+
lineup_data
44+
) as lineup_data_fp, open_as_file(
45+
Source.create(squads_data, optional=True)
46+
) as squads_data_fp, open_as_file(
47+
Source.create(players_data, optional=True)
48+
) as players_data_fp:
49+
return deserializer.deserialize(
50+
inputs=ImpectInputs(
51+
event_data=event_data_fp,
52+
meta_data=lineup_data_fp,
53+
squads_data=squads_data_fp,
54+
players_data=players_data_fp,
55+
)
56+
)
57+
58+
59+
def load_open_data(
60+
match_id: Union[str, int] = "122838",
61+
competition_id: Union[str, int] = "743",
62+
event_types: Optional[List[str]] = None,
63+
coordinates: Optional[str] = None,
64+
event_factory: Optional[EventFactory] = None,
65+
) -> EventDataset:
66+
"""
67+
Load Impect open data.
68+
69+
This function loads event data directly from the ImpectAPI open-data
70+
GitHub repository.
71+
72+
Parameters:
73+
match_id: The id of the match to load data for. Defaults to "100214".
74+
competition_id: The competition id to load squad and player names from. Defaults to "743".
75+
event_types: A list of event types to load.
76+
coordinates: The coordinate system to use.
77+
event_factory: A custom event factory.
78+
79+
Returns:
80+
The parsed event data.
81+
82+
Examples:
83+
>>> from kloppy import impect
84+
>>> dataset = impect.load_open_data(match_id="100214")
85+
>>> df = dataset.to_df(engine="pandas")
86+
"""
87+
88+
warnings.warn(
89+
"\n\nYou are about to use IMPECT public data."
90+
"\nBy using this data, you are agreeing to the user agreement. "
91+
"\nThe user agreement can be found here: https://github.com/ImpectAPI/open-data/blob/main/LICENSE.pdf"
92+
"\n"
93+
)
94+
95+
base_url = (
96+
"https://raw.githubusercontent.com/ImpectAPI/open-data/main/data"
97+
)
98+
99+
return load(
100+
event_data=f"{base_url}/events/events_{match_id}.json",
101+
lineup_data=f"{base_url}/lineups/lineups_{match_id}.json",
102+
squads_data=f"{base_url}/squads/squads_{competition_id}.json",
103+
players_data=f"{base_url}/players/players_{competition_id}.json",
104+
event_types=event_types,
105+
coordinates=coordinates,
106+
event_factory=event_factory,
107+
)

0 commit comments

Comments
 (0)