Skip to content

Latest commit

 

History

History

README.md

step12_visualization — matplotlib 시각화

학습 순서 12번. 숫자를 그림으로 바꿉니다.

⚠️ 설치 필요 — 루트 requirements.txt

왜 그림인가

step11 에서 groupby 로 표를 만들었습니다. 표는 정확하지만 한눈에 안 들어옵니다.

1   355400
2   201000
3   268000
...

숫자 12개를 훑어 "5월이 최저구나"를 알아내는 데는 몇 초가 걸립니다. 그래프는 그걸 0.2초에 알려 줍니다. 분석 결과를 남에게 전달할 때 그림이 필요한 이유입니다.

⚠️ 가장 먼저 — 한글이 깨집니다

matplotlib 기본 폰트에는 한글 글자가 없습니다. 아무 설정 없이 한글 제목을 넣으면 전부 네모(□□□)로 나옵니다. 한국어로 그래프를 그릴 때 거의 매번 만나는 문제입니다.

이 챕터는 krfont.py 모듈로 해결합니다.

import krfont
krfont.apply()      # 설치된 한글 폰트를 찾아 적용

운영체제별로 폰트가 달라서 후보를 순서대로 찾습니다.

OS 기본 탑재
macOS AppleGothic, Apple SD Gothic Neo
Windows Malgun Gothic (맑은 고딕)
리눅스 없음 → sudo apt install fonts-nanum 후 NanumGothic

krfont.apply() 는 axes.unicode_minus = False 도 함께 설정합니다. 한글 폰트 중에는 유니코드 마이너스(−)가 없는 것이 있어서, 이걸 안 하면 음수 축 눈금만 네모로 나옵니다. 원인을 못 찾고 한참 헤매는 증상입니다.

krfont.py 는 step09_module 에서 배운 "같은 설정을 모듈로 빼서 재사용" 을 실제로 쓴 예이기도 합니다. 파일 7개에 같은 코드를 복사해 두는 대신 한 곳에 두었습니다.

학습 목표

  • 한글이 깨지지 않게 폰트를 설정한다
  • Figure 와 Axes 의 관계를 안다
  • 데이터에 맞는 그래프 종류를 고른다
  • 색·범례·축·주석으로 보여 주고 싶은 것을 강조한다
  • 여러 그래프를 한 장에 배치한다
  • df.plot() 으로 pandas에서 바로 그린다

파일 지도

파일 내용
krfont.py ★★ 한글 폰트 설정 모듈
basicEx.py ★ 첫 그래프, Figure/Axes, pyplot vs 객체 지향, 저장 옵션
chartEx1.py 선·막대·가로막대·누적·그룹
chartEx2.py 산점도·히스토그램·박스플롯·파이 (+ 파이를 피해야 하는 이유)
styleEx.py 색·선 스타일·축 다듬기·주석과 강조·스타일 시트
subplotEx.py subplots·축 공유·반복문·gridspec
pandasPlotEx.py ★★ df.plot() — 실무에서 가장 많이 쓰는 방법
test1.py ★★ 종합 — 한 장짜리 매출 대시보드
output/ PNG 저장 위치 (.gitignore 처리)

실행 방법

cd step12_visualization      # ← 데이터를 상대 경로로 찾으므로 이 폴더에서
python3 krfont.py            # 내 컴퓨터에 한글 폰트가 있는지 먼저 확인
python3 basicEx.py
python3 test1.py             # 대시보드

실행하면 output/ 에 PNG가 생깁니다. 창을 띄워 보고 싶으면 각 파일 위쪽의

SHOW = False        # True 로 바꾸면 그래프 창이 뜹니다

를 True 로 바꾸세요. 기본값을 False 로 둔 이유는 창이 뜨면 프로그램이 멈춰서 여러 파일을 연달아 실행하기 불편하기 때문입니다.

짚고 갈 지점

Figure 와 Axes

Figure  : 도화지 한 장 (창 하나)
Axes    : 그 위에 놓인 그래프 한 개 (x축·y축이 있는 영역)

