Skip to content

Commit

Permalink
feat(Wyscout V3): add position information for players (#366)
Browse files Browse the repository at this point in the history
* wyscout v3 - add position information for players
* add PositionType for left and right wingback
  • Loading branch information
DriesDeprest authored Dec 3, 2024
1 parent ef2c398 commit f6db15f
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 18 deletions.
2 changes: 2 additions & 0 deletions kloppy/domain/models/position.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ class PositionType(Enum):
CenterBack = ("Center Back", "CB", "Defender")
LeftCenterBack = ("Left Center Back", "LCB", "CenterBack")
RightCenterBack = ("Right Center Back", "RCB", "CenterBack")
LeftWingBack = ("Left Wing Back", "LWB", "WingBack")
RightWingBack = ("Right Wing Back", "RWB", "WingBack")

Midfielder = ("Midfielder", "MID", None)
DefensiveMidfield = ("Defensive Midfield", "DM", "Midfielder")
Expand Down
81 changes: 63 additions & 18 deletions kloppy/infra/serializers/event/wyscout/deserializer_v3.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
Team,
FormationType,
CarryResult,
PositionType,
)
from kloppy.exceptions import DeserializationError
from kloppy.utils import performance_logging
Expand Down Expand Up @@ -81,36 +82,80 @@
"3-2-3-2": FormationType.THREE_TWO_THREE_TWO,
}

position_types_mapping: Dict[str, PositionType] = {
"GK": PositionType.Goalkeeper,
"LB": PositionType.LeftBack,
"LWB": PositionType.LeftWingBack,
"LB5": PositionType.LeftBack,
"LCB": PositionType.LeftCenterBack,
"LCB3": PositionType.LeftCenterBack,
"CB": PositionType.CenterBack,
"RCB": PositionType.RightCenterBack,
"RCB3": PositionType.RightCenterBack,
"RB": PositionType.RightBack,
"RWB": PositionType.RightWingBack,
"RB5": PositionType.RightBack,
"LW": PositionType.LeftWing,
"LAMF": PositionType.LeftAttackingMidfield,
"LCMF3": PositionType.LeftCentralMidfield,
"LCMF": PositionType.LeftCentralMidfield,
"DMF": PositionType.DefensiveMidfield,
"LDMF": PositionType.LeftDefensiveMidfield,
"RDMF": PositionType.RightDefensiveMidfield,
"RCMF3": PositionType.RightCentralMidfield,
"RCMF": PositionType.RightCentralMidfield,
"RAMF": PositionType.RightAttackingMidfield,
"RW": PositionType.RightWing,
"AMF": PositionType.AttackingMidfield,
"LWF": PositionType.LeftForward,
"CF": PositionType.Striker,
"SS": PositionType.Striker,
"RWF": PositionType.RightForward,
}


def _flip_point(point: Point) -> Point:
return Point(x=100 - point.x, y=100 - point.y)


def _parse_team(raw_events, wyId: str, ground: Ground) -> Team:
# Get the first formation description
first_period_formation_info = raw_events["formations"][wyId]["1H"]
first_formation_descr = next(iter(first_period_formation_info.values()))
formation_str, formation_info = next(iter(first_formation_descr.items()))

# Extract the formation and players' positions
starting_formation = formations.get(formation_str)
starting_players_positions = {
player_id: position_types_mapping.get(
player_info["position"].upper(), PositionType.Unknown
)
for player_descr in formation_info["players"]
for player_id, player_info in player_descr.items()
}

team = Team(
team_id=wyId,
name=raw_events["teams"][wyId]["team"]["officialName"],
ground=ground,
starting_formation=formations[
next(
iter(
raw_events["formations"][wyId]["1H"][
next(iter(raw_events["formations"][wyId]["1H"]))
]
)
)
],
starting_formation=starting_formation,
)
team.players = [
Player(
player_id=str(player["player"]["wyId"]),
team=team,
jersey_no=None,
first_name=player["player"]["firstName"],
last_name=player["player"]["lastName"],

for player in raw_events["players"][wyId]:
player_id = str(player["player"]["wyId"])
starting_position = starting_players_positions.get(player_id)
team.players.append(
Player(
player_id=player_id,
team=team,
jersey_no=None,
first_name=player["player"]["firstName"],
last_name=player["player"]["lastName"],
starting=starting_position is not None,
starting_position=starting_position,
)
)
for player in raw_events["players"][wyId]
]

return team


Expand Down
7 changes: 7 additions & 0 deletions kloppy/tests/test_wyscout.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
Time,
PassType,
PassQualifier,
PositionType,
)

from kloppy import wyscout
Expand Down Expand Up @@ -203,6 +204,12 @@ def test_metadata(self, dataset: EventDataset):
== FormationType.FOUR_THREE_ONE_TWO
)

cr7 = dataset.metadata.teams[0].get_player_by_id("3322")

assert cr7.full_name == "Cristiano Ronaldo dos Santos Aveiro"
assert cr7.starting is True
assert cr7.positions.last() == PositionType.Striker

def test_enriched_metadata(self, dataset: EventDataset):
date = dataset.metadata.date
if date:
Expand Down

0 comments on commit f6db15f

Please sign in to comment.