-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathdata.py
337 lines (306 loc) · 10.3 KB
/
data.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
from dataclasses import dataclass, field, InitVar
from typing import List, Union, Dict, Any, Optional
@dataclass(repr=False)
class PitchBreak:
"""
A class to hold pitch pitch break data
Attributes
----------
breakangle : float
Degrees clockwise (batter's view) that the plane of
the pitch deviates from the vertical
breaklength : float
Max distance that the pitch separates from the straight
line between pitch start and pitch end
breaky : int
Distance from home plate where the break is greatest
spinrate : int
Pitch spinRate
spindirection : int
Pitch spinDirection
"""
breakangle: float
breaklength: float
breaky: float
spinrate: Optional[float] = None
spindirection: Optional[float] = None
def __repr__(self) -> str:
kws = [f'{key}={value}' for key, value in self.__dict__.items() if value is not None]
return "{}({})".format(type(self).__name__, ", ".join(kws))
@dataclass(repr=False)
class PitchCoordinates:
"""
A class to hold pitch coordinates for playLog
Attributes
----------
ay : float, default=None
Ball acceleration on the y axis
az : float, default=None
Ball acceleration on the z axis
pfxx : float, default=None
horizontal movement of the ball in inches
pfxz : float, default=None
Vertical movement of the ball in inches
px : float, default=None
Horizontal position in feet of the ball as it
crosses the front axis of home plate
pz : float, default=None
Vertical position in feet of the ball as it
crosses the front axis of home plate
vx0 : float, default=None
Velocity of the ball from the x-axis
vy0 : float, default=None
Velocity of the ball from the y axis, this
is negative becuase 0,0,0 is behind the batter
and the ball travels from pitcher mound towards 0,0,0
vz0 : float, default=None
Velocity of the ball from the z axis
x0 : float, default=None
Coordinate location of the ball at the point it was
reeased from pitchers hand on the x axis (time=0)
y0 : float, default=None
Coordinate location of the ball at the point it was
reeased from pitchers hand on the y axis (time=0)
z0 : float, default=None
Coordinate location of the ball at the point it was
reeased from pitchers hand on the z axis (time=0)
ax : float, default=None
Ball acceleration on the x axis
x : float, default=None
X coordinate where pitch crossed front of home plate
y : float, default=None
Y coordinate where pitch crossed front of home plate
"""
ay: Optional[float] = None
az: Optional[float] = None
pfxx: Optional[float] = None
pfxz: Optional[float] = None
px: Optional[float] = None
pz: Optional[float] = None
vx0: Optional[float] = None
vy0: Optional[float] = None
vz0: Optional[float] = None
x0: Optional[float] = None
y0: Optional[float] = None
z0: Optional[float] = None
ax: Optional[float] = None
x: Optional[float] = None
y: Optional[float] = None
def __repr__(self) -> str:
kws = [f'{key}={value}' for key, value in self.__dict__.items() if value is not None]
return "{}({})".format(type(self).__name__, ", ".join(kws))
@dataclass(repr=False)
class PitchData:
"""
A class to hold data on a pitch
Attributes
----------
startspeed : float
The starting speed of the pitch.
endspeed : float
The ending speed of the pitch.
strikezonetop : float
The top of the strike zone.
strikezonebottom : float
The bottom of the strike zone.
coordinates : PitchCoordinates
The coordinates of the pitch.
breaks : PitchBreak
The break data of the pitch.
zone : float
The zone in which the pitch was thrown.
typeconfidence : float
The confidence in the type of pitch thrown.
platetime : float
The amount of time the pitch was in the air.
extension : float
The extension of the pitch.
strikezonewidth : float
The width of the strikezone
strikezonedepth : float
The depth of the strikezone
"""
strikezonetop: float
strikezonebottom: float
breaks: Union[PitchBreak, dict]
coordinates: Optional[Union[PitchCoordinates, dict]] = field(default_factory=dict)
extension: Optional[float] = None
startspeed: Optional[float] = None
endspeed: Optional[float] = None
zone: Optional[float] = None
typeconfidence: Optional[float] = None
platetime: Optional[float] = None
strikezonewidth: Optional[float] = None
strikezonedepth: Optional[float] = None
def __post_init__(self):
self.coordinates = PitchCoordinates(**self.coordinates) if self.coordinates else self.coordinates
self.breaks = PitchBreak(**self.breaks) if self.breaks else self.breaks
def __repr__(self) -> str:
kws = [f'{key}={value}' for key, value in self.__dict__.items() if value is not None]
return "{}({})".format(type(self).__name__, ", ".join(kws))
@dataclass
class HitCoordinates:
"""
A class to represent a play events hit location coordinates.
Attributes
----------
coordx : int
X coordinate for hit
coordy : int
Y coordinate for hit
"""
coordx: Optional[float] = None
coordy: Optional[float] = None
@property
def x(self):
return self.coordx
@property
def y(self):
return self.coordy
@dataclass(repr=False)
class HitData:
"""
A class to represent a play events hit data.
Attributes
----------
launchspeed : float
Hit launch speed
launchangle : int
Hit launch angle
totaldistance : int
Hits total distance
trajectory : str
Hit trajectory
hardness : str
Hit hardness
location : str
Hit location
coordinates : HitCoordinate
Hit coordinates
"""
trajectory: str
hardness: str
coordinates: Union[HitCoordinates, dict]
location: Optional[int] = None
launchspeed: Optional[float] = None
launchangle: Optional[str] = None # this is a negative number and I'm brain farting on those
totaldistance: Optional[float] = None
def __post_init__(self):
self.coordinates = HitCoordinates(**self.coordinates) if self.coordinates else self.coordinates
def __repr__(self) -> str:
kws = [f'{key}={value}' for key, value in self.__dict__.items() if value is not None]
return "{}({})".format(type(self).__name__, ", ".join(kws))
@dataclass
class CodeDesc:
"""
a class to hold a code and a description
Attributes
----------
code : str
the code to reference the attribute using this
description : str
the description of the attribute using this
"""
code: str
description: Optional[str] = None
@dataclass(repr=False)
class Count:
"""
a class to hold a pitch count and base runners
Attributes
----------
code : str
code
balls : int
number of balls
inning : int
inning number
istopinning : bool
bool to hold status of top inning
outs : int
number of outs
runneron1b : bool
bool to hold 1b runner status
runneron2b : bool
bool to hold 2b runner status
runneron3b : bool
bool to hold 3b runner status
strikes : int
strike count
"""
balls: int
outs: int
strikes: int
inning: Optional[int] = None
runneron1b: Optional[bool] = None
runneron2b: Optional[bool] = None
runneron3b: Optional[bool] = None
istopinning: Optional[bool] = None
def __repr__(self) -> str:
kws = [f'{key}={value}' for key, value in self.__dict__.items() if value is not None and value]
return "{}({})".format(type(self).__name__, ", ".join(kws))
@dataclass(repr=False)
class PlayDetails:
"""
A class to represent a gamelog stat for a hitter
Attributes
----------
call : CodeDesc
play call code and description
description : str
description of the play
event : str
type of event
eventtype : str
type of event
isinplay : bool
is the ball in play true or false
isstrike : bool
is the ball a strike true or false
isball : bool
is it a ball true or false
isbasehit : bool
is the event a base hit true or false
isatbat : bool
is the event at bat true or false
isplateappearance : bool
is the event a at play appears true or false
type : CodeDesc
type of pitch code and description
batside : CodeDesc
bat side code and description
pitchhand : CodeDesc
pitch hand code and description
fromcatcher : bool
"""
call: Optional[Union[CodeDesc, dict]] = None
isinplay: Optional[bool] = None
isstrike: Optional[bool] = None
isscoringplay: Optional[bool] = None
isout: Optional[bool] = None
runnergoing: Optional[bool] = None
isball: Optional[bool] = None
isbasehit: Optional[bool] = None
isatbat: Optional[bool] = None
isplateappearance: Optional[bool] = None
batside: Optional[Union[CodeDesc, dict]] = field(default_factory=dict)
pitchhand: Optional[Union[CodeDesc, dict]] = field(default_factory=dict)
eventtype: Optional[str] = None
event: Optional[str] = None
description: Optional[str] = None
type: Optional[Union[CodeDesc, dict]] = field(default_factory=dict)
awayscore: Optional[int] = None
homescore: Optional[int] = None
hasreview: Optional[bool] = None
code: Optional[str] = None
ballcolor: Optional[str] = None
trailcolor: Optional[str] = None
fromcatcher: Optional[bool] = None
def __post_init__(self):
self.call = CodeDesc(**self.call) if self.call else self.call
self.batside = CodeDesc(**self.batside) if self.batside else self.batside
self.pitchhand = CodeDesc(**self.pitchhand) if self.pitchhand else self.pitchhand
self.type = CodeDesc(**self.type) if self.type else self.type
def __repr__(self) -> str:
kws = [f'{key}={value}' for key, value in self.__dict__.items() if value is not None and value]
return "{}({})".format(type(self).__name__, ", ".join(kws))