From 1a55a91f8043b9bd1d39cea3add0805d3016b295 Mon Sep 17 00:00:00 2001 From: Pieter Robberechts Date: Sat, 24 Aug 2024 18:48:16 +0200 Subject: [PATCH] wip(docs): event data model --- .../event-data/event-types/ball_out.md | 3 + docs/reference/event-data/event-types/card.md | 3 + .../reference/event-data/event-types/carry.md | 3 + .../event-data/event-types/clearance.md | 3 + docs/reference/event-data/event-types/duel.md | 3 + .../event-types/formation_change.md | 3 + .../event-data/event-types/foul_committed.md | 3 + .../event-data/event-types/generic.md | 3 + .../event-data/event-types/goalkeeper.md | 3 + .../reference/event-data/event-types/index.md | 67 +----- .../event-data/event-types/interception.md | 3 + .../event-data/event-types/miscontrol.md | 3 + docs/reference/event-data/event-types/pass.md | 7 +- .../event-data/event-types/player_off.md | 3 + .../event-data/event-types/player_on.md | 3 + .../event-data/event-types/recovery.md | 3 + docs/reference/event-data/event-types/shot.md | 2 + .../event-data/event-types/substitution.md | 3 + .../event-data/event-types/take_on.md | 3 + docs/reference/event-data/index.md | 10 + docs/reference/providers/spec.yaml | 218 ++++++++++++++++++ docs/utils/macros.py | 179 ++++++++++++++ kloppy/domain/models/event.py | 43 ++-- mkdocs.yml | 60 +++-- 24 files changed, 523 insertions(+), 111 deletions(-) create mode 100644 docs/reference/event-data/event-types/ball_out.md create mode 100644 docs/reference/event-data/event-types/card.md create mode 100644 docs/reference/event-data/event-types/carry.md create mode 100644 docs/reference/event-data/event-types/clearance.md create mode 100644 docs/reference/event-data/event-types/duel.md create mode 100644 docs/reference/event-data/event-types/formation_change.md create mode 100644 docs/reference/event-data/event-types/foul_committed.md create mode 100644 docs/reference/event-data/event-types/generic.md create mode 100644 docs/reference/event-data/event-types/goalkeeper.md create mode 100644 docs/reference/event-data/event-types/interception.md create mode 100644 docs/reference/event-data/event-types/miscontrol.md create mode 100644 docs/reference/event-data/event-types/player_off.md create mode 100644 docs/reference/event-data/event-types/player_on.md create mode 100644 docs/reference/event-data/event-types/recovery.md create mode 100644 docs/reference/event-data/event-types/shot.md create mode 100644 docs/reference/event-data/event-types/substitution.md create mode 100644 docs/reference/event-data/event-types/take_on.md create mode 100644 docs/reference/providers/spec.yaml create mode 100644 docs/utils/macros.py diff --git a/docs/reference/event-data/event-types/ball_out.md b/docs/reference/event-data/event-types/ball_out.md new file mode 100644 index 00000000..89b50875 --- /dev/null +++ b/docs/reference/event-data/event-types/ball_out.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.BallOutEvent} + +{{ render_event_type("kloppy.domain.BallOutEvent") }} diff --git a/docs/reference/event-data/event-types/card.md b/docs/reference/event-data/event-types/card.md new file mode 100644 index 00000000..319d977e --- /dev/null +++ b/docs/reference/event-data/event-types/card.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.CardEvent} + +{{ render_event_type("kloppy.domain.CardEvent") }} diff --git a/docs/reference/event-data/event-types/carry.md b/docs/reference/event-data/event-types/carry.md new file mode 100644 index 00000000..c45391df --- /dev/null +++ b/docs/reference/event-data/event-types/carry.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.CarryEvent} + +{{ render_event_type("kloppy.domain.CarryEvent") }} diff --git a/docs/reference/event-data/event-types/clearance.md b/docs/reference/event-data/event-types/clearance.md new file mode 100644 index 00000000..97d2354d --- /dev/null +++ b/docs/reference/event-data/event-types/clearance.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.ClearanceEvent} + +{{ render_event_type("kloppy.domain.ClearanceEvent") }} diff --git a/docs/reference/event-data/event-types/duel.md b/docs/reference/event-data/event-types/duel.md new file mode 100644 index 00000000..1c60fd60 --- /dev/null +++ b/docs/reference/event-data/event-types/duel.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.DuelEvent} + +{{ render_event_type("kloppy.domain.DuelEvent") }} diff --git a/docs/reference/event-data/event-types/formation_change.md b/docs/reference/event-data/event-types/formation_change.md new file mode 100644 index 00000000..c2efc6a6 --- /dev/null +++ b/docs/reference/event-data/event-types/formation_change.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.FormationChangeEvent} + +{{ render_event_type("kloppy.domain.FormationChangeEvent") }} diff --git a/docs/reference/event-data/event-types/foul_committed.md b/docs/reference/event-data/event-types/foul_committed.md new file mode 100644 index 00000000..778920ba --- /dev/null +++ b/docs/reference/event-data/event-types/foul_committed.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.FoulCommittedEvent} + +{{ render_event_type("kloppy.domain.FoulCommittedEvent") }} diff --git a/docs/reference/event-data/event-types/generic.md b/docs/reference/event-data/event-types/generic.md new file mode 100644 index 00000000..80c7378e --- /dev/null +++ b/docs/reference/event-data/event-types/generic.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.GenericEvent} + +{{ render_event_type("kloppy.domain.GenericEvent") }} diff --git a/docs/reference/event-data/event-types/goalkeeper.md b/docs/reference/event-data/event-types/goalkeeper.md new file mode 100644 index 00000000..3ab333e8 --- /dev/null +++ b/docs/reference/event-data/event-types/goalkeeper.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.GoalkeeperEvent} + +{{ render_event_type("kloppy.domain.GoalkeeperEvent") }} diff --git a/docs/reference/event-data/event-types/index.md b/docs/reference/event-data/event-types/index.md index 9e4948f8..fce3dc14 100644 --- a/docs/reference/event-data/event-types/index.md +++ b/docs/reference/event-data/event-types/index.md @@ -2,67 +2,6 @@ Each event has a type that classifies the general category to which the event belongs. This classification depends on the data provider of the original data. By default, each event in the data provider’s original data is deserialized as a GENERIC event. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
ValueValue DescriptionStatsBombOptaWyscout v2Wyscout v3DataFactorySportecMetrica (JSON)
GENERICUnrecognised event type Parsed Parsed Parsed Parsed Parsed Parsed Parsed
PASSThe attempted delivery of the ball from one player to another player on the same team. ParsedParsedParsed Parsed Parsed Parsed Parsed
+[](){#kloppy.domain.EventType} + +{{ render_event_types() }} diff --git a/docs/reference/event-data/event-types/interception.md b/docs/reference/event-data/event-types/interception.md new file mode 100644 index 00000000..52ec0757 --- /dev/null +++ b/docs/reference/event-data/event-types/interception.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.InterceptionEvent} + +{{ render_event_type("kloppy.domain.InterceptionEvent") }} diff --git a/docs/reference/event-data/event-types/miscontrol.md b/docs/reference/event-data/event-types/miscontrol.md new file mode 100644 index 00000000..c4a868d4 --- /dev/null +++ b/docs/reference/event-data/event-types/miscontrol.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.MiscontrolEvent} + +{{ render_event_type("kloppy.domain.MiscontrolEvent") }} diff --git a/docs/reference/event-data/event-types/pass.md b/docs/reference/event-data/event-types/pass.md index 21d59190..5a8aae0c 100644 --- a/docs/reference/event-data/event-types/pass.md +++ b/docs/reference/event-data/event-types/pass.md @@ -1,4 +1,5 @@ -::: kloppy.domain.PassEvent -options: -inherited_members: false +[](){#kloppy.domain.PassEvent} +{{ render_event_type("kloppy.domain.PassEvent") }} + +[](){#kloppy.domain.PassResult} diff --git a/docs/reference/event-data/event-types/player_off.md b/docs/reference/event-data/event-types/player_off.md new file mode 100644 index 00000000..a977163a --- /dev/null +++ b/docs/reference/event-data/event-types/player_off.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.PlayerOffEvent} + +{{ render_event_type("kloppy.domain.PlayerOffEvent") }} diff --git a/docs/reference/event-data/event-types/player_on.md b/docs/reference/event-data/event-types/player_on.md new file mode 100644 index 00000000..78fd55db --- /dev/null +++ b/docs/reference/event-data/event-types/player_on.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.PlayerOnEvent} + +{{ render_event_type("kloppy.domain.PlayerOnEvent") }} diff --git a/docs/reference/event-data/event-types/recovery.md b/docs/reference/event-data/event-types/recovery.md new file mode 100644 index 00000000..12447ead --- /dev/null +++ b/docs/reference/event-data/event-types/recovery.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.RecoveryEvent} + +{{ render_event_type("kloppy.domain.RecoveryEvent") }} diff --git a/docs/reference/event-data/event-types/shot.md b/docs/reference/event-data/event-types/shot.md new file mode 100644 index 00000000..7685ea9f --- /dev/null +++ b/docs/reference/event-data/event-types/shot.md @@ -0,0 +1,2 @@ +[](){#kloppy.domain.ShotEvent} +{{ render_event_type("kloppy.domain.ShotEvent") }} diff --git a/docs/reference/event-data/event-types/substitution.md b/docs/reference/event-data/event-types/substitution.md new file mode 100644 index 00000000..a489dca9 --- /dev/null +++ b/docs/reference/event-data/event-types/substitution.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.SubstitutionEvent} + +{{ render_event_type("kloppy.domain.SubstitutionEvent") }} diff --git a/docs/reference/event-data/event-types/take_on.md b/docs/reference/event-data/event-types/take_on.md new file mode 100644 index 00000000..f97f2150 --- /dev/null +++ b/docs/reference/event-data/event-types/take_on.md @@ -0,0 +1,3 @@ +[](){#kloppy.domain.TakeOnEvent} + +{{ render_event_type("kloppy.domain.TakeOnEvent") }} diff --git a/docs/reference/event-data/index.md b/docs/reference/event-data/index.md index a55d6c95..699760f6 100644 --- a/docs/reference/event-data/index.md +++ b/docs/reference/event-data/index.md @@ -1,7 +1,17 @@ # Event Data +## Event + ::: kloppy.domain.Event options: show_bases: false inherited_members: false show_source: false + +## Event Qualifier + +::: kloppy.domain.Qualifier + options: + show_bases: false + inherited_members: false + show_source: false diff --git a/docs/reference/providers/spec.yaml b/docs/reference/providers/spec.yaml new file mode 100644 index 00000000..37d9adc0 --- /dev/null +++ b/docs/reference/providers/spec.yaml @@ -0,0 +1,218 @@ +event_types: + kloppy.domain.GenericEvent: + providers: + statsbomb: + status: parsed + statsperform: + status: parsed + wyscout_v2: + status: parsed + wyscout_v3: + status: parsed + datafactory: + status: parsed + sportec: + status: parsed + metrica_json: + status: parsed + kloppy.domain.PassEvent: + providers: + statsbomb: + status: parsed + implementation: event type 30/"Pass" + statsperform: + status: parsed + implementation: event type 1/”Pass” or 2/”Offside pass” + wyscout_v2: + status: parsed + implementation: "event type 8/”Pass” or subtype 30/”Corner”, 31/”Free kick”, 32/”Free kick (cross)”, 34/”Goal kick”, 36/”Throw in” " + attributes: + receive_timestamp: + providers: + statsbomb: + status: parsed + implementation: null + receiver_coordinates: + statsbomb: + status: parsed + implementation: null + receiver_player: + statsbomb: + status: parsed + implementation: null + kloppy.domain.ShotEvent: + providers: + statsbomb: + status: parsed + implementation: event type 16/"Shot" or 20/"Own goal against" + statsperform: + status: parsed + implementation: event type 13/”Shot (miss)” or 14/”Shot (post)” or 15/”Shot (saved)” or 16/”Shot (goal)” + wyscout_v2: + status: parsed + implementation: event type 10/”Shot” or subtype 33/”Free kick (shot)”, 35/”Penalty” + kloppy.domain.TakeOnEvent: + providers: + statsbomb: + status: parsed + implementation: event type 14/”Dribble” + statsperform: + status: parsed + implementation: event type 3/”Take on” + wyscout_v2: + status: not implemented + implementation: null + kloppy.domain.CarryEvent: + providers: + statsbomb: + status: parsed + implementation: event type 43/”Carry” + statsperform: + status: not supported + implementation: null + wyscout_v2: + status: unknown + implementation: null + kloppy.domain.ClearanceEvent: + providers: + statsbomb: + status: parsed + implementation: "event type 9/”Clearance” or a keeper sweeper clearance event (23/”Goalkeeper” event with type 27/”Keeper sweeper” and outcome 48/”Clear”) in which the goalkeeper uses their head or feet" + statsperform: + status: parsed + implementation: event type 12/”Clearance” + wyscout_v2: + status: parsed + implementation: subevent type 71/”Clearance” + kloppy.domain.InterceptionEvent: + providers: + statsbomb: + status: parsed + implementation: event type 10/” Interception” or event type 30/”Pass” with type 64/”One touch interception” + statsperform: + status: parsed + implementation: event type 8/”Interception” or 74/”Blocked pass” + wyscout_v2: + status: parsed + implementation: null + kloppy.domain.DuelEvent: + providers: + statsbomb: + status: parsed + implementation: event type 4/”Duel” or 33/”Fifty-Fifty” or events with attribute “aerial_won” + statsperform: + status: parsed + implementation: event type 7/”Tackle” or 44/”Aerial” or 67/”Fifty-fifty” + wyscout_v2: + status: parsed + implementation: event type 1/”Duel” + kloppy.domain.SubstitutionEvent: + providers: + statsbomb: + status: parsed + implementation: event type 19/”Substition” + statsperform: + status: not implemented + implementation: event type 18/”Player off” and 19/”Player on” + wyscout_v2: + status: not implemented + implementation: null + kloppy.domain.CardEvent: + providers: + statsbomb: + status: parsed + implementation: event type 24/”Bad behaviour” or 22/”Foul committed” + statsperform: + status: parsed + implementation: event type 17/”Card” + wyscout_v2: + status: parsed + implementation: event type 2/”Foul” with tag 1701, 1702 or 1703 + kloppy.domain.PlayerOnEvent: + providers: + statsbomb: + status: parsed + implementation: event type 26/”Player On” + statsperform: + status: not implemented + implementation: event type 21/”Player returns” + wyscout_v2: + status: not implemented + implementation: + kloppy.domain.PlayerOffEvent: + providers: + statsbomb: + status: parsed + implementation: event type 27/”Player Off” + statsperform: + status: not implemented + implementation: event type 20/”Player retired” + wyscout_v2: + status: not implemented + implementation: + kloppy.domain.RecoveryEvent: + providers: + statsbomb: + status: parsed + implementation: "event type 2/”Ball Recovery” or a keeper sweeper claim event (23/”Goalkeeper” event with with type 27/”Keeper sweeper” and outcome 47/”Claim”) in which the goalkeeper does not use their hands " + statsperform: + status: parsed + implementation: event type 49/”Recovery” + wyscout_v2: + status: parsed + implementation: subevent 70/”Acceleration” or 72/”Touch” without tag 1302 + kloppy.domain.MiscontrolEvent: + providers: + statsbomb: + status: parsed + implementation: event type 38/”Miscontrol” + statsperform: + status: parsed + implementation: event type 61/”Ball touch” with outcome 0. + wyscout_v2: + status: parsed + implementation: subevent 72/”Touch” with tag 1302 + kloppy.domain.BallOutEvent: + providers: + statsbomb: + status: parsed + implementation: "events with attribute “out” or StatsBomb event type 30/”Pass”, 16/”Shot”, 10/” Interception”, 4/”Duel” or 23/”Goalkeeper” with an outcome corresponding to ball going out " + statsperform: + status: parsed + implementation: even type 5/”Ball out” or 6/”Corner awarded” + wyscout_v2: + status: parsed + implementation: event type 5/”Interruption” + kloppy.domain.FoulCommittedEvent: + providers: + statsbomb: + status: parsed + implementation: event type 22/”Foul committed” + statsperform: + status: parsed + implementation: event type 4/”Foul committed” with outcome 0 + wyscout_v2: + status: parsed + implementation: event type 2/”Foul” + kloppy.domain.GoalkeeperEvent: + providers: + statsbomb: + status: parsed + implementation: "event type 23/”Goalkeeper”. Some goalkeeper events are parsed as a clearance and recovery. See CLEARANCE and RECOVERY for details. " + statsperform: + status: parsed + implementation: event type 10/”Save” or 11/”Claim” or 41/”Punch” or 52/”Keeper pick-up” or 54/”Smother” + wyscout_v2: + status: parsed + implementation: event type 9/”Save” + kloppy.domain.FormationChangeEvent: + providers: + statsbomb: + status: parsed + implementation: event type 36/”Tactical Shift” + statsperform: + status: parsed + implementation: event type 40/”Formation change” + wyscout_v2: + status: not implemented + implementation: null diff --git a/docs/utils/macros.py b/docs/utils/macros.py new file mode 100644 index 00000000..d19e67e5 --- /dev/null +++ b/docs/utils/macros.py @@ -0,0 +1,179 @@ +""" +Mkdocs-macros module +""" + +import yaml +import griffe +import pandas as pd +import re +from griffe import Docstring + +kloppy = griffe.load("kloppy", resolve_aliases=True) + +_EVENT_DATA_PROVIDERS = { + "statsbomb": "StatsBomb", + "statsperform": "Stats Perform", + "wyscout_v2": "Wyscout (v2)", + "wyscout_v3": "Wyscout (v3)", + "datafactory": "DataFactory", + "sportec": "Sportec", + "metrica_json": "Metrica (JSON)", +} + + +def replace_unescaped_pipes(text: str) -> str: + """ + Replace unescaped pipes. + + For regex explanation, see https://regex101.com/r/s8H588/1 + + Args: + text (str): input string + + Returns: + str: output string + """ + return re.sub(r"(? str: + """ + Convert dataframe to markdown table using tabulate. + """ + # Escape any pipe characters, | to \| + # See https://github.com/astanin/python-tabulate/issues/241 + df.columns = [ + replace_unescaped_pipes(c) if isinstance(c, str) else c for c in df.columns + ] + + # Avoid deprecated applymap warning on pandas>=2.0 + # See https://github.com/timvink/mkdocs-table-reader-plugin/issues/55 + if pd.__version__ >= "2.1.0": + df = df.map(lambda s: replace_unescaped_pipes(s) if isinstance(s, str) else s) + else: + df = df.applymap( + lambda s: replace_unescaped_pipes(s) if isinstance(s, str) else s + ) + + if "index" not in markdown_kwargs: + markdown_kwargs["index"] = False + if "tablefmt" not in markdown_kwargs: + markdown_kwargs["tablefmt"] = "pipe" + + return df.to_markdown(**markdown_kwargs) + + +def define_env(env): + """ + This is the hook for defining variables, macros and filters + + - variables: the dictionary that contains the environment variables + - macro: a decorator function, to declare a macro. + - filter: a function with one of more arguments, + used to perform a transformation + """ + + @env.macro + def render_event_types(): + with open("docs/reference/providers/spec.yaml", "r") as file: + spec = yaml.safe_load(file) + + columns = ["Type"] + data = [] + + for provider_key, provider_name in _EVENT_DATA_PROVIDERS.items(): + columns += [provider_name] + + for event_type, event_type_spec in spec["event_types"].items(): + event_name = eval( + kloppy[event_type.replace("kloppy.", "")].members["event_name"].value + ) + row = [f"[{event_name}][{event_type}]"] + for provider_key, provider_name in _EVENT_DATA_PROVIDERS.items(): + if provider_key in event_type_spec["providers"]: + status = event_type_spec["providers"][provider_key].get( + "status", "unknown" + ) + implementation = event_type_spec["providers"][provider_key].get( + "implementation", "unknown" + ) + if status == "parsed": + row += [f':material-check:{{ title="{implementation}" }}'] + elif status == "not implemented": + row += [':material-progress-helper:{ title="not implemented" }'] + elif status == "not supported": + row += [':material-close:{ title="not supported" }'] + else: + row += [':material-progress-question:{ title="Status unkown" }'] + data += [row] + + table = convert_to_md_table( + pd.DataFrame(data, columns=columns), {"index": False} + ) + + return f""" +

Event types:

+{table} +""" + + @env.macro + def render_event_type(x): + with open("docs/reference/providers/spec.yaml", "r") as file: + spec = yaml.safe_load(file) + + class_spec = kloppy[x.replace("kloppy.", "")] + docstring = Docstring(class_spec.docstring.value, lineno=1).parse("google") + + attr_docstrings = next( + (d.value for d in docstring if d.kind.name == "attributes"), list() + ) + + columns = ["Name", "Type", "Description"] + data = [] + + for key, name in _EVENT_DATA_PROVIDERS.items(): + columns += [name] + + for attr in attr_docstrings: + row = [attr.name, attr.annotation, attr.description] + if attr.name in spec["event_types"][x].get("attributes", {}): + attr_spec = spec["event_types"][x]["attributes"][attr.name].get( + "providers", {} + ) + for provider_key, provider_name in _EVENT_DATA_PROVIDERS.items(): + if provider_key in attr_spec: + status = attr_spec[provider_key].get("status", "unknown") + implementation = attr_spec[provider_key].get( + "implementation", "unknown" + ) + if status == "parsed": + row += [f':material-check:{{ title="{implementation}" }}'] + elif status == "not implemented": + row += [ + ':material-progress-helper:{ title="not implemented" }' + ] + elif status == "not supported": + row += [':material-close:{ title="not supported" }'] + else: + row += [':material-progress-question:{ title="Status unkown" }'] + else: + for provider_key, provider_name in _EVENT_DATA_PROVIDERS.items(): + row += ["-"] + data += [row] + + anchor = f'' # FIXME: this does not work + + description = docstring[0].value + + table = convert_to_md_table( + pd.DataFrame(data, columns=columns), {"index": False} + ) + + return f""" +{anchor} + +{description} + +

Attributes:

+{table} +""" diff --git a/kloppy/domain/models/event.py b/kloppy/domain/models/event.py index c150b9a4..b0aa7d75 100644 --- a/kloppy/domain/models/event.py +++ b/kloppy/domain/models/event.py @@ -261,9 +261,7 @@ def to_dict(self): @property def name(self): - return camelcase_to_snakecase( - removes_suffix(type(self).__name__, "Qualifier") - ) + return camelcase_to_snakecase(removes_suffix(type(self).__name__, "Qualifier")) @dataclass @@ -606,12 +604,8 @@ def get_related_events(self) -> List["Event"]: for event_id in self.related_event_ids ] - def get_related_event( - self, type_: Union[str, EventType] - ) -> Optional["Event"]: - event_type = ( - EventType[type_.upper()] if isinstance(type_, str) else type_ - ) + def get_related_event(self, type_: Union[str, EventType]) -> Optional["Event"]: + event_type = EventType[type_.upper()] if isinstance(type_, str) else type_ for related_event in self.get_related_events(): if related_event.event_type == event_type: return related_event @@ -675,9 +669,7 @@ def matches(self, filter_) -> bool: event_type = parts[0] result = None else: - raise InvalidFilterError( - f"Don't know how to apply filter {filter_}" - ) + raise InvalidFilterError(f"Don't know how to apply filter {filter_}") if event_type: try: @@ -724,8 +716,9 @@ def __repr__(self): @dataclass(repr=False) @docstring_inherit_attributes(Event) class GenericEvent(Event): - """ - GenericEvent + """GenericEvent + + Unrecognised event type. Attributes: event_type (EventType): `EventType.GENERIC` (See [`EventType`][kloppy.domain.models.event.EventType]) @@ -739,8 +732,9 @@ class GenericEvent(Event): @dataclass(repr=False) @docstring_inherit_attributes(Event) class ShotEvent(Event): - """ - ShotEvent + """ShotEvent + + An attempt to score a goal. Attributes: event_type (EventType): `EventType.SHOT` (See [`EventType`][kloppy.domain.models.event.EventType]) @@ -759,8 +753,9 @@ class ShotEvent(Event): @dataclass(repr=False) @docstring_inherit_attributes(Event) class PassEvent(Event): - """ - PassEvent + """PassEvent + + The attempted delivery of the ball from one player to another player on the same team. Attributes: event_type (EventType): `EventType.PASS` (See [`EventType`][kloppy.domain.models.event.EventType]) @@ -1105,15 +1100,11 @@ def add_state(self, *builder_keys): return add_state(self, *builder_keys) - @deprecated( - "to_pandas will be removed in the future. Please use to_df instead." - ) + @deprecated("to_pandas will be removed in the future. Please use to_df instead.") def to_pandas( self, record_converter: Callable[[Event], Dict] = None, - additional_columns: Dict[ - str, Union[Callable[[Event], Any], Any] - ] = None, + additional_columns: Dict[str, Union[Callable[[Event], Any], Any]] = None, ) -> "DataFrame": try: import pandas as pd @@ -1141,9 +1132,7 @@ def generic_record_converter(event: Event): row.update({k: value}) return row - return pd.DataFrame.from_records( - map(generic_record_converter, self.records) - ) + return pd.DataFrame.from_records(map(generic_record_converter, self.records)) def aggregate(self, type_: str, **aggregator_kwargs) -> List[Any]: if type_ == "minutes_played": diff --git a/mkdocs.yml b/mkdocs.yml index 336aa88c..2699b95d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -50,9 +50,9 @@ nav: - Pitch dimensions: user-guide/transformations/dimensions.md - Orientation: user-guide/transformations/orientation.md - Processing data: - - Event data: user-guide/event-data.md - - Tracking data: user-guide/tracking-data.md - - Code data: user-guide/code-data.md + - Event data: user-guide/event-data.md + - Tracking data: user-guide/tracking-data.md + - Code data: user-guide/code-data.md - Dataframe ouput: user-guide/dataframe/index.md - Configuration: user-guide/configuration.md - How-to guides: @@ -66,14 +66,14 @@ nav: - EventDataset: reference/domain/event-dataset.md - TrackingDataset: reference/domain/tracking-dataset.md - CodeDataset: reference/domain/code-dataset.md - - Metadata: + - Metadata: - reference/domain/metadata/index.md - - Team: - - reference/domain/metadata/team/index.md - - FormationType: reference/domain/metadata/team/formation-type.md - - Player: - - reference/domain/metadata/team/player/index.md - - Position: reference/domain/metadata/team/player/position.md + - Team: + - reference/domain/metadata/team/index.md + - FormationType: reference/domain/metadata/team/formation-type.md + - Player: + - reference/domain/metadata/team/player/index.md + - Position: reference/domain/metadata/team/player/position.md - Ground: reference/domain/ground.md - Score: reference/domain/score.md - Provider: reference/domain/provider.md @@ -90,13 +90,30 @@ nav: - TRACAB: reference/providers/tracab.md - Wyscout: reference/providers/wyscout.md - Event Data Model: - - reference/event-data/index.md - - Event Types: - - Oveview: reference/event-data/event-types/index.md - - Pass: reference/event-data/event-types/pass.md - - Qualifiers: - - Overview: reference/event-data/qualifiers/index.md - - SetPieceQualifier: references/event-data/qualifiers/set-piece.md + - reference/event-data/index.md + - Event Types: + - Overview: reference/event-data/event-types/index.md + - Generic: reference/event-data/event-types/generic.md + - Pass: reference/event-data/event-types/pass.md + - Shot: reference/event-data/event-types/shot.md + - Take on: reference/event-data/event-types/take_on.md + - Carry: reference/event-data/event-types/carry.md + - Clearance: reference/event-data/event-types/clearance.md + - Interception: reference/event-data/event-types/interception.md + - Duel: reference/event-data/event-types/duel.md + - Substitution: reference/event-data/event-types/substitution.md + - Card: reference/event-data/event-types/card.md + - Player on: reference/event-data/event-types/player_on.md + - Player off: reference/event-data/event-types/player_off.md + - Recovery: reference/event-data/event-types/recovery.md + - Miscontrol: reference/event-data/event-types/miscontrol.md + - Ball out: reference/event-data/event-types/ball_out.md + - Foul committed: reference/event-data/event-types/foul_committed.md + - Goalkeeper: reference/event-data/event-types/goalkeeper.md + - Formation change: reference/event-data/event-types/formation_change.md + - Qualifiers: + - Overview: reference/event-data/qualifiers/index.md + - SetPieceQualifier: references/event-data/qualifiers/set-piece.md - Development: - Issues: 'issues.md' - Contributing: 'contributing.md' @@ -109,6 +126,11 @@ plugins: include: ["*.ipynb"] include_source: True - search + - autorefs + - macros: + module_name: docs/utils/macros + j2_comment_start_string: '$#' + j2_comment_end_string: '#$' - mkdocstrings: handlers: python: @@ -123,6 +145,10 @@ plugins: - presentations/* markdown_extensions: - admonition + - attr_list + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg - pymdownx.details - pymdownx.highlight: use_pygments: true