한 Figure 에 Axes 를 여러 개 놓을 수 있습니다. 이게 subplotEx.py 의 전부입니다.

두 가지 작성 방식

# (가) pyplot — 짧다
plt.plot(x, y)
plt.title('제목')
plt.savefig('a.png')

# (나) 객체 지향 — 확실하다
fig, ax = plt.subplots(figsize=(6, 4))
ax.plot(x, y)
ax.set_title('제목')
fig.savefig('a.png')

plt.xxx() 는 "지금 활성화된 그래프" 에 그립니다. 그래프가 하나면 편하지만, 여러 개를 다루면 어디에 그려지는지 헷갈립니다. 공식 문서와 실무 코드는 대부분 객체 지향입니다.

메서드 이름도 살짝 다릅니다 — plt.title() ↔ ax.set_title(), plt.xlabel() ↔ ax.set_xlabel().

plt.close() 를 빼먹지 마세요

fig.savefig('a.png')
plt.close(fig)          # ← 이걸 빼면

닫지 않으면 그림이 계속 메모리에 쌓이고 다음 그래프에 겹쳐 그려집니다. 반복문 안에서 그림을 그릴 때 특히 문제가 됩니다.

그래프 종류 고르기

무엇을 보여 주나 무엇을 쓰나
시간에 따른 변화 선 (plot)
항목 간 크기 비교 막대 (bar) — 이름이 길면 가로 막대 (barh)
두 값의 관계 산점도 (scatter)
값의 분포 히스토그램 (hist)
그룹별 분포 비교 박스플롯 (boxplot)
구성 비중 막대. (파이는 되도록 피하세요)

막대와 히스토그램은 다릅니다. 막대는 정해진 항목의 크기이고, 히스토그램은 연속된 값을 구간으로 나눈 개수입니다.

⚠️ 파이 차트는 되도록 쓰지 마세요

사람은 각도 차이를 잘 못 읽습니다. 30%와 35%를 구분하기 어렵고, 조각이 4개를 넘으면 거의 읽을 수 없습니다.

chartEx2.py 는 같은 데이터를 파이(23_pie.png)와 가로 막대(24_pie_vs_bar.png)로 각각 그립니다. 두 파일을 나란히 열어 보세요. 어느 쪽이 정확하게 읽히는지 바로 보입니다.

파이는 "비중"을 강조해야 하고 조각이 3개 이하일 때만 쓰세요.

⚠️ 막대의 y축은 0부터

ax.set_ylim(0, 400)     # 막대 그래프에서는 필수

100과 105를 y축 99~106으로 그리면 5배 차이처럼 보입니다. 막대의 길이가 곧 값이므로 0부터 시작해야 정직합니다.

선 그래프는 변화를 보는 것이라 0부터가 아니어도 되는 경우가 있지만, 막대는 예외가 없습니다.

강조는 "나머지를 죽여서"

ax.plot(월, 매출, color='lightgray')                    # 전체는 흐리게
ax.scatter([최고], [값], color='crimson', s=90)          # 보여 줄 것만 진하게
ax.annotate('최고', xy=(...), xytext=(...), arrowprops=...)

전부 알록달록하면 아무것도 강조되지 않습니다. styleEx.py 의 33_annotate.png 를 보세요.

축 공유

fig, axes = plt.subplots(1, 3, sharey=True)

여러 그래프를 나란히 놓을 때 y축을 맞춰야 정직한 비교가 됩니다. 축이 제각각이면 작은 값이 큰 값처럼 보입니다.

tight_layout()

fig.tight_layout()

여러 그래프를 배치하면 제목과 축 이름이 서로 겹칩니다. 이 한 줄이 자동으로 정리합니다. 거의 항상 부르세요.

pandas로 바로 그리기

df.groupby('월')['매출'].sum().plot(kind='bar')

