diff --git a/kloppy/infra/serializers/tracking/tracab/tracab_dat.py b/kloppy/infra/serializers/tracking/tracab/tracab_dat.py index dcd3f07e..a878c9e3 100644 --- a/kloppy/infra/serializers/tracking/tracab/tracab_dat.py +++ b/kloppy/infra/serializers/tracking/tracab/tracab_dat.py @@ -72,6 +72,7 @@ def _frame_from_line(cls, teams, period, line, frame_rate): ) player = team.get_player_by_jersey_number(jersey_no) + if not player: player = Player( player_id=f"{team.ground}_{jersey_no}", @@ -162,8 +163,12 @@ def deserialize(self, inputs: TRACABInputs) -> TrackingDataset: meta_data = objectify.fromstring(inputs.meta_data.read()) match = meta_data.match frame_rate = int(match.attrib["iFrameRateFps"]) - pitch_size_width = float(match.attrib["fPitchXSizeMeters"]) - pitch_size_height = float(match.attrib["fPitchYSizeMeters"]) + pitch_size_width = float( + match.attrib["fPitchXSizeMeters"].replace(",", ".") + ) + pitch_size_height = float( + match.attrib["fPitchYSizeMeters"].replace(",", ".") + ) periods = [] for period in match.iterchildren(tag="period"): @@ -182,7 +187,9 @@ def deserialize(self, inputs: TRACABInputs) -> TrackingDataset: ) ) - if meta_data.get("HomeTeam") and meta_data.get("AwayTeam"): + if hasattr(meta_data, "HomeTeam") and hasattr( + meta_data, "AwayTeam" + ): home_team = self.create_team( meta_data["HomeTeam"], Ground.HOME, start_frame_id ) diff --git a/kloppy/tests/files/tracab_meta_2.xml b/kloppy/tests/files/tracab_meta_2.xml new file mode 100644 index 00000000..13f2368c --- /dev/null +++ b/kloppy/tests/files/tracab_meta_2.xml @@ -0,0 +1,16 @@ + + + + + + + + + diff --git a/kloppy/tests/files/tracab_meta_3.xml b/kloppy/tests/files/tracab_meta_3.xml new file mode 100644 index 00000000..4316a7b4 --- /dev/null +++ b/kloppy/tests/files/tracab_meta_3.xml @@ -0,0 +1,12 @@ + + + + + + diff --git a/kloppy/tests/test_tracab.py b/kloppy/tests/test_tracab.py index abbf817c..3298e2ce 100644 --- a/kloppy/tests/test_tracab.py +++ b/kloppy/tests/test_tracab.py @@ -39,6 +39,16 @@ def xml_meta_data(base_dir: Path) -> Path: return base_dir / "files" / "tracab_meta.xml" +@pytest.fixture(scope="session") +def xml_meta2_data(base_dir: Path) -> Path: + return base_dir / "files" / "tracab_meta_2.xml" + + +@pytest.fixture(scope="session") +def xml_meta3_data(base_dir: Path) -> Path: + return base_dir / "files" / "tracab_meta_3.xml" + + @pytest.fixture(scope="session") def dat_raw_data(base_dir: Path) -> Path: return base_dir / "files" / "tracab_raw.dat" @@ -223,3 +233,125 @@ def test_correct_normalized_deserialization( assert dataset.records[0].players_data[ player_home_1 ].coordinates == Point(x=1.0019047619047619, y=0.49602941176470583) + + +class TestTracabMeta2: + def test_correct_deserialization( + self, xml_meta2_data: Path, dat_raw_data: Path + ): + dataset = tracab.load( + meta_data=xml_meta2_data, + raw_data=dat_raw_data, + coordinates="tracab", + only_alive=False, + ) + + # Check metadata + assert dataset.metadata.provider == Provider.TRACAB + assert dataset.dataset_type == DatasetType.TRACKING + assert len(dataset.records) == 7 + assert len(dataset.metadata.periods) == 2 + assert dataset.metadata.orientation == Orientation.AWAY_HOME + assert dataset.metadata.periods[0].id == 1 + assert dataset.metadata.periods[0].start_timestamp == timedelta( + seconds=73940, microseconds=320000 + ) + assert dataset.metadata.periods[0].end_timestamp == timedelta( + seconds=76656, microseconds=320000 + ) + assert dataset.metadata.periods[1].id == 2 + assert dataset.metadata.periods[1].start_timestamp == timedelta( + seconds=77684, microseconds=560000 + ) + assert dataset.metadata.periods[1].end_timestamp == timedelta( + seconds=80717, microseconds=320000 + ) + + # No need to check frames, since we do that in TestTracabDATTracking + # The only difference in this test is the meta data file structure + + # make sure player data is only in the frame when the player is at the pitch + assert "home_20" in [ + player.player_id + for player in dataset.records[0].players_data.keys() + ] + assert "home_20" not in [ + player.player_id + for player in dataset.records[6].players_data.keys() + ] + + def test_correct_normalized_deserialization( + self, xml_meta2_data: Path, dat_raw_data: Path + ): + dataset = tracab.load( + meta_data=xml_meta2_data, raw_data=dat_raw_data, only_alive=False + ) + + player_home_1 = dataset.metadata.teams[0].get_player_by_jersey_number( + 1 + ) + + assert dataset.records[0].players_data[ + player_home_1 + ].coordinates == Point(x=1.0019047619047619, y=0.49602941176470583) + + +class TestTracabMeta3: + def test_correct_deserialization( + self, xml_meta3_data: Path, dat_raw_data: Path + ): + dataset = tracab.load( + meta_data=xml_meta3_data, + raw_data=dat_raw_data, + coordinates="tracab", + only_alive=False, + ) + + # Check metadata + assert dataset.metadata.provider == Provider.TRACAB + assert dataset.dataset_type == DatasetType.TRACKING + assert len(dataset.records) == 7 + assert len(dataset.metadata.periods) == 2 + assert dataset.metadata.orientation == Orientation.AWAY_HOME + assert dataset.metadata.periods[0].id == 1 + assert dataset.metadata.periods[0].start_timestamp == timedelta( + seconds=73940, microseconds=320000 + ) + assert dataset.metadata.periods[0].end_timestamp == timedelta( + seconds=76656, microseconds=320000 + ) + assert dataset.metadata.periods[1].id == 2 + assert dataset.metadata.periods[1].start_timestamp == timedelta( + seconds=77684, microseconds=560000 + ) + assert dataset.metadata.periods[1].end_timestamp == timedelta( + seconds=80717, microseconds=320000 + ) + + # No need to check frames, since we do that in TestTracabDATTracking + # The only difference in this test is the meta data file structure + + # make sure player data is only in the frame when the player is at the pitch + assert "home_20" in [ + player.player_id + for player in dataset.records[0].players_data.keys() + ] + assert "home_20" not in [ + player.player_id + for player in dataset.records[6].players_data.keys() + ] + + def test_correct_normalized_deserialization( + self, xml_meta3_data: Path, dat_raw_data: Path + ): + dataset = tracab.load( + meta_data=xml_meta3_data, raw_data=dat_raw_data, only_alive=False + ) + + player_home_1 = dataset.metadata.teams[0].get_player_by_jersey_number( + 1 + ) + + assert dataset.records[0].players_data[ + player_home_1 + ].coordinates == Point(x=1.0019047619047619, y=0.49602941176470583)