def _frame_from_row(row: dict, metadata: EPTSMetadata) -> Frame: timestamp = row["timestamp"] if metadata.periods and row["period_id"]: # might want to search for it instead period = metadata.periods[row["period_id"] - 1] else: period = None players_coordinates = {} for team in metadata.teams: for player in team.players: if f"player_{player.player_id}_x" in row: players_coordinates[player] = Point( x=row[f"player_{player.player_id}_x"], y=row[f"player_{player.player_id}_y"], ) return Frame( frame_id=row["frame_id"], timestamp=timestamp, ball_owning_team=None, ball_state=None, period=period, players_coordinates=players_coordinates, ball_coordinates=Point(x=row["ball_x"], y=row["ball_y"]), )
def test_transform_to_coordinate_system(self): base_dir = os.path.dirname(__file__) dataset = tracab.load( meta_data=f"{base_dir}/files/tracab_meta.xml", raw_data=f"{base_dir}/files/tracab_raw.dat", only_alive=False, coordinates="tracab", ) player_home_19 = dataset.metadata.teams[0].get_player_by_jersey_number( 19) assert dataset.records[0].players_data[ player_home_19].coordinates == Point(x=-1234.0, y=-294.0) transformed_dataset = dataset.transform( to_coordinate_system=Provider.METRICA) transformerd_coordinate_system = MetricaCoordinateSystem( normalized=True, length=dataset.metadata.coordinate_system.length, width=dataset.metadata.coordinate_system.width, ) assert transformed_dataset.records[0].players_data[ player_home_19].coordinates == Point(x=0.3766, y=0.5489999999999999) assert (transformed_dataset.metadata.orientation == dataset.metadata.orientation) assert (transformed_dataset.metadata.coordinate_system == transformerd_coordinate_system) assert (transformed_dataset.metadata.pitch_dimensions == transformerd_coordinate_system.pitch_dimensions)
def _frame_from_row(row: dict, meta_data: EPTSMetaData) -> Frame: timestamp = row["timestamp"] if meta_data.periods and row["period_id"]: # might want to search for it instead period = meta_data.periods[row["period_id"] - 1] else: period = None home_team_player_positions = {} away_team_player_positions = {} for player in meta_data.players: if player.team == Team.HOME: if f"player_home_{player.jersey_no}_x" in row: home_team_player_positions[player.jersey_no] = Point( x=row[f"player_home_{player.jersey_no}_x"], y=row[f"player_home_{player.jersey_no}_y"], ) elif player.team == Team.AWAY: if f"player_away_{player.jersey_no}_x" in row: away_team_player_positions[player.jersey_no] = Point( x=row[f"player_away_{player.jersey_no}_x"], y=row[f"player_away_{player.jersey_no}_y"], ) return Frame( frame_id=row["frame_id"], timestamp=timestamp, ball_owning_team=None, ball_state=None, period=period, home_team_player_positions=home_team_player_positions, away_team_player_positions=away_team_player_positions, ball_position=Point(x=row["ball_x"], y=row["ball_y"]), )
def _frame_from_row(row: dict, meta_data: EPTSMetaData) -> Frame: timestamp = row['timestamp'] if meta_data.periods: # might want to search for it instead period = meta_data.periods[row['period_id'] - 1] else: period = None home_team_player_positions = {} away_team_player_positions = {} for player in meta_data.players: if player.team == Team.HOME: home_team_player_positions[player.jersey_no] = Point( x=row[f'player_home_{player.jersey_no}_x'], y=row[f'player_home_{player.jersey_no}_y']) elif player.team == Team.AWAY: home_team_player_positions[player.jersey_no] = Point( x=row[f'player_away_{player.jersey_no}_x'], y=row[f'player_away_{player.jersey_no}_y']) return Frame(frame_id=row['frame_id'], timestamp=timestamp, ball_owning_team=None, ball_state=None, period=period, home_team_player_positions=home_team_player_positions, away_team_player_positions=away_team_player_positions, ball_position=Point(x=row['ball_x'], y=row['ball_y']))
def _get_tracking_dataset(self): home_team = Team(team_id="home", name="home", ground=Ground.HOME) away_team = Team(team_id="away", name="away", ground=Ground.AWAY) teams = [home_team, away_team] periods = [ Period( id=1, start_timestamp=0.0, end_timestamp=10.0, attacking_direction=AttackingDirection.HOME_AWAY, ), Period( id=2, start_timestamp=15.0, end_timestamp=25.0, attacking_direction=AttackingDirection.AWAY_HOME, ), ] metadata = Metadata( flags=~(DatasetFlag.BALL_OWNING_TEAM | DatasetFlag.BALL_STATE), pitch_dimensions=PitchDimensions(x_dim=Dimension(0, 100), y_dim=Dimension(-50, 50)), orientation=Orientation.HOME_TEAM, frame_rate=25, periods=periods, teams=teams, score=None, provider=None, ) tracking_data = TrackingDataset( metadata=metadata, records=[ Frame( frame_id=1, timestamp=0.1, ball_owning_team=None, ball_state=None, period=periods[0], players_coordinates={}, ball_coordinates=Point(x=100, y=-50), ), Frame( frame_id=2, timestamp=0.2, ball_owning_team=None, ball_state=None, period=periods[0], players_coordinates={ Player(team=home_team, player_id="home_1", jersey_no=1): Point(x=15, y=35) }, ball_coordinates=Point(x=0, y=50), ), ], ) return tracking_data
def test_correct_deserialization(self): base_dir = os.path.dirname(__file__) serializer = MetricaTrackingSerializer() with open( f"{base_dir}/files/metrica_home.csv", "rb" ) as raw_data_home, open( f"{base_dir}/files/metrica_away.csv", "rb" ) as raw_data_away: dataset = serializer.deserialize( inputs={ "raw_data_home": raw_data_home, "raw_data_away": raw_data_away, } ) assert dataset.metadata.provider == Provider.METRICA assert dataset.dataset_type == DatasetType.TRACKING assert len(dataset.records) == 6 assert len(dataset.metadata.periods) == 2 assert dataset.metadata.orientation == Orientation.FIXED_HOME_AWAY assert dataset.metadata.periods[0] == Period( id=1, start_timestamp=0.04, end_timestamp=0.12, attacking_direction=AttackingDirection.HOME_AWAY, ) assert dataset.metadata.periods[1] == Period( id=2, start_timestamp=5800.16, end_timestamp=5800.24, attacking_direction=AttackingDirection.AWAY_HOME, ) # make sure data is loaded correctly (including flip y-axis) home_player = dataset.metadata.teams[0].players[0] assert dataset.records[0].players_coordinates[home_player] == Point( x=0.00082, y=1 - 0.48238 ) away_player = dataset.metadata.teams[1].players[0] assert dataset.records[0].players_coordinates[away_player] == Point( x=0.90509, y=1 - 0.47462 ) assert dataset.records[0].ball_coordinates == Point( x=0.45472, y=1 - 0.38709 ) # make sure player data is only in the frame when the player is at the pitch assert "home_14" not in [ player.player_id for player in dataset.records[0].players_coordinates.keys() ] assert "home_14" in [ player.player_id for player in dataset.records[3].players_coordinates.keys() ]
def __create_iterator(self, data: Readable, sample_rate: float, frame_rate: int) -> Iterator: """ Notes: 1. the y-axis is flipped because Metrica use (y, -y) instead of (-y, y) """ team = None frame_idx = 0 frame_sample = 1 / sample_rate player_jersey_numbers = [] period = None for i, line in enumerate(data): line = line.strip().decode("ascii") columns = line.split(",") if i == 0: team = columns[3] elif i == 1: player_jersey_numbers = columns[3:-2:2] elif i == 2: # consider doing some validation on the columns pass else: period_id = int(columns[0]) frame_id = int(columns[1]) if period is None or period.id != period_id: period = Period( id=period_id, start_timestamp=frame_id / frame_rate, end_timestamp=frame_id / frame_rate, ) else: # consider not update this every frame for performance reasons period.end_timestamp = frame_id / frame_rate if frame_idx % frame_sample == 0: yield self.__PartialFrame( team=team, period=period, frame_id=frame_id, player_positions={ player_no: Point( x=float(columns[3 + i * 2]), y=1 - float(columns[3 + i * 2 + 1]), ) for i, player_no in enumerate( player_jersey_numbers) if columns[3 + i * 2] != "NaN" }, ball_position=Point(x=float(columns[-2]), y=1 - float(columns[-1])) if columns[-2] != "NaN" else None, ) frame_idx += 1
def test_transform(self): tracking_data = self._get_dataset() # orientation change AND dimension scale transformed_data_set = transform(tracking_data, to_orientation="AWAY_TEAM", to_pitch_dimensions=[[0, 1], [0, 1]]) assert transformed_data_set.frames[0].ball_position == Point(x=0, y=1) assert transformed_data_set.frames[1].ball_position == Point(x=1, y=0)
def test_correct_deserialization(self, meta_data: str, raw_data: str, additional_meta_data: str): dataset = secondspectrum.load( meta_data=meta_data, raw_data=raw_data, additional_meta_data=additional_meta_data, only_alive=False, coordinates="secondspectrum", ) # Check provider, type, shape, etc assert dataset.metadata.provider == Provider.SECONDSPECTRUM assert dataset.dataset_type == DatasetType.TRACKING assert len(dataset.records) == 376 assert len(dataset.metadata.periods) == 2 assert dataset.metadata.orientation == Orientation.FIXED_AWAY_HOME # Check the Periods assert dataset.metadata.periods[0].id == 1 assert dataset.metadata.periods[0].start_timestamp == 0 assert dataset.metadata.periods[0].end_timestamp == 2982240 assert (dataset.metadata.periods[0].attacking_direction == AttackingDirection.AWAY_HOME) assert dataset.metadata.periods[1].id == 2 assert dataset.metadata.periods[1].start_timestamp == 3907360 assert dataset.metadata.periods[1].end_timestamp == 6927840 assert (dataset.metadata.periods[1].attacking_direction == AttackingDirection.HOME_AWAY) # Check some timestamps assert dataset.records[0].timestamp == 0 # First frame assert dataset.records[20].timestamp == 320.0 # Later frame # Check some players home_player = dataset.metadata.teams[0].players[2] assert home_player.player_id == "8xwx2" assert dataset.records[0].players_coordinates[home_player] == Point( x=-8.943903672572427, y=-28.171654132650364) away_player = dataset.metadata.teams[1].players[3] assert away_player.player_id == "2q0uv" assert dataset.records[0].players_coordinates[away_player] == Point( x=-45.11871334915762, y=-20.06459030559596) # Check the ball assert dataset.records[1].ball_coordinates == Point3D( x=-23.147073918432426, y=13.69367399756424, z=0.0) # Check pitch dimensions pitch_dimensions = dataset.metadata.pitch_dimensions assert pitch_dimensions.x_dim.min == -52.425 assert pitch_dimensions.x_dim.max == 52.425 assert pitch_dimensions.y_dim.min == -33.985 assert pitch_dimensions.y_dim.max == 33.985
def _frame_from_line(cls, period, line, frame_rate): line = str(line) frame_id, players, ball = line.strip().split(":")[:3] home_team_player_positions = {} away_team_player_positions = {} for player in players.split(";")[:-1]: team_id, target_id, jersey_no, x, y, speed = player.split(",") team_id = int(team_id) if team_id == 1: home_team_player_positions[jersey_no] = Point( float(x), float(y)) elif team_id == 0: away_team_player_positions[jersey_no] = Point( float(x), float(y)) ( ball_x, ball_y, ball_z, ball_speed, ball_owning_team, ball_state, ) = ball.rstrip(";").split(",")[:6] frame_id = int(frame_id) if ball_owning_team == "H": ball_owning_team = Team.HOME elif ball_owning_team == "A": ball_owning_team = Team.AWAY else: raise Exception(f"Unknown ball owning team: {ball_owning_team}") if ball_state == "Alive": ball_state = BallState.ALIVE elif ball_state == "Dead": ball_state = BallState.DEAD else: raise Exception(f"Unknown ball state: {ball_state}") return Frame( frame_id=frame_id, timestamp=frame_id / frame_rate - period.start_timestamp, ball_position=Point(float(ball_x), float(ball_y)), ball_state=ball_state, ball_owning_team=ball_owning_team, home_team_player_positions=home_team_player_positions, away_team_player_positions=away_team_player_positions, period=period, )
def test_correct_deserialization(self): base_dir = os.path.dirname(__file__) serializer = TRACABSerializer() with open(f"{base_dir}/files/tracab_meta.xml", "rb") as meta_data, open(f"{base_dir}/files/tracab_raw.dat", "rb") as raw_data: dataset = serializer.deserialize( inputs={ "meta_data": meta_data, "raw_data": raw_data }, options={"only_alive": False}, ) assert len(dataset.records) == 6 assert len(dataset.periods) == 2 assert dataset.orientation == Orientation.FIXED_HOME_AWAY assert dataset.periods[0] == Period( id=1, start_timestamp=4.0, end_timestamp=4.08, attacking_direction=AttackingDirection.HOME_AWAY, ) assert dataset.periods[1] == Period( id=2, start_timestamp=8.0, end_timestamp=8.08, attacking_direction=AttackingDirection.AWAY_HOME, ) assert dataset.records[0].home_team_player_positions["19"] == Point( x=-1234.0, y=-294.0) assert dataset.records[0].away_team_player_positions["19"] == Point( x=8889, y=-666) assert dataset.records[0].ball_position == Point(x=-27, y=25) assert dataset.records[0].ball_state == BallState.ALIVE assert dataset.records[0].ball_owning_team == Team.HOME assert dataset.records[1].ball_owning_team == Team.AWAY assert dataset.records[2].ball_state == BallState.DEAD # make sure player data is only in the frame when the player is at the pitch assert "1337" not in dataset.records[0].away_team_player_positions assert "1337" in dataset.records[3].away_team_player_positions
def test_correct_normalized_deserialization(self, f7_data: str, f24_data: str): dataset = opta.load( f24_data=f24_data, f7_data=f7_data, ) assert dataset.events[0].coordinates == Point(0.501, 0.506)
def test_correct_deserialization(self): base_dir = os.path.dirname(__file__) serializer = EPTSSerializer() with open(f"{base_dir}/files/epts_meta.xml", "rb") as metadata, open(f"{base_dir}/files/epts_raw.txt", "rb") as raw_data: dataset = serializer.deserialize(inputs={ "metadata": metadata, "raw_data": raw_data }) first_player = next(iter(dataset.records[0].players_coordinates)) assert len(dataset.records) == 2 assert len(dataset.metadata.periods) == 1 assert dataset.metadata.orientation is None assert dataset.records[0].players_coordinates[first_player] == Point( x=-769, y=-2013) assert dataset.records[0].ball_coordinates == Point3D(x=-2656, y=367, z=100)
def __change_point_coordinate_system(self, point: Union[Point, Point3D]): if not point: return None x = self._from_coordinate_system.pitch_dimensions.x_dim.to_base( point.x ) y = self._from_coordinate_system.pitch_dimensions.y_dim.to_base( point.y ) if ( self._from_coordinate_system.vertical_orientation != self._to_coordinate_system.vertical_orientation ): y = 1 - y if not self._to_coordinate_system.normalized: x = self._to_coordinate_system.pitch_dimensions.x_dim.from_base(x) y = self._to_coordinate_system.pitch_dimensions.y_dim.from_base(y) if isinstance(point, Point3D): return Point3D(x=x, y=y, z=point.z) else: return Point(x=x, y=y)
def _parse_coordinates(event_attributes: Dict) -> Point: if "X-Position" not in event_attributes: return None return Point( x=float(event_attributes["X-Position"]), y=float(event_attributes["Y-Position"]), )
def _parse_shot(raw_event: Dict, next_event: Dict) -> Dict: result = None qualifiers = _generic_qualifiers(raw_event) if _has_tag(raw_event, 101): result = ShotResult.GOAL elif _has_tag(raw_event, 2101): result = ShotResult.BLOCKED elif any((_has_tag(raw_event, tag) for tag in wyscout_tags.SHOT_POST)): result = ShotResult.POST elif any( (_has_tag(raw_event, tag) for tag in wyscout_tags.SHOT_OFF_TARGET) ): result = ShotResult.OFF_TARGET elif any((_has_tag(raw_event, tag) for tag in wyscout_tags.SHOT_ON_GOAL)): result = ShotResult.SAVED if next_event["eventName"] == wyscout_events.SAVE.EVENT: if next_event["subEventName"] == wyscout_events.SAVE.REFLEXES: qualifiers.append( GoalkeeperActionQualifier(GoalkeeperAction.REFLEX) ) if next_event["subEventName"] == wyscout_events.SAVE.SAVE_ATTEMPT: qualifiers.append( GoalkeeperActionQualifier(GoalkeeperAction.SAVE_ATTEMPT) ) return { "result": result, "result_coordinates": Point( x=float(raw_event["positions"][1]["x"]), y=float(raw_event["positions"][1]["y"]), ), "qualifiers": qualifiers, }
def _parse_pass(raw_event: Dict, next_event: Dict) -> Dict: pass_result = None if _has_tag(raw_event, wyscout_tags.ACCURATE): pass_result = PassResult.COMPLETE elif _has_tag(raw_event, wyscout_tags.NOT_ACCURATE): pass_result = PassResult.INCOMPLETE if next_event: if next_event["eventName"] == wyscout_events.OFFSIDE.EVENT: pass_result = PassResult.OFFSIDE if next_event["eventName"] == wyscout_events.INTERRUPTION.EVENT: if ( next_event["subEventName"] == wyscout_events.INTERRUPTION.BALL_OUT ): pass_result = PassResult.OUT return { "result": pass_result, "qualifiers": _pass_qualifiers(raw_event), "receive_timestamp": None, "receiver_player": None, "receiver_coordinates": Point( x=float(raw_event["positions"][1]["x"]), y=float(raw_event["positions"][1]["y"]), ), }
def _parse_coordinates(coordinates: Dict[str, float]) -> Point: # location is cell based # +-------+-------+ # | -1,-1 | 1,-1 | # +-------+-------+ # | -1,1 | 1,1 | # +-------+-------+ return Point(x=coordinates["x"], y=coordinates["y"])
def _get_tracking_dataset(self): periods = [ Period( id=1, start_timestamp=0.0, end_timestamp=10.0, attacking_direction=AttackingDirection.HOME_AWAY, ), Period( id=2, start_timestamp=15.0, end_timestamp=25.0, attacking_direction=AttackingDirection.AWAY_HOME, ), ] tracking_data = TrackingDataset( flags=~(DatasetFlag.BALL_OWNING_TEAM | DatasetFlag.BALL_STATE), pitch_dimensions=PitchDimensions(x_dim=Dimension(0, 100), y_dim=Dimension(-50, 50)), orientation=Orientation.HOME_TEAM, frame_rate=25, records=[ Frame( frame_id=1, timestamp=0.1, ball_owning_team=None, ball_state=None, period=periods[0], away_team_player_positions={}, home_team_player_positions={}, ball_position=Point(x=100, y=-50), ), Frame( frame_id=2, timestamp=0.2, ball_owning_team=None, ball_state=None, period=periods[0], away_team_player_positions={"1": Point(x=10, y=20)}, home_team_player_positions={"1": Point(x=15, y=35)}, ball_position=Point(x=0, y=50), ), ], periods=periods, ) return tracking_data
def test_correct_normalized_deserialization(self, lineup_data: str, event_data: str): """ This test uses data from the StatsBomb open data project. """ dataset = statsbomb.load(lineup_data=lineup_data, event_data=event_data) assert dataset.events[10].coordinates == Point(0.2875, 0.25625)
def _parse_shot(qualifiers: Dict[int, str], type_id: int, position: Point) -> Dict: if type_id == EVENT_TYPE_SHOT_GOAL: if 28 in qualifiers: position = Point(x=100 - position.x, y=100 - position.y) result = ShotResult.GOAL else: result = None return dict(position=position, result=result)
def _parse_shot(qualifiers: Dict[int, str], type_id: int, coordinates: Point) -> Dict: if type_id == EVENT_TYPE_SHOT_GOAL: if 28 in qualifiers: coordinates = Point(x=100 - coordinates.x, y=100 - coordinates.y) result = ShotResult.GOAL else: result = None return dict(coordinates=coordinates, result=result)
def test_correct_normalized_deserialization( self, meta_data: str, raw_data: str ): base_dir = os.path.dirname(__file__) dataset = skillcorner.load(meta_data=meta_data, raw_data=raw_data) home_player = dataset.metadata.teams[0].players[2] assert dataset.records[0].players_data[ home_player ].coordinates == Point(x=0.8225688718076191, y=0.6405503322430882)
def _parse_coordinates(event_start_or_end: dict) -> Point: x = event_start_or_end["x"] y = event_start_or_end["y"] if x is None: return None return Point( x=x, y=y, )
def test_correct_deserialization(self, home_data: str, away_data: str): dataset = metrica.load_tracking_csv(home_data=home_data, away_data=away_data) assert dataset.metadata.provider == Provider.METRICA assert dataset.dataset_type == DatasetType.TRACKING assert len(dataset.records) == 6 assert len(dataset.metadata.periods) == 2 assert dataset.metadata.orientation == Orientation.FIXED_HOME_AWAY assert dataset.metadata.periods[0] == Period( id=1, start_timestamp=0.04, end_timestamp=0.12, attacking_direction=AttackingDirection.HOME_AWAY, ) assert dataset.metadata.periods[1] == Period( id=2, start_timestamp=5800.16, end_timestamp=5800.24, attacking_direction=AttackingDirection.AWAY_HOME, ) # make sure data is loaded correctly (including flip y-axis) home_player = dataset.metadata.teams[0].players[0] assert dataset.records[0].players_data[ home_player].coordinates == Point(x=0.00082, y=1 - 0.48238) away_player = dataset.metadata.teams[1].players[0] assert dataset.records[0].players_data[ away_player].coordinates == Point(x=0.90509, y=1 - 0.47462) assert dataset.records[0].ball_coordinates == Point(x=0.45472, y=1 - 0.38709) # make sure player data is only in the frame when the player is at the pitch assert "home_14" not in [ player.player_id for player in dataset.records[0].players_data.keys() ] assert "home_14" in [ player.player_id for player in dataset.records[3].players_data.keys() ]
def _frame_from_row(row: dict, metadata: EPTSMetadata, transformer: DatasetTransformer) -> Frame: timestamp = row["timestamp"] if metadata.periods and row["period_id"]: # might want to search for it instead period = metadata.periods[row["period_id"] - 1] else: period = None other_sensors = [] for sensor in metadata.sensors: if sensor.sensor_id not in ["position", "distance", "speed"]: other_sensors.append(sensor) players_data = {} for team in metadata.teams: for player in team.players: other_data = {} for sensor in other_sensors: other_data.update({ sensor.sensor_id: row[f"player_{player.player_id}_{sensor.channels[0].channel_id}"] }) players_data[player] = PlayerData( coordinates=Point( x=row[f"player_{player.player_id}_x"], y=row[f"player_{player.player_id}_y"], ) if f"player_{player.player_id}_x" in row else None, speed=row[f"player_{player.player_id}_s"] if f"player_{player.player_id}_s" in row else None, distance=row[f"player_{player.player_id}_d"] if f"player_{player.player_id}_d" in row else None, other_data=other_data, ) frame = Frame( frame_id=row["frame_id"], timestamp=timestamp, ball_owning_team=None, ball_state=None, period=period, players_data=players_data, other_data={}, ball_coordinates=Point3D(x=row["ball_x"], y=row["ball_y"], z=row.get("ball_z")), ) if transformer: frame = transformer.transform_frame(frame) return frame
def _parse_pass(raw_qualifiers: Dict[int, str], outcome: int) -> Dict: if outcome: receiver_coordinates = Point(x=float(raw_qualifiers[140]), y=float(raw_qualifiers[141])) result = PassResult.COMPLETE else: result = PassResult.INCOMPLETE # receiver_coordinates = None receiver_coordinates = Point(x=float(raw_qualifiers[140]), y=float(raw_qualifiers[141])) qualifiers = _get_event_qualifiers(raw_qualifiers) return dict( result=result, receiver_coordinates=receiver_coordinates, receiver_player=None, receive_timestamp=None, qualifiers=qualifiers, )
def test_correct_deserialization(self): base_dir = os.path.dirname(__file__) serializer = MetricaTrackingSerializer() with open(f"{base_dir}/files/metrica_home.csv", "rb") as raw_data_home, open( f"{base_dir}/files/metrica_away.csv", "rb") as raw_data_away: dataset = serializer.deserialize(inputs={ "raw_data_home": raw_data_home, "raw_data_away": raw_data_away, }) assert len(dataset.records) == 6 assert len(dataset.periods) == 2 assert dataset.orientation == Orientation.FIXED_HOME_AWAY assert dataset.periods[0] == Period( id=1, start_timestamp=0.04, end_timestamp=0.12, attacking_direction=AttackingDirection.HOME_AWAY, ) assert dataset.periods[1] == Period( id=2, start_timestamp=5800.16, end_timestamp=5800.24, attacking_direction=AttackingDirection.AWAY_HOME, ) # make sure data is loaded correctly (including flip y-axis) assert dataset.records[0].home_team_player_positions["11"] == Point( x=0.00082, y=1 - 0.48238) assert dataset.records[0].away_team_player_positions["25"] == Point( x=0.90509, y=1 - 0.47462) assert dataset.records[0].ball_position == Point(x=0.45472, y=1 - 0.38709) # make sure player data is only in the frame when the player is at the pitch assert "14" not in dataset.records[0].home_team_player_positions assert "14" in dataset.records[3].home_team_player_positions
def _parse_position(position: List[float], fidelity_version: int) -> Point: # location is cell based # [1, 120] x [1, 80] # +-----+------+ # | 1,1 | 2, 1 | # +-----+------+ # | 1,2 | 2,2 | # +-----+------+ cell_side = 0.1 if fidelity_version == 2 else 1.0 cell_relative_center = cell_side / 2 return Point(x=position[0] - cell_relative_center, y=position[1] - cell_relative_center)
def transform_point(self, point: Point, flip: bool) -> Point: # 1. always apply changes from coordinate system # 2. flip coordinates depending on orientation x_base = self._from_pitch_dimensions.x_dim.to_base(point.x) y_base = self._from_pitch_dimensions.y_dim.to_base(point.y) if flip: x_base = 1 - x_base y_base = 1 - y_base return Point(x=self._to_pitch_dimensions.x_dim.from_base(x_base), y=self._to_pitch_dimensions.y_dim.from_base(y_base))