Skip to content

Commit

Permalink
Merge pull request #323 from my-game-plan/feature/wyscout-carry
Browse files Browse the repository at this point in the history
[Wyscout v3] add parsing of carry event
  • Loading branch information
koenvo authored Jun 3, 2024
2 parents f6e6af5 + 1aa82d4 commit c720be5
Show file tree
Hide file tree
Showing 3 changed files with 132 additions and 7 deletions.
57 changes: 51 additions & 6 deletions kloppy/infra/serializers/event/wyscout/deserializer_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
TakeOnResult,
Team,
FormationType,
CarryResult,
)
from kloppy.exceptions import DeserializationError
from kloppy.utils import performance_logging
Expand Down Expand Up @@ -262,6 +263,33 @@ def _parse_interception(raw_event: Dict, next_event: Dict) -> Dict:
}


def _parse_carry(raw_event: Dict, next_event: Dict, start_ts: Dict) -> Dict:
qualifiers = _generic_qualifiers(raw_event)
carry_info = raw_event["carry"]
end_coordinates = Point(
x=float(carry_info["endLocation"]["x"]),
y=float(carry_info["endLocation"]["y"]),
)

if next_event is not None:
period_id = int(next_event["matchPeriod"].replace("H", ""))
end_timestamp = _create_timestamp_timedelta(
next_event, start_ts, period_id
)
else:
period_id = int(raw_event["matchPeriod"].replace("H", ""))
end_timestamp = _create_timestamp_timedelta(
raw_event, start_ts, period_id
)

return {
"result": CarryResult.COMPLETE,
"qualifiers": qualifiers,
"end_coordinates": end_coordinates,
"end_timestamp": end_timestamp,
}


def _parse_goalkeeper_save(raw_event: Dict) -> Dict:
qualifiers = _generic_qualifiers(raw_event)

Expand Down Expand Up @@ -412,6 +440,19 @@ def _parse_duel(raw_event: Dict) -> Dict:
return {"result": result, "qualifiers": qualifiers}


def _create_timestamp_timedelta(
raw_event: Dict, start_ts: Dict, period_id: int
) -> timedelta:
time_delta = (
timedelta(
seconds=float(raw_event["second"] + raw_event["minute"] * 60)
)
- start_ts[period_id]
)

return time_delta


def get_home_away_team_formation(event, team):
if team.ground == Ground.HOME:
current_home_team_formation = formations[event["team"]["formation"]]
Expand Down Expand Up @@ -556,12 +597,9 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset:
"ball_owning_team": ball_owning_team,
"ball_state": None,
"period": periods[-1],
"timestamp": timedelta(
seconds=float(
raw_event["second"] + raw_event["minute"] * 60
)
)
- start_ts[period_id],
"timestamp": _create_timestamp_timedelta(
raw_event, start_ts, period_id
),
}

primary_event_type = raw_event["type"]["primary"]
Expand Down Expand Up @@ -662,6 +700,13 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset:
if event and self.should_include_event(event):
events.append(transformer.transform_event(event))
continue
elif "carry" in secondary_event_types:
carry_event_args = _parse_carry(
raw_event, next_event, start_ts
)
event = self.event_factory.build_carry(
**carry_event_args, **generic_event_args
)

else:
event = self.event_factory.build_generic(
Expand Down
75 changes: 75 additions & 0 deletions kloppy/tests/files/wyscout_events_v3.json
Original file line number Diff line number Diff line change
Expand Up @@ -1088,6 +1088,81 @@
"xg": 0
}
}
},{
"id": 139800001,
"matchId": 5352524,
"matchPeriod": "2H",
"minute": 50,
"second": 35,
"matchTimestamp": "00:50:35.129",
"videoTimestamp": "3078.129596",
"relatedEventId": null,
"type": {
"primary": "touch",
"secondary": [
"carry"
]
},
"location": {
"x": 39,
"y": 74
},
"team": {
"formation": "4-2-3-1",
"id": 3166,
"name": "Bologna"
},
"opponentTeam": {
"formation": "3-4-3",
"id": 3185,
"name": "Torino"
},
"player": {
"id": 99430,
"name": "Ł. Skorupski",
"position": "GK"
},
"pass": null,
"shot": null,
"groundDuel": null,
"aerialDuel": null,
"infraction": null,
"carry": {
"progression": 19.07,
"endLocation": {
"x": 58,
"y": 74
}
},
"possession": {
"id": 13970000,
"duration": "21.63938",
"types": [
"attack"
],
"eventsNumber": 12,
"eventIndex": 11,
"startLocation": {
"x": 34,
"y": 67
},
"endLocation": {
"x": 91,
"y": 10
},
"team": {
"formation": "4-2-3-1",
"id": 3166,
"name": "Bologna"
},
"attack": {
"withShot": false,
"withShotOnGoal": false,
"withGoal": false,
"flank": "left",
"xg": 0
}
}
}
],
"formations": {
Expand Down
7 changes: 6 additions & 1 deletion kloppy/tests/test_wyscout.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def test_metadata(self, dataset: EventDataset):
)
assert dataset.metadata.periods[1].end_timestamp == timedelta(
minutes=20, seconds=47
) + timedelta(minutes=50, seconds=30)
) + timedelta(minutes=50, seconds=35)

def test_timestamps(self, dataset: EventDataset):
kickoff_p1 = dataset.get_event_by_id(663292348)
Expand Down Expand Up @@ -249,3 +249,8 @@ def test_interception_event(self, dataset: EventDataset):
def test_take_on_event(self, dataset: EventDataset):
take_on_event = dataset.get_event_by_id(139800000)
assert take_on_event.event_type == EventType.TAKE_ON

def test_carry_event(self, dataset: EventDataset):
carry_event = dataset.get_event_by_id(139800001)
assert carry_event.event_type == EventType.CARRY
assert carry_event.end_coordinates == Point(58.0, 74.0)

0 comments on commit c720be5

Please sign in to comment.