학습 순서 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 : 그 위에 놓인 그래프 한 개 (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().
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개 이하일 때만 쓰세요.
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축을 맞춰야 정직한 비교가 됩니다. 축이 제각각이면 작은 값이 큰 값처럼 보입니다.
fig.tight_layout()여러 그래프를 배치하면 제목과 축 이름이 서로 겹칩니다. 이 한 줄이 자동으로 정리합니다. 거의 항상 부르세요.
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 를 나중에 부르세요.
python3 krfont.py를 실행해 내 컴퓨터에 어떤 한글 폰트가 있는지 확인하세요.basicEx.py에서krfont.apply()줄을 주석 처리하고 실행해, 한글이 실제로 어떻게 깨지는지 눈으로 보세요.chartEx2.py의23_pie.png와24_pie_vs_bar.png를 나란히 열고, 음료·베이커리·디저트의 비중 차이를 어느 쪽에서 더 정확히 읽을 수 있는지 판단하세요.styleEx.py의32_axes.png에서set_ylim(0, 400)을set_ylim(140, 360)으로 바꿔 보세요. 같은 데이터가 얼마나 다르게 보이나요?chartEx1.py의 누적 막대를 그룹 막대로, 그룹 막대를 누적으로 서로 바꿔 보고 각각 무엇을 읽기 좋은지 정리하세요.pandasPlotEx.py의 피벗 그래프를kind='area'로 바꿔 보세요.test1.py대시보드에 요일별 매출 그래프를 추가하세요. (step11_pandas/timeEx.py참고)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 에서 이미 했습니다.