팔레트·스케일·필터링, 여기까지 만지면 실전이다 – Seaborn Heatmap 번외편

앞 글에서는 flights 예제 데이터로 기본 Seaborn Heatmap을 그려 보고, 색의 패턴을 읽으면서 인사이트를 정리해 봤습니다.
이번 번외편에서는 같은 데이터를 그대로 쓰지만 팔레트, 값 스케일, 연도 필터링 세 가지만 살짝 만져서 “보고용 그래프”로 한 단계 업그레이드해 보겠습니다.
실제 업무에서는
- 팀장 · 상사에게 보여줄 메인 그래프
- 특정 구간만 확대해서 붙이는 서브 그래프
- 프레젠테이션에 넣을 한 장짜리 핵심 슬라이드”
등을 만들어야 하니까요.
팔레트만 바꿔도 그래프의 성격이 달라진다
기본 히트맵은 보통 rocket류의 짙은 보라 → 밝은 노랑 팔레트를 씁니다.
하지만 “많을수록 좋다”는 메시지를 강조하고 싶다면, 직관적인 파랑–초록–노랑 계열이 훨씬 읽기 편합니다.
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
import seaborn as sns
# ===== 1) macOS 한글 폰트 탐색 =====
font_path = None
for f in fm.findSystemFonts():
if "AppleGothic" in f or "Apple SD Gothic" in f:
font_path = f
break
if font_path:
font_name = fm.FontProperties(fname=font_path).get_name()
print("사용 폰트:", font_name)
else:
font_name = "Apple SD Gothic Neo"
print("AppleGothic 못찾음 →", font_name, "시도")
# ===== 2) seaborn 테마 + 폰트/마이너스 설정 =====
sns.set_theme(
style="whitegrid",
rc={
"font.family": font_name,
"axes.unicode_minus": False,
},
)
# (추가) matplotlib에도 한 번 더 고정
plt.rcParams["font.family"] = font_name
plt.rcParams["axes.unicode_minus"] = False
# ===== 3) flights 데이터 히트맵 =====
flights_long = sns.load_dataset("flights")
flights = flights_long.pivot(index="month", columns="year", values="passengers")
fig, ax = plt.subplots(figsize=(9, 6))
sns.heatmap(
flights,
annot=True,
fmt="d",
linewidths=.5,
cmap="YlGnBu", # 팔레트 변경
ax=ax,
)
ax.set_title("연도별·월별 항공 승객 수 (YlGnBu 팔레트)")
fig.tight_layout()
plt.show()
팔레트 선택 팁
- 매출·사용자수·승객수처럼 “커질수록 좋은 값” →
YlGnBu,Greens,Blues - 위험도·에러 횟수처럼 “커질수록 안 좋은 값” →
Reds,OrRd - 비율·편차처럼 양·음이 모두 중요한 값 →
coolwarm,RdBu_r같은 양·음 구분 팔레트
값 스케일 제한으로 “쏠린 색” 완화하기
연도 뒤로 갈수록 승객 수가 많이 늘어나서, 뒤쪽 연도는 거의 밝은 색만 보이고 앞쪽 연도는 어두운 색 덩어리처럼 뭉쳐 보입니다.
이럴 때는 값 스케일을 인위적으로 눌러 주거나, 로그 스케일을 살짝 사용하는 방법이 있습니다.
from matplotlib.colors import LogNorm
fig, ax = plt.subplots(figsize=(9, 6))
sns.heatmap(
flights,
annot=False, # 이번엔 숫자 대신 색 패턴만 보기
linewidths=.5,
cmap="magma",
norm=LogNorm(), # 로그 스케일 적용
ax=ax
)
ax.set_title("항공 승객 수 히트맵 (로그 스케일)")
fig.tight_layout()
로그 스케일을 쓰면
- 뒤쪽 연도의 “압도적인 증가” 효과는 조금 줄어들고
- 앞쪽 연도의 차이도 눈에 들어옵니다.
또는 단순하게 vmin, vmax로 상·하한을 잘라내서 극단적인 값이 그래프를 지배하지 않도록 조정할 수도 있습니다.
fig, ax = plt.subplots(figsize=(9, 6))
sns.heatmap(
flights,
annot=True,
fmt="d",
linewidths=.5,
cmap="rocket_r",
vmin=150, # 최솟값 이하를 한 색으로 묶기
vmax=600, # 최댓값 이상을 한 색으로 묶기
ax=ax
)
ax.set_title("항공 승객 수 히트맵 (값 범위 150~600 제한)")
fig.tight_layout()
보고용으로는
- 로그 스케일: 전체 패턴을 고르게 보고 싶을 때
- vmin/vmax: “이 이상이면 다 위험”, “이 이하는 모두 양호”처럼 경계값을 강조할 때
쓰면 좋습니다.
특정 연도만 따로 보는 “줌인 서브 히트맵”
상사에게 설명할 때는 “최근 5년만 따로 보여줄래?” 같은 요구가 나오기도 합니다.
히트맵은 열(column)이 연도이기 때문에, loc으로 필요한 연도만 골라서 그리면 됩니다.
recent_years = [1956, 1957, 1958, 1959, 1960]
flights_recent = flights[recent_years]
fig, ax = plt.subplots(figsize=(7, 5))
sns.heatmap(
flights_recent,
annot=True,
fmt="d",
linewidths=.5,
cmap="YlOrRd",
ax=ax
)
ax.set_title("최근 5년(1956–1960) 항공 승객 수 히트맵")
fig.tight_layout()
이렇게 만들면
- 메인 보고서에는 전체 12년짜리 히트맵을 넣고
- 부록이나 상세 페이지에는 “최근 5년 확대 버전”을 같이 넣어서
“전체 패턴 + 최신 추세”를 동시에 보여줄 수 있습니다.
연도 대신 특정 월만 보고 싶다면, flights.loc["Jan":"Mar"]처럼 행 인덱스로 자르는 것도 가능합니다.
실무에서 써먹기 좋은 조합 예시
마지막으로, 위의 세 가지를 한 번에 조합해 봅니다.
“최근 5년만, 성수기(6~8월)만, 직관적인 팔레트로”라는 요구가 들어왔다고 가정해 보죠.
# 6~8월만 필터링
summer = flights.loc[["Jun", "Jul", "Aug"], 1956:1960]
fig, ax = plt.subplots(figsize=(6, 4))
sns.heatmap(
summer,
annot=True,
fmt="d",
linewidths=.5,
cmap="YlGnBu",
vmin=300,
vmax=700,
ax=ax
)
ax.set_title("성수기(6–8월) 최근 5년 승객 수 비교")
fig.tight_layout()
이 정도만 조합해도
- “최근 5년 동안 여름 성수기 수요가 얼마나 더 커졌는지”
- “어느 해가 유난히 강했는지”
를 한눈에 설명할 수 있는 “보고서용 그림”이 됩니다.
마무리 – 번외편에서 챙겨야 할 것들
이번 번외편에서 정리한 포인트를 다시 적어 보면
- 팔레트는 값의 의미(좋음/나쁨/중립)에 맞춰 고르기
- 값 스케일은 로그 스케일 또는 vmin/vmax로 “쏠림”을 완화하기
- 특정 연도·월을 필터링해서 메인·서브 그래프를 분리 구성하기
앞으로 실제 프로젝트에서 히트맵을 그릴 때,
“그냥 한 번에 다 보여주는 기본 그래프”에서 한 걸음 더 나아가서
“보고서와 발표를 위해 다듬어진 그래프”로 만들어 보는 연습을 해보면 좋겠습니다.






