나는 처음으로 Streamlit을 시도하고 MLB 배트 트래킹 대시보드를 만들었다

발행: (2026년 2월 12일 오후 01:49 GMT+9)
5 분 소요
원문: Dev.to

Source: Dev.to

위에 제공된 소스 링크 외에 번역하고 싶은 텍스트를 알려주시면, 해당 내용을 한국어로 번역해 드리겠습니다.

What I Built

I built a web dashboard to visualize MLB bat tracking data from Baseball Savant.

👉 MLB Bat Tracking Dashboard

Dashboard top page

The dashboard has five tabs:

TabWhat it shows
LeaderboardRankings by Bat Speed, Attack Angle, and more
Player ComparisonRadar & bar charts comparing up to 6 players
WBC Country StrengthBatting & pitching scores for all 20 WBC 2026 nations
Team Lineup BuilderBat‑tracking metrics for each MLB team’s 9‑man lineup
Monthly TrendMonth‑by‑month bat speed trend for any player

It also supports English/Japanese language switching.

데이터 소스

저는 자체 오픈‑소스 라이브러리 savant‑extras를 사용하여 데이터를 가져왔습니다.

pip install savant-extras
from savant_extras import bat_tracking, bat_tracking_monthly

# Batter bat tracking data for 2025 season
df = bat_tracking(year=2025, player_type="batter")

# Monthly breakdown
df_monthly = bat_tracking_monthly(year=2025)
  • GitHub:
  • PyPI:

왜 나는 Streamlit을 선택했는가

데이터 분석을 시각적이고 접근하기 쉬운 형태로 공유하고 싶었습니다. Streamlit은 세 가지 이유로 매력적이었습니다:

  • Pure Python – HTML, CSS, JavaScript가 필요 없습니다.
  • 무료 호스팅 Streamlit Community Cloud에서 (GitHub 저장소만 연결하면 됩니다).
  • 한 줄 UI 컴포넌트 – 예: st.selectbox(), st.slider().

예시: 사이드바에 드롭다운 추가하기.

import streamlit as st

year = st.sidebar.selectbox("Season", [2024, 2025], index=1)
player_type = st.sidebar.selectbox("Player type", ["batter", "pitcher"])

핵심 구현 포인트

API 호출 캐싱

매 인터랙션마다 데이터를 가져오면 너무 느립니다. @st.cache_data는 결과를 캐시하여 동일한 인수로 반복 호출 시 즉시 반환합니다.

@st.cache_data(ttl=3600)
def load_bat_data(year: int, player_type: str):
    return bat_tracking(year=year, player_type=player_type)

탭 간 데이터 공유

Streamlit은 각 인터랙션마다 스크립트를 다시 실행합니다. 버튼을 눌러 데이터를 로드한 뒤에는 st.session_state를 사용해 데이터를 유지합니다.

if load_btn:
    st.session_state["df_raw"] = load_bat_data(year, player_type)

if "df_raw" in st.session_state:
    df = st.session_state["df_raw"]

일본어 폰트 지원

Matplotlib 차트에 일본어 라벨을 표시하기 위해 matplotlib-fontja를 사용했습니다.

import matplotlib_fontja  # noqa: F401  ← import 하면 일본어 폰트가 활성화됩니다

겪은 문제: Python 3.13에서 japanize_matplotlib

Streamlit Community Cloud에 배포하면서 Python 3.13에서 distutils가 제거되어 오류가 발생했습니다.

File "japanize_matplotlib/japanize_matplotlib.py", line 5, in 
    from distutils.version import LooseVersion
ModuleNotFoundError

해결 방법은 japanize-matplotlibmatplotlib-fontja로 교체하는 것이었습니다.

- japanize-matplotlib>=1.1
+ matplotlib-fontja

데이터 주의사항

  • MLB 로스터에 포함된 선수들만 포함됩니다; NPB 및 마이너리그 선수는 제외됩니다.
  • 이름 매칭 제한 – 철자 변형이나 동명이인 경우 정확히 매치되지 않을 수 있습니다.
  • WBC 2026 점수는 임시 – 로스터는 Baseball America의 2025년 2월 예측을 기반으로 하며 실제 로스터와 다를 수 있습니다.
  • 배트 트래킹 정확도는 Baseball Savant 데이터 품질에 따라 달라집니다.

결과는 참고용으로 활용하시고, 최종적인 출처로 사용하지 마세요.

요약

  • savant‑extras(내 OSS 라이브러리)를 사용해 데이터를 가져왔습니다.
  • Streamlit으로 5개의 탭 대시보드를 만들었습니다.
  • Streamlit Community Cloud에 무료로 배포했습니다.

Streamlit은 예상보다 쉬웠습니다. st.tabs() 로 탭을 만들고, st.expander() 로 아코디언을 만들며, st.columns() 로 컬럼 레이아웃을 구성하면 대부분의 기능을 구현할 수 있습니다. 데이터 분석을 공유 가능한 형태로 만들고 싶다면 Streamlit이 좋은 선택입니다.

링크

  • 앱:
  • savant‑extras (PyPI):
  • savant‑extras (GitHub):
  • Baseball Savant:
0 조회
Back to Blog

관련 글

더 보기 »

왜 0.1 + 0.2가 코드에서 0.3이 되지 않을까

markdown Floating‑Point Surprise python print 0.1 + 0.2 당신은 0.3이 나오길 기대합니다. 하지만 실제로는 0.30000000000000004가 나옵니다. 당신의 계산기는 0.3이라고 말하고, Excel도 0.3이라고 말합니다. Yo...

dev 여정을 시작하기

배경: 나는 초보자이지만 완전히 초보자는 아니다. 나는 80년대에 어린 시절 BASIC을 배웠고, 20대에 HTML + CSS를 배웠지만, 그 이후로는 코딩을 거의 하지 않았다.