matplotlib에서 야구장과 스프레이 차트 그리기: baseball-field-viz
Source: Dev.to
위에 제공된 Source 라인 아래에 번역하고 싶은 전체 텍스트를 붙여 주세요.
텍스트를 주시면, 코드 블록이나 URL은 그대로 두고 나머지 내용을 한국어로 번역해 드리겠습니다.
배경
pybaseball의 내장 spraychart()는 편리하지만 히트맵 오버레이를 지원하지 않아 구역별 타구 밀도를 시각화하기 어렵습니다.
seaborn의 kdeplot이나 histplot을 야구장 위에 사용하려면 Matplotlib에서 필드를 직접 그려야 합니다. 좌표 변환과 필드 그리기 코드를 매번 작성하는 것은 번거롭기 때문에 이를 패키징했습니다.
pip install baseball-field-viz
PyPI:
GitHub:
baseball-field-viz가 제공하는 기능
Statcast 시각화를 위한 세 가지 함수:
from baseball_field_viz import transform_coords, draw_field, spraychart
| 함수 | 설명 |
|---|---|
transform_coords(df) | Statcast hc_x/hc_y를 피트 단위로 변환 (홈 플레이트를 원점으로) |
draw_field(ax) | Matplotlib Axes에 야구장을 그립니다 |
spraychart(ax, df, color_by='events') | 위 두 함수를 결합한 원‑라인 함수 |
사용법
빠른 시작
import matplotlib.pyplot as plt
from baseball_field_viz import spraychart
fig, ax = plt.subplots(figsize=(10, 10))
spraychart(ax, df, color_by='events', title='Player — Batted Balls')
plt.show()
color_by='events' 사용 시:
- home run → red
- triple → orange
- double → blue
- single → green
히트맵 오버레이 (핵심 장점)
draw_field가 Axes 객체를 반환하므로, Matplotlib/Seaborn 플롯을 위에 겹쳐 그릴 수 있습니다:
import seaborn as sns
from baseball_field_viz import draw_field, transform_coords
df_t = transform_coords(df[df['hc_x'].notna()])
hits = df_t[df_t['events'].isin(['home_run', 'double', 'triple', 'single'])]
outs = df_t[~df_t['events'].isin(['home_run', 'double', 'triple', 'single'])]
fig, axs = plt.subplots(1, 2, figsize=(16, 8))
# Hits heatmap
draw_field(axs[0])
sns.kdeplot(data=hits, x='x', y='y', ax=axs[0],
cmap='Reds', fill=True, alpha=0.6)
axs[0].set_xlim(-350, 350)
axs[0].set_ylim(-50, 400)
axs[0].set_title('Hits Heatmap')
# Outs heatmap
draw_field(axs[1])
sns.kdeplot(data=outs, x='x', y='y', ax=axs[1],
cmap='Blues', fill=True, alpha=0.6)
axs[1].set_xlim(-350, 350)
axs[1].set_ylim(-50, 400)
axs[1].set_title('Outs Heatmap')
plt.tight_layout()
plt.show()
WBC 2026 로스터 선수에 적용
이 라이브러리를 사용해 WBC 2026 스카우팅 데이터셋을 기반으로 한 Kaggle 노트북을 공개했습니다 — 2024‑2025 시즌 MLB 정규 시즌 Statcast 데이터(모든 18개 국가의 WBC 2026 로스터에 포함된 선수들). (참고: 이는 WBC 경기 데이터가 아니라 WBC 참가 자격이 있는 선수들의 MLB 데이터입니다.)
Kaggle Notebook:
모든 18개 국가 — 전체 개요 스프레이 차트
draw_field와 tab20 컬러맵을 이용한 국가별 산점도 사용:
from baseball_field_viz import draw_field, transform_coords
import matplotlib.cm as cm
import numpy as np
hit_events = ['home_run', 'double', 'triple', 'single']
hits = transform_coords(df[df['hc_x'].notna() & df['events'].isin(hit_events)])
country_list = sorted(hits['country_name'].unique())
colors = cm.tab20(np.linspace(0, 1, len(country_list)))
color_map = dict(zip(country_list, colors))
fig, ax = plt.subplots(figsize=(12, 12))
draw_field(ax)
for country in country_list:
subset = hits[hits['country_name'] == country]
ax.scatter(subset['x'], subset['y'],
c=[color_map[country]], alpha=0.35, s=12,
label=f"{country} ({len(subset)})")
ax.legend(loc='upper right', fontsize=8, ncol=2)
plt.show()
상위 4개 국가 비교
spraychart()를 사용하면 국가별 그리드를 손쉽게 만들 수 있습니다:
top_countries = ['USA', 'Dominican Republic', 'Venezuela', 'Japan']
fig, axs = plt.subplots(2, 2, figsize=(16, 14))
for ax, country in zip(axs.flat, top_countries):
df_c = df[df['country_name'] == country]
spraychart(ax, df_c, color_by='events', title=country)
plt.tight_layout()
plt.show()
일본 — 안타 vs. 아웃 히트맵
KDE 오버레이를 통해 산점도로는 파악하기 어려운 구역별 경향을 드러냅니다:
df_jpn_t = transform_coords(df[df['country_name'] == 'Japan'][df['hc_x'].notna()])
hits_jpn = df_jpn_t[df_jpn_t['events'].isin(hit_events)]
outs_jpn = df_jpn_t[~df_jpn_t['events'].isin(hit_events)]
fig, axs = plt.subplots(1, 2, figsize=(16, 8))
draw_field(axs[0])
sns.kdeplot(data=hits_jpn, x='x', y='y', ax=axs[0],
cmap='Reds', fill=True, alpha=0.6)
draw_field(axs[1])
sns.kdeplot(data=outs_jpn, x='x', y='y', ax=axs[1],
cmap='Blues', fill=True, alpha=0.6)
plt.show()
WBC 2026 스카우팅 대시보드
이 데이터셋은 인터랙티브 대시보드에도 활용됩니다:
Dashboard:
동일한 Statcast 데이터를 기반으로 만든, 18개 국가 전체에 걸친 선수별 타격 및 투구 통계.
v0.2.0 – 스트라이크 존 지원
버전 0.2.0은 두 개의 새로운 함수를 추가합니다:
| Function | Description |
|---|---|
draw_strike_zone(ax, sz_top=3.5, sz_bot=1.5) | plate_x/plate_z 좌표에서 스트라이크 존 사각형을 그립니다 |
pitch_zone_chart(ax, df, color_by='pitch_type') | 자동 크기 조정 스트라이크 존 오버레이와 함께 투구 위치를 플롯합니다 |
스트라이크 존
from pybaseball import statcast_pitcher
from baseball_field_viz import pitch_zone_chart
import matplotlib.pyplot as plt
df = statcast_pitcher('2025-03-01', '2025-10-31', 592789) # Yoshinobu Yamamoto
fig, ax = plt.subplots(figsize=(6, 6))
pitch_zone_chart(ax, df, color_by='pitch_type',
title='Yamamoto 2025 — Pitch Locations')
plt.show()
Statcast는 피치당 sz_top/sz_bot 열을 포함합니다(키에서 추정한 것이 아니라 Hawk‑Eye 측정값).
DataFrame에 해당 열이 존재하면 pitch_zone_chart가 자동으로 평균을 사용하므로, 스트라이크 존은 각 타자의 실제 스탠스를 반영하며 추정값이 아닙니다.
설치
pip install baseball-field-viz
요구 사항
- Python 3.9+
- matplotlib ≥ 3.5
- numpy ≥ 1.21
- pandas ≥ 1.3
요약
draw_field(ax)+spraychart()가 보일러플레이트 Statcast 시각화 코드를 대체합니다.- 직접
Axes접근을 통해 pybaseball의spraychart()에서는 불가능한 히트맵 오버레이를 구현할 수 있습니다. - 18개 국가의 WBC 2026 Statcast 데이터를 사용해 테스트했습니다.
PyPI:
GitHub