Update functions/PitchPlotFunctions.py
Browse files- functions/PitchPlotFunctions.py +46 -31
functions/PitchPlotFunctions.py
CHANGED
|
@@ -311,68 +311,83 @@ class PitchPlotFunctions:
|
|
| 311 |
def break_plot_big(self, df: pl.DataFrame, ax: plt.Axes, sport_id: int):
|
| 312 |
"""
|
| 313 |
Plots a big break plot for the given DataFrame on the provided axis.
|
| 314 |
-
|
| 315 |
-
Parameters:
|
| 316 |
-
df (pl.DataFrame): The DataFrame containing pitch data.
|
| 317 |
-
ax (plt.Axes): The matplotlib axis to plot on.
|
| 318 |
-
sport_id (int): The sport ID to determine the plot title.
|
| 319 |
"""
|
| 320 |
-
# Set font properties
|
| 321 |
font_properties = {'size': 10}
|
| 322 |
font_properties_titles = {'size': 16}
|
| 323 |
font_properties_axes = {'size': 14}
|
| 324 |
|
| 325 |
-
# Get unique pitch types
|
| 326 |
label_labels = df.sort(by=['prop', 'pitch_type'], descending=[False, True])['pitch_type'].unique()
|
| 327 |
-
j = 0
|
| 328 |
dict_colour, dict_pitch = self.pitch_colours()
|
| 329 |
custom_theme, colour_palette = self.sns_custom_theme()
|
| 330 |
|
| 331 |
-
#
|
| 332 |
for label in label_labels:
|
| 333 |
subset = df.filter(pl.col('pitch_type') == label)
|
| 334 |
if len(subset) > 4:
|
| 335 |
try:
|
| 336 |
-
if df['pitcher_hand'][0] == 'R'
|
| 337 |
-
|
| 338 |
-
|
| 339 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 340 |
except ValueError:
|
| 341 |
return
|
| 342 |
-
j += 1
|
| 343 |
-
else:
|
| 344 |
-
j += 1
|
| 345 |
|
| 346 |
-
# Plot scatter
|
| 347 |
-
if df['pitcher_hand'][0] == 'R'
|
| 348 |
-
|
| 349 |
-
|
| 350 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 351 |
|
| 352 |
# Set plot limits and labels
|
| 353 |
ax.set_xlim((-25, 25))
|
| 354 |
ax.set_ylim((-25, 25))
|
| 355 |
ax.hlines(y=0, xmin=-50, xmax=50, color=colour_palette[8], alpha=0.5, linestyles='--', zorder=1)
|
| 356 |
ax.vlines(x=0, ymin=-50, ymax=50, color=colour_palette[8], alpha=0.5, linestyles='--', zorder=1)
|
| 357 |
-
|
| 358 |
-
|
| 359 |
-
ax.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 360 |
|
| 361 |
# Remove legend and set tick labels
|
| 362 |
ax.get_legend().remove()
|
| 363 |
ax.set_xticklabels(ax.get_xticks(), fontdict=font_properties)
|
| 364 |
ax.set_yticklabels(ax.get_yticks(), fontdict=font_properties)
|
| 365 |
|
| 366 |
-
# Add text annotations
|
| 367 |
if df['pitcher_hand'][0] == 'R':
|
| 368 |
-
ax.text(-24.5, -24.5, s='← Glove Side', fontstyle='italic', ha='left', va='bottom',
|
| 369 |
-
|
| 370 |
-
|
|
|
|
|
|
|
| 371 |
ax.invert_xaxis()
|
| 372 |
-
ax.text(24.5, -24.5, s='← Arm Side', fontstyle='italic', ha='left', va='bottom',
|
| 373 |
-
|
|
|
|
|
|
|
| 374 |
|
| 375 |
-
# Set aspect ratio and
|
| 376 |
ax.set_aspect('equal', adjustable='box')
|
| 377 |
ax.xaxis.set_major_formatter(FuncFormatter(lambda x, _: int(x)))
|
| 378 |
ax.yaxis.set_major_formatter(FuncFormatter(lambda x, _: int(x)))
|
|
|
|
| 311 |
def break_plot_big(self, df: pl.DataFrame, ax: plt.Axes, sport_id: int):
|
| 312 |
"""
|
| 313 |
Plots a big break plot for the given DataFrame on the provided axis.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 314 |
"""
|
| 315 |
+
# Set font properties
|
| 316 |
font_properties = {'size': 10}
|
| 317 |
font_properties_titles = {'size': 16}
|
| 318 |
font_properties_axes = {'size': 14}
|
| 319 |
|
| 320 |
+
# Get unique pitch types
|
| 321 |
label_labels = df.sort(by=['prop', 'pitch_type'], descending=[False, True])['pitch_type'].unique()
|
|
|
|
| 322 |
dict_colour, dict_pitch = self.pitch_colours()
|
| 323 |
custom_theme, colour_palette = self.sns_custom_theme()
|
| 324 |
|
| 325 |
+
# Plot confidence ellipses
|
| 326 |
for label in label_labels:
|
| 327 |
subset = df.filter(pl.col('pitch_type') == label)
|
| 328 |
if len(subset) > 4:
|
| 329 |
try:
|
| 330 |
+
mult = 1 if df['pitcher_hand'][0] == 'R' else -1
|
| 331 |
+
self.confidence_ellipse(
|
| 332 |
+
subset['hb'] * mult,
|
| 333 |
+
subset['ivb'],
|
| 334 |
+
ax=ax,
|
| 335 |
+
edgecolor=dict_colour[label],
|
| 336 |
+
n_std=2,
|
| 337 |
+
facecolor=dict_colour[label],
|
| 338 |
+
alpha=0.2
|
| 339 |
+
)
|
| 340 |
except ValueError:
|
| 341 |
return
|
|
|
|
|
|
|
|
|
|
| 342 |
|
| 343 |
+
# Plot scatter points
|
| 344 |
+
mult = 1 if df['pitcher_hand'][0] == 'R' else -1
|
| 345 |
+
sns.scatterplot(
|
| 346 |
+
ax=ax,
|
| 347 |
+
x=df['hb'] * mult,
|
| 348 |
+
y=df['ivb'],
|
| 349 |
+
hue=df['pitch_type'],
|
| 350 |
+
palette=dict_colour,
|
| 351 |
+
ec='black',
|
| 352 |
+
alpha=1,
|
| 353 |
+
zorder=2,
|
| 354 |
+
s=35
|
| 355 |
+
)
|
| 356 |
|
| 357 |
# Set plot limits and labels
|
| 358 |
ax.set_xlim((-25, 25))
|
| 359 |
ax.set_ylim((-25, 25))
|
| 360 |
ax.hlines(y=0, xmin=-50, xmax=50, color=colour_palette[8], alpha=0.5, linestyles='--', zorder=1)
|
| 361 |
ax.vlines(x=0, ymin=-50, ymax=50, color=colour_palette[8], alpha=0.5, linestyles='--', zorder=1)
|
| 362 |
+
|
| 363 |
+
# Set labels with proper padding
|
| 364 |
+
ax.set_xlabel('Horizontal Break (in)', fontdict=font_properties_axes, labelpad=10)
|
| 365 |
+
ax.set_ylabel('Induced Vertical Break (in)', fontdict=font_properties_axes, labelpad=10)
|
| 366 |
+
ax.set_title(
|
| 367 |
+
f"{self.sport_id_dict()[sport_id]} - Short Form Pitch Movement Plot",
|
| 368 |
+
fontdict=font_properties_titles,
|
| 369 |
+
pad=20 # Add padding between title and plot
|
| 370 |
+
)
|
| 371 |
|
| 372 |
# Remove legend and set tick labels
|
| 373 |
ax.get_legend().remove()
|
| 374 |
ax.set_xticklabels(ax.get_xticks(), fontdict=font_properties)
|
| 375 |
ax.set_yticklabels(ax.get_yticks(), fontdict=font_properties)
|
| 376 |
|
| 377 |
+
# Add text annotations
|
| 378 |
if df['pitcher_hand'][0] == 'R':
|
| 379 |
+
ax.text(-24.5, -24.5, s='← Glove Side', fontstyle='italic', ha='left', va='bottom',
|
| 380 |
+
bbox=dict(facecolor='white', edgecolor='black'), fontsize=13, zorder=3)
|
| 381 |
+
ax.text(24.5, -24.5, s='Arm Side →', fontstyle='italic', ha='right', va='bottom',
|
| 382 |
+
bbox=dict(facecolor='white', edgecolor='black'), fontsize=13, zorder=3)
|
| 383 |
+
else:
|
| 384 |
ax.invert_xaxis()
|
| 385 |
+
ax.text(24.5, -24.5, s='← Arm Side', fontstyle='italic', ha='left', va='bottom',
|
| 386 |
+
bbox=dict(facecolor='white', edgecolor='black'), fontsize=13, zorder=3)
|
| 387 |
+
ax.text(-24.5, -24.5, s='Glove Side →', fontstyle='italic', ha='right', va='bottom',
|
| 388 |
+
bbox=dict(facecolor='white', edgecolor='black'), fontsize=13, zorder=3)
|
| 389 |
|
| 390 |
+
# Set aspect ratio and tick formatters
|
| 391 |
ax.set_aspect('equal', adjustable='box')
|
| 392 |
ax.xaxis.set_major_formatter(FuncFormatter(lambda x, _: int(x)))
|
| 393 |
ax.yaxis.set_major_formatter(FuncFormatter(lambda x, _: int(x)))
|