Skip to content

Commit

Permalink
Merge pull request #207 from MKlaasman/feature/add_miscontrol_events
Browse files Browse the repository at this point in the history
Add MiscontrolEvent
  • Loading branch information
koenvo authored Sep 18, 2023
2 parents 5751a88 + 53ce4ac commit 8b4b5a1
Show file tree
Hide file tree
Showing 11 changed files with 60 additions and 9 deletions.
17 changes: 17 additions & 0 deletions kloppy/domain/models/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ class EventType(Enum):
PLAYER_ON (EventType):
PLAYER_OFF (EventType):
RECOVERY (EventType):
MISCONTROL (EventType):
BALL_OUT (EventType):
FOUL_COMMITTED (EventType):
FORMATION_CHANGE (EventType):
Expand All @@ -203,6 +204,7 @@ class EventType(Enum):
PLAYER_ON = "PLAYER_ON"
PLAYER_OFF = "PLAYER_OFF"
RECOVERY = "RECOVERY"
MISCONTROL = "MISCONTROL"
BALL_OUT = "BALL_OUT"
FOUL_COMMITTED = "FOUL_COMMITTED"
FORMATION_CHANGE = "FORMATION_CHANGE"
Expand Down Expand Up @@ -864,6 +866,20 @@ class BallOutEvent(Event):
event_name: str = "ball_out"


@dataclass(repr=False)
@docstring_inherit_attributes(Event)
class MiscontrolEvent(Event):
"""
MiscontrolEvent
Attributes:
event_type (EventType): `EventType.MISCONTROL` (See [`EventType`][kloppy.domain.models.event.EventType])
event_name (str): "miscontrol"
"""

event_type: EventType = EventType.MISCONTROL
event_name: str = "miscontrol"


@dataclass(repr=False)
@docstring_inherit_attributes(Event)
class FoulCommittedEvent(Event):
Expand Down Expand Up @@ -976,6 +992,7 @@ def generic_record_converter(event: Event):
"FormationChangeEvent",
"EventDataset",
"RecoveryEvent",
"MiscontrolEvent",
"FoulCommittedEvent",
"BallOutEvent",
"SetPieceType",
Expand Down
4 changes: 4 additions & 0 deletions kloppy/domain/services/event_factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
GenericEvent,
TakeOnEvent,
RecoveryEvent,
MiscontrolEvent,
CarryEvent,
DuelEvent,
ClearanceEvent,
Expand Down Expand Up @@ -78,6 +79,9 @@ def build_generic(self, **kwargs) -> GenericEvent:
def build_recovery(self, **kwargs) -> RecoveryEvent:
return create_event(RecoveryEvent, **kwargs)

def build_miscontrol(self, **kwargs) -> MiscontrolEvent:
return create_event(MiscontrolEvent, **kwargs)

def build_take_on(self, **kwargs) -> TakeOnEvent:
return create_event(TakeOnEvent, **kwargs)

Expand Down
8 changes: 8 additions & 0 deletions kloppy/infra/serializers/event/opta/deserializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
EVENT_TYPE_CARD = 17
EVENT_TYPE_RECOVERY = 49
EVENT_TYPE_FORMATION_CHANGE = 40
EVENT_TYPE_BALL_TOUCH = 61

BALL_OUT_EVENTS = [EVENT_TYPE_BALL_OUT, EVENT_TYPE_CORNER_AWARDED]
DUEL_EVENTS = [EVENT_TYPE_TACKLE, EVENT_TYPE_AERIAL, EVENT_TYPE_50_50]
Expand All @@ -85,6 +86,7 @@
EVENT_TYPE_SHOT_SAVED,
EVENT_TYPE_SHOT_GOAL,
EVENT_TYPE_RECOVERY,
EVENT_TYPE_BALL_TOUCH,
)

EVENT_QUALIFIER_GOAL_KICK = 124
Expand Down Expand Up @@ -716,6 +718,12 @@ def deserialize(self, inputs: OptaInputs) -> EventDataset:
**duel_event_kwargs,
**generic_event_kwargs,
)
elif (type_id == EVENT_TYPE_BALL_TOUCH) & (outcome == 0):
event = self.event_factory.build_miscontrol(
result=None,
qualifiers=None,
**generic_event_kwargs,
)
elif (type_id == EVENT_TYPE_FOUL_COMMITTED) and (
outcome == 0
):
Expand Down
8 changes: 8 additions & 0 deletions kloppy/infra/serializers/event/statsbomb/deserializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
SB_EVENT_TYPE_SHOT = 16
SB_EVENT_TYPE_PASS = 30
SB_EVENT_TYPE_50_50 = 33
SB_EVENT_TYPE_MISCONTROL = 38
SB_EVENT_TYPE_CARRY = 43

