포스트

Matplotlib 기초 (3) - 여러 그래프와 꾸미기, pandas 연동

한 화면에 그래프를 여러 개 배치하는 subplots, 색·축 범위·격자로 그림을 다듬는 법, pandas의 df.plot()으로 바로 그리는 법, 그리고 seaborn을 곁들이는 지점까지 정리하며 데이터 분석 기초 세 시리즈를 마무리하는 Matplotlib 기초 마지막 편입니다.

Matplotlib 기초 (3) - 여러 그래프와 꾸미기, pandas 연동

그래프 한 장을 그릴 줄 알면, 다음은 여러 장을 한 화면에 놓고 보기 좋게 다듬는 일입니다. 이 글은 subplots로 그래프를 배치하는 법, 색과 축으로 그림을 다듬는 법, 그리고 pandas에서 그래프를 바로 그리는 df.plot()을 다룹니다. 1편의 Figure와 Axes 구조가 여기서 진가를 발휘합니다. 이 글로 NumPy부터 이어온 데이터 분석 기초를 마무리합니다.

여러 그래프를 한 화면에: subplots

1편에서 Figure는 도화지, Axes는 그 위의 그래프 하나라고 했습니다. plt.subplots(행, 열)에 숫자를 주면 도화지 하나에 Axes를 격자로 여러 개 만들 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import pandas as pd
import matplotlib.pyplot as plt

df = pd.read_csv("https://blog.hoseunggg.com/assets/data/grades.csv")

fig, axes = plt.subplots(1, 2, figsize=(12, 4))   # 1행 2열, 도화지 크기 지정

axes[0].hist(df["성적"].dropna(), bins=20)
axes[0].set_title("성적 분포")

axes[1].scatter(df["학점"], df["성적"], alpha=0.3)
axes[1].set_title("학점과 성적")

fig.tight_layout()   # 그래프끼리 겹치는 제목·라벨을 자동 정리

plt.subplots(1, 2)는 Axes 두 개를 배열로 돌려줍니다. axes[0], axes[1]처럼 인덱스로 골라 각각에 그립니다. 2행 2열이면 axes[0, 0]처럼 2차원 인덱스가 됩니다. figsize=(가로, 세로)는 인치 단위 도화지 크기이고, fig.tight_layout()은 그래프들이 서로 겹치지 않게 간격을 자동 조정합니다.

여기서 1편에서 객체지향 방식을 권한 이유가 분명해집니다. 그래프가 여러 개면 “지금 활성화된 그래프”라는 개념이 무너지므로, axes[0]처럼 명시적으로 지목하는 방식만이 안전합니다.

색과 축으로 다듬기

기본 그래프를 읽기 좋게 만드는 손질은 대부분 몇 가지 인자로 끝납니다.

1
2
3
4
5
6
7
8
9
10
term_avg = df.groupby("수강학기")["성적"].mean()

fig, ax = plt.subplots(figsize=(10, 4))
ax.plot(term_avg.index, term_avg.values,
        color="tab:blue", linewidth=2, marker="o")

ax.set_ylim(0, 100)                 # y축 범위 고정
ax.grid(True, alpha=0.3)            # 옅은 격자
ax.tick_params(axis="x", rotation=45)   # x축 라벨 회전
ax.set_title("학기별 평균 성적")

자주 쓰는 손질은 이 정도입니다.

  • color"tab:blue", "tab:orange" 같은 기본 팔레트 색이 무난합니다. 빨강과 초록만으로 구분하는 것은 색각 이상이 있는 사람이 못 읽으므로 피합니다.
  • set_ylim / set_xlim — 축 범위를 고정합니다. 성적처럼 0~100이 정해진 데이터는 set_ylim(0, 100)으로 고정해야 여러 그래프의 높이를 공정하게 비교할 수 있습니다.
  • grid — 옅은 격자는 값을 읽는 데 도움이 됩니다. alpha로 흐리게 해서 데이터를 가리지 않게 합니다.
  • tick_params(rotation=45) — 학기 라벨처럼 길어서 겹치는 눈금을 비스듬히 돌립니다.

