From fed94a05dcda41473f3931c422636512e0467c39 Mon Sep 17 00:00:00 2001 From: Ricardo Furbino Date: Wed, 22 May 2024 15:36:01 +0200 Subject: [PATCH 1/7] improvement: treats wyscout v3 shot end location --- .../event/wyscout/deserializer_v3.py | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py index fa6cb0e7..f5149b4d 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py @@ -48,7 +48,7 @@ from kloppy.utils import performance_logging from ..deserializer import EventDataDeserializer -from .deserializer_v2 import WyscoutInputs +from .deserializer_v2 import WyscoutInputs, _create_shot_result_coordinates logger = logging.getLogger(__name__) @@ -131,10 +131,7 @@ def _parse_shot(raw_event: Dict) -> Dict: return { "result": result, - "result_coordinates": Point( - x=float(0), - y=float(0), - ), + "result_coordinates": _create_shot_result_coordinates(raw_event), "qualifiers": qualifiers, } @@ -187,12 +184,14 @@ def _parse_pass(raw_event: Dict, next_event: Dict, team: Team) -> Dict: "qualifiers": _pass_qualifiers(raw_event), "receive_timestamp": None, "receiver_player": receiver_player, - "receiver_coordinates": Point( - x=float(raw_event["pass"]["endLocation"]["x"]), - y=float(raw_event["pass"]["endLocation"]["y"]), - ) - if len(raw_event["pass"]["endLocation"]) > 1 - else None, + "receiver_coordinates": ( + Point( + x=float(raw_event["pass"]["endLocation"]["x"]), + y=float(raw_event["pass"]["endLocation"]["y"]), + ) + if len(raw_event["pass"]["endLocation"]) > 1 + else None + ), } @@ -516,9 +515,11 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: periods.append( Period( id=period_id, - start_timestamp=timedelta(seconds=0) - if len(periods) == 0 - else periods[-1].end_timestamp, + start_timestamp=( + timedelta(seconds=0) + if len(periods) == 0 + else periods[-1].end_timestamp + ), end_timestamp=None, ) ) @@ -543,16 +544,20 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: generic_event_args = { "event_id": raw_event["id"], "raw_event": raw_event, - "coordinates": Point( - x=float(raw_event["location"]["x"]), - y=float(raw_event["location"]["y"]), - ) - if raw_event["location"] - else None, + "coordinates": ( + Point( + x=float(raw_event["location"]["x"]), + y=float(raw_event["location"]["y"]), + ) + if raw_event["location"] + else None + ), "team": team, - "player": players[team_id][player_id] - if player_id != INVALID_PLAYER - else None, + "player": ( + players[team_id][player_id] + if player_id != INVALID_PLAYER + else None + ), "ball_owning_team": ball_owning_team, "ball_state": None, "period": periods[-1], From aba5042746b05c70fe750120d196f72771b4dd68 Mon Sep 17 00:00:00 2001 From: Ricardo Furbino Date: Thu, 23 May 2024 02:09:49 +0200 Subject: [PATCH 2/7] fix: uses function for v3 instead of resusing v2 --- .../event/wyscout/deserializer_v3.py | 83 ++++++++++++++++++- .../serializers/event/wyscout/wyscout_tags.py | 22 +++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py index f5149b4d..30307fc4 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py @@ -2,7 +2,7 @@ import logging from dataclasses import replace from datetime import timedelta -from typing import Dict, List, Tuple, NamedTuple, IO +from typing import Dict, List, Tuple, NamedTuple, IO, Optional from kloppy.domain import ( BallOutEvent, @@ -48,7 +48,8 @@ from kloppy.utils import performance_logging from ..deserializer import EventDataDeserializer -from .deserializer_v2 import WyscoutInputs, _create_shot_result_coordinates +from .deserializer_v2 import WyscoutInputs +from . import wyscout_tags logger = logging.getLogger(__name__) @@ -99,6 +100,82 @@ def _parse_team(raw_events, wyId: str, ground: Ground) -> Team: return team +def _create_shot_result_coordinates(raw_event: Dict) -> Optional[Point]: + """Estimate the shot end location from the Wyscout tags. + + Wyscout does not provide end-coordinates of shots. Instead shots on goal + are tagged with a zone. This function maps each of these zones to + a coordinate. The zones and corresponding y-coordinate are depicted below. + + + olt | ot | ort + -------------------------------- + ||=================|| + ------------------------------- + || g;l | gt | grt || + -------------------------------- + ol || gcl | gc | gcr || or + -------------------------------- + olb || glb | gb | gln || grb + + 40 45 50 55 60 (y-coordinate of zone) + 44.62 55.38 (y-coordiante of post) + """ + if ( + raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.GoalBottomCenter + or raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.GoalCenter + or raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.GoalTopCenter + ): + return Point(100.0, 50.0) + if ( + raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.GoalBottomRight + or raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.GoalCenterRight + or raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.GoalTopRight + ): + return Point(100.0, 55.0) + if ( + raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.GoalBottomLeft + or raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.GoalCenterLeft + or raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.GoalTopLeft + ): + return Point(100.0, 45.0) + if raw_event["shot"]["goalZone"] == wyscout_tags.ShotZoneResults.OutTop: + return Point(100.0, 50.0) + if ( + raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.OutRightTop + or raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.OutRight + or raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.OutBottomRight + ): + return Point(100.0, 60.0) + if ( + raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.OutLeftTop + or raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.OutLeft + or raw_event["shot"]["goalZone"] + == wyscout_tags.ShotZoneResults.OutBottomLeft + ): + return Point(100.0, 40.0) + if raw_event["shot"]["goalZone"] == wyscout_tags.ShotZoneResults.Blocked: + return Point( + x=float(raw_event["location"]["x"]), + y=float(raw_event["positions"]["y"]), + ) + return None + + def _generic_qualifiers(raw_event: Dict) -> List[Qualifier]: qualifiers: List[Qualifier] = [] @@ -540,6 +617,8 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: ball_owning_team = teams[ str(raw_event["possession"]["team"]["id"]) ] + else: + ball_owning_team = team # TODO: this solve the issue of ball owning team when transforming to spald, but it's not correct generic_event_args = { "event_id": raw_event["id"], diff --git a/kloppy/infra/serializers/event/wyscout/wyscout_tags.py b/kloppy/infra/serializers/event/wyscout/wyscout_tags.py index 28f9d5fb..abb375dd 100644 --- a/kloppy/infra/serializers/event/wyscout/wyscout_tags.py +++ b/kloppy/infra/serializers/event/wyscout/wyscout_tags.py @@ -1,3 +1,5 @@ +from enum import Enum + GOAL = 101 OWN_GOAL = 102 @@ -87,3 +89,23 @@ DANGEROUS_BALL_LOST = 2001 BLOCKED = 2101 + + +class ShotZoneResults(Enum): + GoalBottomLeft = "glb" + GoalBottomRight = "gbr" + GoalBottomCenter = "gbc" + GoalCenterLeft = "gcl" + GoalCenter = "gc" + GoalCenterRight = "gcr" + GoalTopLeft = "gtl" + GoalTopRight = "gtr" + GoalTopCenter = "gtc" + OutBottomRight = "obr" + OutBottomLeft = "obl" + OutRight = "or" + OutLeft = "ol" + OutLeftTop = "olt" + OutTop = "ot" + OutRightTop = "ort" + Blocked = "bc" From 70318403cf5038aeed62f7f0b237b073c2227def Mon Sep 17 00:00:00 2001 From: Ricardo Furbino Date: Tue, 28 May 2024 00:13:55 +0200 Subject: [PATCH 3/7] refactor: moves shot zone results --- .../event/wyscout/deserializer_v3.py | 21 ++++++++++++++++++ .../serializers/event/wyscout/wyscout_tags.py | 22 ------------------- 2 files changed, 21 insertions(+), 22 deletions(-) diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py index 30307fc4..8cdd2758 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py @@ -2,6 +2,7 @@ import logging from dataclasses import replace from datetime import timedelta +from enum import Enum from typing import Dict, List, Tuple, NamedTuple, IO, Optional from kloppy.domain import ( @@ -81,6 +82,26 @@ } +class ShotZoneResults(Enum): + GoalBottomLeft = "glb" + GoalBottomRight = "gbr" + GoalBottomCenter = "gbc" + GoalCenterLeft = "gcl" + GoalCenter = "gc" + GoalCenterRight = "gcr" + GoalTopLeft = "gtl" + GoalTopRight = "gtr" + GoalTopCenter = "gtc" + OutBottomRight = "obr" + OutBottomLeft = "obl" + OutRight = "or" + OutLeft = "ol" + OutLeftTop = "olt" + OutTop = "ot" + OutRightTop = "ort" + Blocked = "bc" + + def _parse_team(raw_events, wyId: str, ground: Ground) -> Team: team = Team( team_id=wyId, diff --git a/kloppy/infra/serializers/event/wyscout/wyscout_tags.py b/kloppy/infra/serializers/event/wyscout/wyscout_tags.py index abb375dd..28f9d5fb 100644 --- a/kloppy/infra/serializers/event/wyscout/wyscout_tags.py +++ b/kloppy/infra/serializers/event/wyscout/wyscout_tags.py @@ -1,5 +1,3 @@ -from enum import Enum - GOAL = 101 OWN_GOAL = 102 @@ -89,23 +87,3 @@ DANGEROUS_BALL_LOST = 2001 BLOCKED = 2101 - - -class ShotZoneResults(Enum): - GoalBottomLeft = "glb" - GoalBottomRight = "gbr" - GoalBottomCenter = "gbc" - GoalCenterLeft = "gcl" - GoalCenter = "gc" - GoalCenterRight = "gcr" - GoalTopLeft = "gtl" - GoalTopRight = "gtr" - GoalTopCenter = "gtc" - OutBottomRight = "obr" - OutBottomLeft = "obl" - OutRight = "or" - OutLeft = "ol" - OutLeftTop = "olt" - OutTop = "ot" - OutRightTop = "ort" - Blocked = "bc" From 0ec6f6f0866579f14306365701f291fd0ec71c89 Mon Sep 17 00:00:00 2001 From: Ricardo Furbino Date: Tue, 28 May 2024 00:20:43 +0200 Subject: [PATCH 4/7] refactor: puts shot zone results in kloppy's enum standard --- .../event/wyscout/deserializer_v3.py | 90 +++++++++---------- 1 file changed, 41 insertions(+), 49 deletions(-) diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py index 8cdd2758..df08556b 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py @@ -83,23 +83,23 @@ class ShotZoneResults(Enum): - GoalBottomLeft = "glb" - GoalBottomRight = "gbr" - GoalBottomCenter = "gbc" - GoalCenterLeft = "gcl" - GoalCenter = "gc" - GoalCenterRight = "gcr" - GoalTopLeft = "gtl" - GoalTopRight = "gtr" - GoalTopCenter = "gtc" - OutBottomRight = "obr" - OutBottomLeft = "obl" - OutRight = "or" - OutLeft = "ol" - OutLeftTop = "olt" - OutTop = "ot" - OutRightTop = "ort" - Blocked = "bc" + GOAL_BOTTOM_LEFT = "glb" + GOAL_BOTTOM_RIGHT = "gbr" + GOAL_BOTTOM_CENTER = "gbc" + GOAL_CENTER_LEFT = "gcl" + GOAL_CENTER = "gc" + GOAL_CENTER_RIGHT = "gcr" + GOAL_TOP_LEFT = "gtl" + GOAL_TOP_RIGHT = "gtr" + GOAL_TOP_CENTER = "gtc" + OUT_BOTTOM_RIGHT = "obr" + OUT_BOTTOM_LEFT = "obl" + OUT_RIGHT = "or" + OUT_LEFT = "ol" + OUT_LEFT_TOP = "olt" + OUT_TOP = "ot" + OUT_RIGHT_TOP = "ort" + BLOCKED = "bc" def _parse_team(raw_events, wyId: str, ground: Ground) -> Team: @@ -143,57 +143,49 @@ def _create_shot_result_coordinates(raw_event: Dict) -> Optional[Point]: 44.62 55.38 (y-coordiante of post) """ if ( - raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.GoalBottomCenter - or raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.GoalCenter - or raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.GoalTopCenter + raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_BOTTOM_CENTER + or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_CENTER + or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_TOP_CENTER ): return Point(100.0, 50.0) + if ( - raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.GoalBottomRight - or raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.GoalCenterRight - or raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.GoalTopRight + raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_BOTTOM_RIGHT + or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_CENTER_RIGHT + or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_TOP_RIGHT ): return Point(100.0, 55.0) + if ( - raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.GoalBottomLeft - or raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.GoalCenterLeft - or raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.GoalTopLeft + raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_BOTTOM_LEFT + or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_CENTER_LEFT + or raw_event["shot"]["goalZone"] == ShotZoneResults.GOAL_TOP_LEFT ): return Point(100.0, 45.0) - if raw_event["shot"]["goalZone"] == wyscout_tags.ShotZoneResults.OutTop: + + if raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_TOP: return Point(100.0, 50.0) + if ( - raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.OutRightTop - or raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.OutRight - or raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.OutBottomRight + raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_RIGHT_TOP + or raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_RIGHT + or raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_BOTTOM_RIGHT ): return Point(100.0, 60.0) + if ( - raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.OutLeftTop - or raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.OutLeft - or raw_event["shot"]["goalZone"] - == wyscout_tags.ShotZoneResults.OutBottomLeft + raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_LEFT_TOP + or raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_LEFT + or raw_event["shot"]["goalZone"] == ShotZoneResults.OUT_BOTTOM_LEFT ): return Point(100.0, 40.0) - if raw_event["shot"]["goalZone"] == wyscout_tags.ShotZoneResults.Blocked: + + if raw_event["shot"]["goalZone"] == ShotZoneResults.BLOCKED: return Point( x=float(raw_event["location"]["x"]), y=float(raw_event["positions"]["y"]), ) + return None From 922c4a820ca5469f855ec5c71ef5dd2299fb0900 Mon Sep 17 00:00:00 2001 From: Ricardo Furbino Date: Tue, 28 May 2024 00:29:37 +0200 Subject: [PATCH 5/7] fix: removes band-aid fix --- kloppy/infra/serializers/event/wyscout/deserializer_v3.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py index df08556b..1f7dc6a5 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py @@ -630,8 +630,6 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset: ball_owning_team = teams[ str(raw_event["possession"]["team"]["id"]) ] - else: - ball_owning_team = team # TODO: this solve the issue of ball owning team when transforming to spald, but it's not correct generic_event_args = { "event_id": raw_event["id"], From d5d5a7f0b85539cab561b177ac6f70b100953a72 Mon Sep 17 00:00:00 2001 From: Ricardo Furbino Date: Tue, 28 May 2024 15:13:47 +0200 Subject: [PATCH 6/7] fix: removes import --- kloppy/infra/serializers/event/wyscout/deserializer_v3.py | 1 - 1 file changed, 1 deletion(-) diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py index 1f7dc6a5..6304dbc0 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py @@ -50,7 +50,6 @@ from ..deserializer import EventDataDeserializer from .deserializer_v2 import WyscoutInputs -from . import wyscout_tags logger = logging.getLogger(__name__) From 0073035fe258d8af04ceaa14588876ecca923214 Mon Sep 17 00:00:00 2001 From: Pieter Robberechts Date: Sat, 14 Dec 2024 19:53:25 +0100 Subject: [PATCH 7/7] add test + bugfixes --- .../event/wyscout/deserializer_v3.py | 28 ++++++------ kloppy/tests/test_wyscout.py | 44 ++++++++++++------- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py index 02df3d32..8e2143aa 100644 --- a/kloppy/infra/serializers/event/wyscout/deserializer_v3.py +++ b/kloppy/infra/serializers/event/wyscout/deserializer_v3.py @@ -109,18 +109,18 @@ def _flip_point(point: Point) -> Point: return Point(x=100 - point.x, y=100 - point.y) -class ShotZoneResults(Enum): +class ShotZoneResults(str, Enum): GOAL_BOTTOM_LEFT = "glb" - GOAL_BOTTOM_RIGHT = "gbr" - GOAL_BOTTOM_CENTER = "gbc" - GOAL_CENTER_LEFT = "gcl" + GOAL_BOTTOM_RIGHT = "grb" + GOAL_BOTTOM_CENTER = "gb" + GOAL_CENTER_LEFT = "gl" GOAL_CENTER = "gc" - GOAL_CENTER_RIGHT = "gcr" - GOAL_TOP_LEFT = "gtl" - GOAL_TOP_RIGHT = "gtr" - GOAL_TOP_CENTER = "gtc" + GOAL_CENTER_RIGHT = "gr" + GOAL_TOP_LEFT = "glt" + GOAL_TOP_RIGHT = "grt" + GOAL_TOP_CENTER = "gt" OUT_BOTTOM_RIGHT = "obr" - OUT_BOTTOM_LEFT = "obl" + OUT_BOTTOM_LEFT = "olb" OUT_RIGHT = "or" OUT_LEFT = "ol" OUT_LEFT_TOP = "olt" @@ -182,11 +182,11 @@ def _create_shot_result_coordinates(raw_event: Dict) -> Optional[Point]: -------------------------------- ||=================|| ------------------------------- - || g;l | gt | grt || + || glt | gt | grt || -------------------------------- - ol || gcl | gc | gcr || or + ol || gl | gc | gr || or -------------------------------- - olb || glb | gb | gln || grb + olb || glb | gb | grb || orb 40 45 50 55 60 (y-coordinate of zone) 44.62 55.38 (y-coordiante of post) @@ -229,10 +229,12 @@ def _create_shot_result_coordinates(raw_event: Dict) -> Optional[Point]: ): return Point(100.0, 40.0) + # If the shot is blocked, the start location is the best possible estimate + # for the shot's end location if raw_event["shot"]["goalZone"] == ShotZoneResults.BLOCKED: return Point( x=float(raw_event["location"]["x"]), - y=float(raw_event["positions"]["y"]), + y=float(raw_event["location"]["y"]), ) return None diff --git a/kloppy/tests/test_wyscout.py b/kloppy/tests/test_wyscout.py index 5d28f64e..d5cb8b2f 100644 --- a/kloppy/tests/test_wyscout.py +++ b/kloppy/tests/test_wyscout.py @@ -2,32 +2,33 @@ from pathlib import Path import pytest + +from kloppy import wyscout from kloppy.domain import ( BodyPart, BodyPartQualifier, - Point, - EventDataset, - SetPieceType, - SetPieceQualifier, + CardQualifier, + CardType, DatasetType, DuelQualifier, DuelType, + EventDataset, EventType, - GoalkeeperQualifier, + FormationType, GoalkeeperActionType, - CardQualifier, - CardType, + GoalkeeperQualifier, Orientation, + PassQualifier, PassResult, - FormationType, - Time, PassType, - PassQualifier, + Point, PositionType, + SetPieceQualifier, + SetPieceType, + ShotResult, + Time, ) -from kloppy import wyscout - @pytest.fixture(scope="session") def event_v2_data(base_dir: Path) -> Path: @@ -268,12 +269,25 @@ def test_shot_assist_event(self, dataset: EventDataset): ) def test_shot_event(self, dataset: EventDataset): - shot_event = dataset.get_event_by_id(1927028534) - assert shot_event.event_type == EventType.SHOT + # a blocked free kick shot + blocked_shot_event = dataset.get_event_by_id(1927028534) + assert blocked_shot_event.event_type == EventType.SHOT + assert blocked_shot_event.result == ShotResult.BLOCKED + assert blocked_shot_event.result_coordinates == Point(x=77.0, y=21.0) assert ( - shot_event.get_qualifier_value(SetPieceQualifier) + blocked_shot_event.get_qualifier_value(SetPieceQualifier) == SetPieceType.FREE_KICK ) + # off target shot + off_target_shot = dataset.get_event_by_id(1927028562) + assert off_target_shot.event_type == EventType.SHOT + assert off_target_shot.result == ShotResult.OFF_TARGET + assert off_target_shot.result_coordinates is None + # on target shot + on_target_shot = dataset.get_event_by_id(1927028637) + assert on_target_shot.event_type == EventType.SHOT + assert on_target_shot.result == ShotResult.SAVED + assert on_target_shot.result_coordinates == Point(100.0, 45.0) def test_foul_committed_event(self, dataset: EventDataset): foul_committed_event = dataset.get_event_by_id(1927028873)