SB_EVENT_TYPE_HALF_START = 18
Expand Down Expand Up @@ -794,6 +795,13 @@ def deserialize(self, inputs: StatsBombInputs) -> EventDataset:
**generic_event_kwargs,
)
new_events.append(clearance_event)
elif event_type == SB_EVENT_TYPE_MISCONTROL:
miscontrol_event = self.event_factory.build_miscontrol(
result=None,
qualifiers=None,
**generic_event_kwargs,
)
new_events.append(miscontrol_event)
# For dribble and carry the definitions
# are flipped between StatsBomb and kloppy
elif event_type == SB_EVENT_TYPE_DRIBBLE:
Expand Down
12 changes: 12 additions & 0 deletions kloppy/infra/serializers/event/wyscout/deserializer_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,18 @@ def deserialize(self, inputs: WyscoutInputs) -> EventDataset:
**clearance_event_args,
**generic_event_args,
)
elif (
raw_event["subEventId"]
== wyscout_events.OTHERS_ON_BALL.TOUCH
) & (_has_tag(raw_event, wyscout_tags.MISSED_BALL)):
miscontrol_event_args = {
"result": None,
"qualifiers": _generic_qualifiers(raw_event),
}
event = self.event_factory.build_miscontrol(
**miscontrol_event_args,
**generic_event_args,
)
else:
recovery_event_args = _parse_recovery(raw_event)
event = self.event_factory.build_recovery(
Expand Down
7 changes: 0 additions & 7 deletions kloppy/infra/serializers/event/wyscout/deserializer_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,6 @@ def _parse_team(raw_events, wyId: str, ground: Ground) -> Team:
return team


def _has_tag(raw_event, tag_id) -> bool:
for tag in raw_event["tags"]:
if tag["id"] == tag_id:
return True
return False


def _generic_qualifiers(raw_event: Dict) -> List[Qualifier]:
qualifiers: List[Qualifier] = []

Expand Down
4 changes: 4 additions & 0 deletions kloppy/tests/files/opta_f24.xml
Original file line number Diff line number Diff line change
Expand Up @@ -264,5 +264,9 @@
<Q id="6037763229" qualifier_id="56" value="Back" />
<Q id="6037763231" qualifier_id="140" value="23.9" />
</Event>
<Event id="2509132175" event_id="50" type_id="61" period_id="1" min="22" sec="6" player_id="460842" team_id="2592" outcome="0" x="1.3" y="81.1" timestamp="2018-09-23T17:21:01.810" last_modified="2018-09-23T17:08:02" version="1537718881823">
<Q id="4042410691" qualifier_id="178" />
<Q id="4039492675" qualifier_id="56" value="Back" />
</Event>
</Game>
</Games>
2 changes: 1 addition & 1 deletion kloppy/tests/test_adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,4 @@ def read_to_stream(self, url: str, output: BinaryIO):
# Asserts borrowed from `test_opta.py`
assert dataset.metadata.provider == Provider.OPTA
assert dataset.dataset_type == DatasetType.EVENT
assert len(dataset.events) == 23
assert len(dataset.events) == 24
5 changes: 4 additions & 1 deletion kloppy/tests/test_opta.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def test_correct_deserialization(self, f7_data: str, f24_data: str):
)
assert dataset.metadata.provider == Provider.OPTA
assert dataset.dataset_type == DatasetType.EVENT
assert len(dataset.events) == 23
assert len(dataset.events) == 24
assert len(dataset.metadata.periods) == 2
assert (
dataset.events[10].ball_owning_team == dataset.metadata.teams[1]
Expand Down Expand Up @@ -113,6 +113,9 @@ def test_correct_deserialization(self, f7_data: str, f24_data: str):
assert dataset.events[18].result.value == "OWN_GOAL" # 2318697001
# Check OFFSIDE pass has end_coordinates
assert dataset.events[20].receiver_coordinates.x == 89.3 # 2360555167
assert (
dataset.events[23].event_type == EventType.MISCONTROL
) # 250913217

# Check counterattack
assert (
Expand Down
1 change: 1 addition & 0 deletions kloppy/tests/test_statsbomb.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ def test_correct_deserialization(
== DuelType.GROUND
)
assert dataset.events[272].event_type == EventType.CLEARANCE
assert dataset.events[68].event_type == EventType.MISCONTROL

def test_correct_normalized_deserialization(
self, lineup_data: Path, event_data: Path
Expand Down
1 change: 1 addition & 0 deletions kloppy/tests/test_wyscout.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def test_correct_v2_deserialization(self, event_v2_data: Path):
data_version="V2",
)
assert dataset.records[2].coordinates == Point(29.0, 6.0)
assert dataset.events[11].event_type == EventType.MISCONTROL
assert dataset.events[136].event_type == EventType.CLEARANCE

assert (
Expand Down

0 comments on commit 8b4b5a1

Please sign in to comment.