impectPy 2.4.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2023 impectPy authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,424 @@
1
+ Metadata-Version: 2.1
2
+ Name: impectPy
3
+ Version: 2.4.4
4
+ Summary: A Python package to facilitate interaction with the Impect customer API
5
+ Home-page: https://github.com/ImpectAPI/impectPy
6
+ Author: Impect
7
+ Author-email: info@impect.com
8
+ License: MIT
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE.md
11
+ Requires-Dist: requests>=2.24.0
12
+ Requires-Dist: pandas>=2.0.0
13
+ Requires-Dist: numpy<2.0,>=1.24.2
14
+
15
+ # impectPy <picture><source media="(prefers-color-scheme: dark)" srcset="https://github.com/ImpectAPI/logos/blob/main/impectPy_white.svg"><source media="(prefers-color-scheme: light)" srcset="https://github.com/ImpectAPI/logos/blob/main/impectPy_black.svg"><img alt="ImpectPy Logo" src="https://github.com/ImpectAPI/logos/blob/main/impectPy_black.svg" align="right" height="40"></picture>
16
+
17
+ A package provided by: Impect GmbH
18
+
19
+ Version: v2.4.4
20
+
21
+ **Updated: June 5th 2025**
22
+
23
+ ---
24
+
25
+ **Supported API Version: V5**
26
+ For older versions, please see list below:
27
+
28
+ - API V4: https://github.com/ImpectAPI/impectPy/tree/v1.0.3
29
+ - API V3: not supported by this package
30
+
31
+ ---
32
+
33
+ ## Introduction
34
+
35
+ The goal of the impectPy package is to provide an easy way for Impect
36
+ Customers to access data from the customer API. This API includes basic
37
+ information about competitions, competition iterations, and matches as
38
+ well as event data and aggregated scorings per player and position on
39
+ match and season level.
40
+
41
+ ## Installation
42
+
43
+ You can install the latest version of impectPy from
44
+ [GitHub](https://github.com/) with:
45
+
46
+ ``` cmd
47
+ pip install git+https://github.com/ImpectAPI/impectPy.git@v2.4.4
48
+ ```
49
+
50
+ ## Usage
51
+
52
+ ### Getting started
53
+
54
+ Before accessing any data via our API, you will need to request a bearer
55
+ token for authorization. You can get this authorization token using the
56
+ following code snippet:
57
+
58
+ ``` python
59
+ import impectPy as ip
60
+ import pandas as pd
61
+
62
+ # define login credentials
63
+ username = "yourUsername"
64
+ password = "yourPassword"
65
+
66
+ # get access token
67
+ token = ip.getAccessToken(username=username, password=password)
68
+ ```
69
+
70
+ This access token is a requirement to use any of the functions that
71
+ requests data from the API. We recommend to first get a list of
72
+ competition iterations that are enabled for your account.
73
+
74
+ ### Retrieve Basic Information
75
+
76
+ ``` python
77
+ # get list of iterations
78
+ iterations = ip.getIterations(token=token)
79
+
80
+ # print iterations to console
81
+ iterations
82
+ ```
83
+
84
+ If any iteration you were expected to see is not listed, please contact
85
+ your sales representative. Now let’s assume you are interested in data
86
+ for 2022/23 season of the 1. Bundesliga (iteration = 518). The following
87
+ snippet gets you a list of matches for this iteration:
88
+
89
+ ``` python
90
+ # get matches for iteration
91
+ matchplan = ip.getMatches(iteration=518, token=token)
92
+
93
+ # print matches to console
94
+ matchplan
95
+ ```
96
+
97
+ The column `available` denotes whether a given match has been tagged by Impect
98
+ and the data is available to you.
99
+
100
+ ### Retrieve Match Level Data
101
+
102
+ Let's assume you are interested in the FC Bayern München vs Borussia Dortmund game
103
+ from April 1st 2023 (matchId = 84344) and want to retrieve event level data as well
104
+ as team formation, starting position and substitution data. As the functions allows
105
+ for multiple games to be requested at once, we need to wrap the matchId into a list.
106
+ Hence, to request data for this game, run the following code snippet:
107
+
108
+ ``` python
109
+ # define matches to get event data for
110
+ matches = [84344]
111
+
112
+ # get event data for matches
113
+ events = ip.getEvents(
114
+ matches=matches,
115
+ token=token,
116
+ include_kpis=True,
117
+ include_set_pieces=True
118
+ )
119
+
120
+ # get match info
121
+ formations = ip.getFormations(matches, token)
122
+ substitutions = ip.getSubstitutions(matches, token)
123
+ starting_positions = ip.getStartingPositions(matches, token)
124
+
125
+ # print first few rows from events dataframe to console
126
+ events.head()
127
+ ```
128
+
129
+ You can access the aggregated scores per player and position or per
130
+ squad for this match in a similar way. You can also find more detailed data
131
+ around set piece situations within our API.
132
+ Also, we provide you with IMPECT scores and ratios that you might know from our
133
+ Scouting and Analysis portals. On player level, these are calculated across
134
+ positions which is why you have to supply the function with a list of positions
135
+ your want to retrieve data for:
136
+
137
+ ``` python
138
+ # define matches to get further data for
139
+ matches = [84344]
140
+
141
+ # get set piece data including KPI aggregates
142
+ setPieces = ip.getSetPieces(matches=matches, token=token)
143
+
144
+ # get kpi matchsums for match per player and position
145
+ playerMatchsums = ip.getPlayerMatchsums(matches=matches, token=token)
146
+
147
+ # get kpi matchsums for match per squad
148
+ squadMatchsums = ip.getSquadMatchsums(matches=matches, token=token)
149
+
150
+ # define positions to get scores aggregated by
151
+ positions = ["LEFT_WINGBACK_DEFENDER", "RIGHT_WINGBACK_DEFENDER"]
152
+
153
+ # get player scores and ratios for match and positions per player
154
+ playerMatchScores = ip.getPlayerMatchScores(
155
+ matches=matches,
156
+ positions=positions,
157
+ token=token
158
+ )
159
+
160
+ # get squad scores and ratios for match per squad
161
+ squadMatchScores = ip.getSquadMatchScores(matches=matches, token=token)
162
+ ```
163
+
164
+ In case you wish to retrieve data for multiple matches, we suggest using
165
+ the following method to do so in order to minimize the amount of
166
+ requests sent to the API. Let’s also get the event data for the RB
167
+ Leipzig vs FSV Mainz 05 game (matchId = 84350) from the same day:
168
+
169
+ ``` python
170
+ # define list of matches
171
+ matches = [84344, 84350]
172
+
173
+ # apply getEvents function to a set of matchIds
174
+ events = ip.getEvents(
175
+ matches=matches,
176
+ token=token,
177
+ include_kpis=True,
178
+ include_set_pieces=True
179
+ )
180
+
181
+ # get set piece data including KPI aggregates
182
+ setPieces = ip.getSetPieces(matches=matches, token=token)
183
+
184
+ # get matchsums for matches per player and position
185
+ playerMatchsums = ip.getPlayerMatchsums(matches=matches, token=token)
186
+
187
+ # get matchsums for matches per squad
188
+ squadMatchsums = ip.getSquadMatchsums(matches=matches, token=token)
189
+
190
+ # define positions to get scores aggregated by
191
+ positions = ["LEFT_WINGBACK_DEFENDER", "RIGHT_WINGBACK_DEFENDER"]
192
+
193
+ # get player scores and ratios for match and positions per player
194
+ playerMatchScores = ip.getPlayerMatchScores(
195
+ matches=matches,
196
+ positions=positions,
197
+ token=token
198
+ )
199
+
200
+ # get squad scores and ratios for match per squad
201
+ squadMatchScores = ip.getSquadMatchScores(matches=matches, token=token)
202
+ ```
203
+
204
+ ### Retrieve Iteration Level Data
205
+
206
+ Starting from API version V5, we also offer an endpoint to get KPI average values
207
+ per iteration on player as well as squad level. These averages are calculated by
208
+ dividing the kpi sum of all individual matches by the sum of matchShares the player
209
+ accumulated at a given position. On a team level we divide the score by the
210
+ amount of matches played by the team.
211
+ Also, we provide you with IMPECT scores and ratios that you might know from our
212
+ Scouting and Analysis portals. On player level, these are calculated across
213
+ positions which is why you have to supply the function with a list of positions
214
+ your want to retrieve data for.
215
+ Let's assume you were interested in wing backs in the 2022/2023 Bundesliga season,
216
+ then you could use this code snippet:
217
+
218
+ ``` python
219
+ # define iteration ID
220
+ iteration = 518
221
+
222
+ # define positions to get scores aggregated by
223
+ positions = ["LEFT_WINGBACK_DEFENDER", "RIGHT_WINGBACK_DEFENDER"]
224
+
225
+ # get player kpi averages for iteration
226
+ playerIterationAverages = ip.getPlayerIterationAverages(
227
+ iteration=iteration,
228
+ token=token
229
+ )
230
+
231
+ # get squad kpi averages for iteration
232
+ squadIterationAverages = ip.getSquadIterationAverages(
233
+ iteration=iteration,
234
+ token=token
235
+ )
236
+
237
+ # get player scores and ratios for iteration and positions
238
+ playerIterationScores = ip.getPlayerIterationScores(
239
+ iteration=iteration,
240
+ positions=positions,
241
+ token=token
242
+ )
243
+
244
+ # get squad scores and ratios for iteration
245
+ squadIterationScores = ip.getSquadIterationScores(
246
+ iteration=iteration,
247
+ token=token
248
+ )
249
+
250
+ # get squad rating for iteration
251
+ squadRatings = ip.getSquadRatings(iteration=iteration, token=token
252
+ ```
253
+
254
+ You can now also retrieve the positional profile scores for players via our API. This
255
+ includes profiles that you created through the scouting portal. The function requires a
256
+ positional input that determines which matchShares to consider when computing the scores.
257
+ In the below example, all matchShares that a player played as either a left back or a right
258
+ back are included for profile score calculation.
259
+
260
+ ``` python
261
+ # define iteration ID
262
+ iteration = 518
263
+
264
+ # define positions to get scores aggregated by
265
+ positions = ["LEFT_WINGBACK_DEFENDER", "RIGHT_WINGBACK_DEFENDER"]
266
+
267
+ # get player profile scores
268
+ playerProfileScores = getPlayerProfileScores(iteration, positions, token)
269
+ ```
270
+
271
+ Please keep in mind that Impect enforces a rate limit of 10 requests per second
272
+ per user. A token bucket logic has been implemented to restrict the amount of API
273
+ calls made on the client side already. The rate limit is read from the first limit
274
+ policy sent back by the API, so if this limit increases over time, this package will
275
+ act accordingly.
276
+
277
+ ### SportsCodeXML
278
+
279
+ It is also possible to convert a dataframe containing event data into an XML file,
280
+ that can be imported into Videotools such as FOCUS. The XML can be customized to a certain
281
+ degree using the following in put variables:
282
+ * `codeTag`: Customize code tag selection (Choose what goes into the `code` tag)
283
+ * `lables`: Customize labels included (provide a list of labels to be included)
284
+ * `kpis`: Customize KPIs included (provide a list of KPIs to be included)
285
+ * `labelSorting`: Enable/Disable label sorting (Labels and KPIs are usually prefixed with a sorting number (e.g. `01 | `) or the word `KPI: ` to enable easier filtering in your video tool.)
286
+ * `sequencing`: Disable sequencing (A sequence of `RECEPTION > DRIBBLE > PASS` is split into 3 instances: `RECEPTION`, `DRIBBLE`, `PASS`)
287
+ * `buckets`: Disable Label/KPI buckets (e.g. conversion from value `0.1` to bucket `[0,1[`)
288
+
289
+ To see a full list of available codeTags, labels, KPIs and allowed combinations of these,
290
+ please see the beginning of the [function definition](https://github.com/ImpectAPI/impectPy/blob/release/impectPy/xml.py).
291
+
292
+ Please make sure to only retrieve event data for
293
+ one game at a time. Let's use the Bayern vs Dortmund game from earlier as an example:
294
+
295
+ ``` python
296
+ # define matchId
297
+ matches = [84344]
298
+
299
+ # get event data for matchId
300
+ events = ip.getEvents(matches=matches, token=token)
301
+
302
+ # define lead and lag time in seconds
303
+ lead = 3
304
+ lag = 3
305
+
306
+ # define period start offsets from video start in seconds
307
+ p1Start = 16 # first half kickoff happens after 16 seconds in your video file
308
+ p2Start = 48 * 60 + 53 # first half kickoff happens after 48 minutes and 53 seconds in your video file
309
+ p3Start = 0 # set to timestamp of the kickoff of the first half of extra time
310
+ p4Start = 0 # set to timestamp of the kickoff of the second half of extra time
311
+ p5Start = 0 # set to timestamp of the first penalty of the penalty shootout
312
+
313
+ # generate xml
314
+ xml_tree = ip.generateXML(
315
+ events=events,
316
+ lead=lead,
317
+ lag=lag,
318
+ p1Start=p1Start,
319
+ p2Start=p2Start,
320
+ p3Start=p3Start,
321
+ p4Start=p4Start,
322
+ p5Start=p5Start,
323
+ codeTag="playerName", # Use the playerName for the Code Tag
324
+ labels=["action", "opponents"], # defaults to None to inlcude all available labels
325
+ kpis=["BYPASSED_OPPONENTS", "BYPASSED_DEFENDERS"], # defaults to None to inlcude all available KPIs
326
+ labelSorting=False, # Disable sorting prefixes
327
+ sequencing=False, # Disable merging of consecutive events by the same player into one sequence
328
+ buckets=False # Use precise KPI and label values instead of predefined buckets
329
+ )
330
+
331
+ # write to xml file
332
+ with open(f"match{matches[0]}_"
333
+ # add home team name
334
+ f"{events.homeSquadName.unique().tolist()[0].replace(' ', '_')}"
335
+ f"_vs_"
336
+ # add away team name
337
+ f"{events.awaySquadName.unique().tolist()[0].replace(' ', '_')}"
338
+ f".xml",
339
+ "wb") as file:
340
+ xml_tree.write(file,
341
+ xml_declaration=True,
342
+ encoding='utf-8',
343
+ method="xml")
344
+ ```
345
+
346
+ ## Object-Oriented Package Version
347
+
348
+ Since version 2.4.0, there is another way to call the familiar functions in a more object-oriented way.
349
+ An object of the class "Impect" can be used to query the API. This new object offers a slightly enhanced
350
+ performance and stores your token as an object attribute. This means you no longer have to include it in
351
+ every function call. This new IMPECT object can be used as shown in the example below:
352
+
353
+ ```python
354
+ from impectPy import Impect
355
+
356
+ # define login credentials
357
+ username = "yourUsername"
358
+ password = "yourPassword"
359
+
360
+ # create Impect instance and login
361
+ api = Impect()
362
+ api.login(username, password)
363
+
364
+ # define iteration ID
365
+ iteration = 518
366
+
367
+ # define matchId
368
+ matches = [84344]
369
+
370
+ # define positions to get scores/profiles aggregated by
371
+ positions = ["LEFT_WINGBACK_DEFENDER", "RIGHT_WINGBACK_DEFENDER"]
372
+
373
+ # get iterations
374
+ iterations = api.getIterations()
375
+
376
+ # get squad ratings
377
+ ratings = api.getSquadRatings(iteration)
378
+
379
+ # get matches
380
+ matchplan = api.getMatches(iteration)
381
+
382
+ # get match info
383
+ formations = api.getFormations(matches)
384
+ substitutions = api.getSubstitutions(matches)
385
+ startingPositions = api.getStartingPositions(matches)
386
+
387
+ # get match events
388
+ events = api.getEvents(matches, include_kpis=True, include_set_pieces=True)
389
+
390
+ # get set pieces
391
+ setPieces = api.getSetPieces(matches)
392
+
393
+ # get player iteration averages
394
+ playerIterationAverages = api.getPlayerIterationAverages(iteration)
395
+
396
+ # get player matchsums
397
+ playerMatchsums = api.getPlayerMatchsums(matches)
398
+
399
+ # get squad iteration averages
400
+ squadIterationAverages = api.getSquadIterationAverages(iteration)
401
+
402
+ # get squad matchsums
403
+ squadMatchsums = api.getSquadMatchsums(matches)
404
+
405
+ # get player match scores
406
+ playerMatchScores = api.getPlayerMatchScores(matches, positions)
407
+
408
+ # get squad match scores
409
+ squadMatchScores = api.getSquadMatchScores(matches)
410
+
411
+ # get player iteration scores
412
+ playerIterationScores = api.getPlayerIterationScores(iteration, positions)
413
+
414
+ # get squad iteration scores
415
+ squadIterationScores = api.getSquadIterationScores(iteration)
416
+
417
+ # get player profile scores
418
+ playerProfileScores = api.getPlayerProfileScores(iteration, positions)
419
+ ```
420
+
421
+ ## Final Notes
422
+
423
+ Further documentation on the data and explanations of variables can be
424
+ found in our [glossary](https://glossary.impect.com/).