축 범위 이야기에는 정직함의 문제가 걸려 있습니다. 막대 그래프의 y축을 0에서 시작하지 않으면 작은 차이가 큰 차이처럼 과장됩니다. 막대 그래프는 y축을 0부터 두는 것이 원칙입니다.

pandas에서 바로 그리기: df.plot()

지금까지는 pandas로 집계한 값을 matplotlib에 넘겨 그렸습니다. 사실 pandas는 matplotlib을 안에 품고 있어서, DataFrame이나 Series에 바로 .plot()을 부를 수 있습니다.

1
2
3
term_avg.plot(kind="line", marker="o", title="학기별 평균 성적")
df["평점"].value_counts().sort_index().plot(kind="bar")
df["성적"].plot(kind="hist", bins=20)

kind로 그래프 종류를 고릅니다. "line", "bar", "hist", "box", "scatter"가 있습니다. 탐색 단계에서 빠르게 훑어볼 때는 이 한 줄이 편합니다.

df.plot()도 결국 matplotlib을 부르는 것이라, 앞에서 배운 손질을 그대로 얹을 수 있습니다. .plot()이 돌려주는 것이 바로 Axes 객체입니다.

1
2
3
ax = term_avg.plot(kind="line", marker="o")
ax.set_ylim(0, 100)
ax.set_ylabel("성적")

정리하면, 빠르게 탐색할 때는 df.plot(), 세밀하게 다듬거나 여러 그래프를 배치할 때는 fig, ax = plt.subplots()로 시작하는 방식을 씁니다. 둘은 대립하는 게 아니라 같은 도구의 두 입구입니다.

seaborn을 곁들이는 지점

matplotlib으로 통계 그래프를 그리다 보면 반복되는 준비 작업이 많아집니다. 집단별로 데이터를 나누고, 색을 배정하고, 범례를 다는 일입니다. seaborn은 matplotlib 위에 얹혀서 이런 통계 시각화를 한 줄로 줄여주는 라이브러리입니다.

1
2
3
4
import seaborn as sns

# 이수구분별 성적 분포를 색까지 나눠 한 줄로
sns.boxplot(data=df, x="이수구분", y="성적")

앞에서 박스플롯 여러 개를 나란히 그리려고 데이터를 집단별로 쪼갰던 작업을, seaborn은 xy 컬럼 이름만 주면 알아서 합니다. seaborn도 내부는 matplotlib이라, 이 글에서 배운 Figure와 Axes, 축 손질이 그대로 통합니다. matplotlib으로 구조를 이해한 다음 seaborn으로 넘어가는 순서가 좋은 이유입니다. seaborn 자체는 별도 노트에서 다룰 주제입니다.

정리

개념한 줄 요약
subplotsplt.subplots(행, 열)로 Axes를 격자로. axes[i]로 지목해 그린다
tight_layout그래프끼리 겹치는 제목·라벨을 자동 정리
색과 축color, set_ylim, grid, tick_params로 다듬기
축의 정직함막대 그래프의 y축은 0부터. 안 그러면 차이가 과장된다
df.plot()pandas에서 바로 그리기. 탐색은 이 한 줄, 반환값은 Axes
seabornmatplotlib 위의 통계 시각화 단축 도구. 내부는 matplotlib

데이터 분석 기초를 마치며

NumPy 기초에서 배열로 데이터를 빠르게 다루는 법, Pandas 기초에서 표로 데이터를 정제하고 집계하는 법, 그리고 이 Matplotlib 기초에서 그것을 그림으로 확인하는 법까지, 데이터 분석의 기본 도구 세 벌을 정리했습니다. 데이터를 배열로 다루고, 표로 점검하고, 그림으로 확인하는 이 흐름이 이후 모든 작업의 바닥이 됩니다.

이 위에서 데이터로부터 모델을 학습시키는 이야기가 머신러닝 기초로 이어집니다. 도구를 익혔으니, 이제 그 도구로 무엇을 만드는지로 넘어갈 차례입니다.

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.