DataFrame·Series 에 .plot() 이 붙어 있습니다. 내부적으로 matplotlib을 부르므로 결과는 같고, 데이터가 이미 pandas에 있다면 훨씬 짧습니다.

언제
.plot() 탐색적 분석(EDA). 빠르게 확인만 할 때 — 거의 이것만 씁니다
matplotlib 직접 보고서·발표용으로 다듬을 때. 주석·강조·복잡한 배치

섞어 써도 됩니다. .plot() 이 Axes 를 돌려주므로 받아서 계속 손보면 됩니다 (pandasPlotEx.py 의 57_mixed.png).

스타일 시트를 쓰면 폰트가 초기화됩니다

with plt.style.context('ggplot'):
    krfont.apply(verbose=False)     # ← 다시 불러야 한다

스타일이 rcParams 를 통째로 갈아 끼우면서 폰트 설정도 날아갑니다. 한글이 갑자기 깨지면 이걸 의심하세요.

흔한 실수

증상 원인
한글이 □□□ krfont.apply() 안 부름
음수 눈금만 □ axes.unicode_minus = False 누락
스타일 적용 후 갑자기 깨짐 스타일이 폰트를 초기화. 다시 적용
그림이 겹쳐 그려짐 plt.close() 누락
제목·축 이름이 겹침 tight_layout() 누락
제목이 잘려 저장됨 savefig(bbox_inches='tight') 누락
막대 위 값이 잘림 set_ylim 위쪽 여유 부족
창이 안 뜸 SHOW = True 로 바꾸거나 plt.show() 추가
저장 파일이 비어 있음 plt.show() 를 savefig 앞에 부름 (show 가 그림을 비운다)

마지막 것이 잘 안 잡힙니다. savefig 를 먼저, show 를 나중에 부르세요.

연습 과제

  1. python3 krfont.py 를 실행해 내 컴퓨터에 어떤 한글 폰트가 있는지 확인하세요.
  2. basicEx.py 에서 krfont.apply() 줄을 주석 처리하고 실행해, 한글이 실제로 어떻게 깨지는지 눈으로 보세요.
  3. chartEx2.py 의 23_pie.png 와 24_pie_vs_bar.png 를 나란히 열고, 음료·베이커리·디저트의 비중 차이를 어느 쪽에서 더 정확히 읽을 수 있는지 판단하세요.
  4. styleEx.py 의 32_axes.png 에서 set_ylim(0, 400) 을 set_ylim(140, 360) 으로 바꿔 보세요. 같은 데이터가 얼마나 다르게 보이나요?
  5. chartEx1.py 의 누적 막대를 그룹 막대로, 그룹 막대를 누적으로 서로 바꿔 보고 각각 무엇을 읽기 좋은지 정리하세요.
  6. pandasPlotEx.py 의 피벗 그래프를 kind='area' 로 바꿔 보세요.
  7. test1.py 대시보드에 요일별 매출 그래프를 추가하세요. (step11_pandas/timeEx.py 참고)
  8. test1.py 를 함수로 나누세요 — load(), draw_monthly(ax, data), draw_category(ax, data) … step06_function 에서 배운 대로.

여기까지 왔다면

step01 의 print('hello python') 에서 시작해 데이터를 읽고 정제하고 집계해 그림으로 만드는 한 바퀴를 완주했습니다.

이 저장소가 다루지 않은 것들 중 다음으로 갈 만한 곳:

주제 도구
통계 그래프를 더 쉽게 seaborn — matplotlib 위에 얹는 층. 한 줄이 더 짧아집니다
마우스로 만지는 그래프 plotly — 확대·툴팁이 되는 웹 그래프
코드와 결과를 함께 문서로 Jupyter Notebook
데이터베이스에서 바로 읽기 pd.read_sql()
통계 검정 scipy.stats
머신러닝 scikit-learn

어느 쪽이든 데이터를 다루는 부분은 여기서 배운 pandas 가 그대로입니다. 분석의 8할은 데이터를 깨끗하게 만드는 일이고, 그건 step08~step11 에서 이미 했습니다.