목차
메타 설명
숫자로 가득한 데이터를 어떻게 한눈에 이해할 수 있을까요? Python의 대표적인 데이터 시각화 라이브러리 Matplotlib를 이용해 선 그래프, 막대그래프, 산점도, 히스토그램, 원 그래프를 만들고 꾸미는 방법을 초보자도 이해할 수 있도록 실습 중심으로 알아봅니다.
지난 시간에는 pandas를 이용해 CSV와 Excel 데이터를 정리하고 분석하는 방법을 배웠습니다.
카테고리별 매출도 계산했고, 판매량이 높은 상품도 찾았으며, 결측치와 중복 데이터도 깔끔하게 정리했습니다.
분석 결과가 다음과 같다고 가정해 보겠습니다.
1월 매출: 1,200,000원
2월 매출: 1,350,000원
3월 매출: 1,280,000원
4월 매출: 1,620,000원
5월 매출: 1,850,000원
6월 매출: 2,100,000원숫자를 읽어 보면 매출이 전반적으로 증가했다는 사실을 알 수 있습니다.
하지만 다음과 같은 그래프가 있다면 어떨까요?
매출
▲
│ ●
│ ●
│ ●
│ ●
│ ● ●
│ ●
└──────────────────────────▶ 월
1월 2월 3월 4월 5월 6월숫자를 하나씩 읽지 않아도 매출의 흐름이 바로 보입니다.
3월에 잠깐 감소했다가 4월부터 다시 상승했다는 사실도 금방 알아차릴 수 있습니다.
이것이 바로 데이터 시각화의 힘입니다.
숫자가 보고서 책상 위에서 졸고 있었다면, 그래프는 그 숫자를 무대 위로 끌어올려 이야기를 시작하게 만듭니다. 📊🎤
이번 시간에는 Python의 대표적인 데이터 시각화 라이브러리인 Matplotlib를 이용해 숫자 데이터를 보기 좋은 그래프로 변환하는 방법을 알아보겠습니다.
1. 데이터 시각화란?
데이터 시각화는 숫자나 문자로 이루어진 데이터를 그래프, 차트, 지도 등의 시각적인 형태로 표현하는 작업입니다.
다음 두 데이터를 비교해 보겠습니다.
숫자로만 표현한 경우
Python: 85
Java: 70
JavaScript: 78
SQL: 90
Go: 65막대그래프로 표현한 경우
Python █████████████████ 85
Java ██████████████ 70
JavaScript ███████████████ 78
SQL ██████████████████ 90
Go █████████████ 65그래프로 표현하면 SQL 점수가 가장 높고 Go 점수가 가장 낮다는 사실을 즉시 알 수 있습니다.
데이터 시각화는 다음과 같은 질문에 빠르게 답할 수 있도록 도와줍니다.
* 시간이 지나면서 값이 증가하고 있는가?* 어떤 항목이 가장 큰가?* 값들이 어느 구간에 많이 몰려 있는가?* 두 변수 사이에 관계가 있는가?* 전체에서 각 항목이 차지하는 비율은 얼마인가?* 다른 값들과 크게 동떨어진 이상치는 있는가?
데이터를 분석하는 것이 탐정의 추리라면, 그래프는 사건 현장의 CCTV 화면과 같습니다.
숫자만 봤을 때 숨어 있던 패턴이 화면 위에서 슬쩍 모습을 드러냅니다. 🔍
2. Matplotlib란?
Matplotlib는 Python에서 정적 이미지, 애니메이션, 대화형 시각화를 만들 수 있는 대표적인 데이터 시각화 라이브러리입니다. 공식 문서에서도 Matplotlib를 Python을 위한 종합적인 시각화 라이브러리로 소개합니다.
Matplotlib를 사용하면 다음과 같은 그래프를 만들 수 있습니다.
* 선 그래프* 막대그래프* 가로 막대그래프* 산점도* 히스토그램* 원 그래프* 상자 수염 그래프* 영역 그래프* 오차 막대그래프* 히트맵* 3차원 그래프* 애니메이션 그래프
Matplotlib는 다음 라이브러리들의 시각화 기반으로도 널리 활용됩니다.
pandas
Seaborn
GeoPandas
scikit-learn 시각화 도구
여러 과학 계산 라이브러리Matplotlib의 가장 큰 특징은 그래프의 거의 모든 부분을 세밀하게 조절할 수 있다는 점입니다.
그래프 크기
선의 색상
선의 굵기
점의 모양
글꼴
축 범위
눈금
범례
격자
여백
해상도
파일 형식처음에는 설정 항목이 많아 복잡해 보일 수 있습니다.
하지만 기본 구조만 이해하면 그래프라는 무대의 조명, 배우, 배경, 자막을 원하는 대로 연출할 수 있습니다. 🎭
3. Matplotlib 설치하기
터미널이나 명령 프롬프트에서 다음 명령어를 실행합니다.
pip install matplotlibPython 실행 환경을 명확히 지정하려면 다음 명령어를 사용할 수 있습니다.
python -m pip install matplotlibmacOS나 Linux 환경에서 `python3`를 사용한다면 다음과 같이 설치합니다.
python3 -m pip install matplotlibMatplotlib 공식 설치 문서는 Windows, macOS, Linux에서 PyPI의 wheel 패키지를 이용해 설치할 수 있도록 안내합니다.
가상환경에서 설치하기
Windows
python -m venv venv
venv\Scripts\activate
python -m pip install matplotlibmacOS 또는 Linux
python3 -m venv venv
source venv/bin/activate
python -m pip install matplotlib설치 확인하기
import matplotlib
print(matplotlib.__version__)버전이 정상적으로 출력되면 설치가 완료된 것입니다.
4. 첫 번째 선 그래프 그리기
가장 간단한 선 그래프부터 만들어 보겠습니다.
import matplotlib.pyplot as plt
months = [1, 2, 3, 4, 5, 6]
sales = [120, 135, 128, 162, 185, 210]
plt.plot(months, sales)
plt.show()코드를 실행하면 별도의 창에 선 그래프가 나타납니다.
코드 분석
pyplot 불러오기
import matplotlib.pyplot as pltMatplotlib의 `pyplot` 모듈을 `plt`라는 별명으로 불러옵니다.
`pyplot`은 현재 Figure와 Axes를 추적하면서 그래프를 그리는 상태 기반 인터페이스입니다. 간단한 그래프나 대화형 작업에서 편리하게 사용할 수 있습니다.
선 그래프 그리기
plt.plot(months, sales)첫 번째 값은 x축 데이터입니다.
months = [1, 2, 3, 4, 5, 6]두 번째 값은 y축 데이터입니다.
sales = [120, 135, 128, 162, 185, 210]각 데이터는 다음과 같이 연결됩니다.
x=1, y=120
x=2, y=135
x=3, y=128
x=4, y=162
x=5, y=185
x=6, y=210그래프 화면 표시하기
plt.show()작성한 그래프를 화면에 표시합니다.
공식 시작 가이드에서도 `Figure`와 `Axes`를 만든 뒤 데이터를 그리고 `plt.show()`로 화면에 표시하는 기본 흐름을 안내합니다.
5. Figure와 Axes 이해하기
Matplotlib를 제대로 사용하려면 `Figure`와 `Axes`의 차이를 이해해야 합니다.
이름만 보면 Axes가 단순히 x축과 y축을 의미하는 것처럼 느껴지지만, Matplotlib에서는 조금 다릅니다.
Figure
└── Axes
├── 제목
├── x축
├── y축
├── 선
├── 막대
├── 점
├── 범례
└── 격자Figure
`Figure`는 그래프 전체를 담는 가장 바깥쪽 도화지입니다.
사진 액자 전체
문서의 한 페이지
공연장의 전체 무대Axes
`Axes`는 Figure 안에서 실제 그래프가 그려지는 영역입니다.
하나의 Figure 안에 Axes를 여러 개 배치하면 한 화면에 여러 그래프를 그릴 수 있습니다.
Figure
├── 첫 번째 Axes: 월별 매출
├── 두 번째 Axes: 상품별 판매량
├── 세 번째 Axes: 지역별 매출
└── 네 번째 Axes: 가격 분포다음 코드에서 `fig`는 Figure이고 `ax`는 Axes입니다.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(
[1, 2, 3, 4],
[10, 20, 15, 30]
)
plt.show()Matplotlib는 명시적인 Axes 인터페이스와 상태 기반 pyplot 인터페이스를 제공합니다. 명시적인 방식은 Figure와 Axes 객체를 직접 생성하고 해당 객체의 메서드로 그래프를 구성합니다.
6. pyplot 방식과 객체 지향 방식
Matplotlib에서는 크게 두 가지 방식으로 그래프를 작성할 수 있습니다.
pyplot 방식
import matplotlib.pyplot as plt
plt.plot(
[1, 2, 3],
[10, 20, 15]
)
plt.title("월별 매출")
plt.xlabel("월")
plt.ylabel("매출")
plt.show()코드가 짧고 간단합니다.
작은 그래프를 빠르게 확인할 때 편리합니다.
객체 지향 방식
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(
[1, 2, 3],
[10, 20, 15]
)
ax.set_title("월별 매출")
ax.set_xlabel("월")
ax.set_ylabel("매출")
plt.show()객체 지향 방식에서는 `ax` 객체를 통해 그래프를 조작합니다.
어떤 방식을 사용하는 것이 좋을까?
간단한 데이터 확인
→ pyplot 방식
여러 그래프 배치
→ 객체 지향 방식
함수로 그래프 생성
→ 객체 지향 방식
복잡한 보고서와 대시보드
→ 객체 지향 방식이번 글에서는 두 방식을 모두 소개하지만, 실전 코드에서는 객체 지향 방식을 중심으로 사용하겠습니다.
객체 지향 방식은 각 그래프의 주인이 명확합니다.
그래프가 여러 개일 때 “제목이 어느 그래프로 갔지?”라는 유령 사건이 줄어듭니다. 👻
7. 그래프 제목과 축 이름 설정하기
import matplotlib.pyplot as plt
months = [1, 2, 3, 4, 5, 6]
sales = [120, 135, 128, 162, 185, 210]
fig, ax = plt.subplots()
ax.plot(months, sales)
ax.set_title("월별 매출 변화")
ax.set_xlabel("월")
ax.set_ylabel("매출액")
plt.show()pyplot 방식
plt.title("월별 매출 변화")
plt.xlabel("월")
plt.ylabel("매출액")객체 지향 방식
ax.set_title("월별 매출 변화")
ax.set_xlabel("월")
ax.set_ylabel("매출액")제목은 그래프가 무엇을 보여 주는지 설명해야 합니다.
다음 제목은 의미가 너무 넓습니다.
매출 그래프조금 더 구체적으로 작성하는 것이 좋습니다.
2026년 상반기 월별 온라인 매출좋은 제목은 그래프를 처음 보는 사람에게 다음 정보를 전달합니다.
무엇을
어떤 기준으로
어느 기간 동안
표현했는가?8. 선의 모양 꾸미기
선 그래프는 색상, 굵기, 선 모양, 점 모양 등을 변경할 수 있습니다.
import matplotlib.pyplot as plt
months = [1, 2, 3, 4, 5, 6]
sales = [120, 135, 128, 162, 185, 210]
fig, ax = plt.subplots()
ax.plot(
months,
sales,
color="royalblue",
linewidth=3,
linestyle="--",
marker="o",
markersize=8
)
ax.set_title("월별 매출 변화")
ax.set_xlabel("월")
ax.set_ylabel("매출액")
plt.show()주요 설정
선 색상
color="royalblue"색상 이름을 사용할 수 있습니다.
color="red"
color="green"
color="orange"
color="black"16진수 색상 코드도 사용할 수 있습니다.
color="#3366CC"Matplotlib는 색상 이름, 16진수 코드, RGB와 RGBA 값 등 여러 형식의 색상 표현을 지원합니다.
선 굵기
linewidth=3또는 줄여서 작성할 수 있습니다.
lw=3선 모양
linestyle="--"| 설정 | 모양 |
|---|---|
| `"-"` | 실선 |
| `"--"` | 점선 |
| `"-."` | 일점쇄선 |
| `":"` | 짧은 점선 |
점 모양
marker="o"| 설정 | 모양 |
|---|---|
| `"o"` | 원 |
| `"s"` | 사각형 |
| `"^"` | 위쪽 삼각형 |
| `"v"` | 아래쪽 삼각형 |
| `"D"` | 다이아몬드 |
| `"x"` | 엑스 |
| `"*"` | 별 |
점 크기
markersize=8또는 다음과 같이 줄일 수 있습니다.
ms=8간단한 축약 표현
다음처럼 한 문자열 안에 색상, 점, 선 스타일을 표현할 수도 있습니다.
ax.plot(
months,
sales,
"ro--"
)의미는 다음과 같습니다.
r → red
o → 원형 마커
-- → 점선다만 설정이 많아질수록 명시적인 키워드 방식이 읽기 쉽습니다.
9. 여러 개의 선 그리기
온라인 매출과 오프라인 매출을 함께 비교해 보겠습니다.
import matplotlib.pyplot as plt
months = [1, 2, 3, 4, 5, 6]
online_sales = [
120,
135,
128,
162,
185,
210
]
offline_sales = [
150,
145,
138,
140,
152,
160
]
fig, ax = plt.subplots()
ax.plot(
months,
online_sales,
marker="o",
label="온라인"
)
ax.plot(
months,
offline_sales,
marker="s",
label="오프라인"
)
ax.set_title("판매 채널별 월간 매출")
ax.set_xlabel("월")
ax.set_ylabel("매출액")
ax.legend()
plt.show()같은 Axes에 `plot()`을 여러 번 호출하면 여러 선을 함께 표시할 수 있습니다.
ax.plot(months, online_sales)
ax.plot(months, offline_sales)단, 비교하는 데이터의 단위가 지나치게 다르면 한 그래프에 표시하지 않는 것이 좋습니다.
예를 들어 다음 데이터를 같은 y축에 표시하면 해석이 어려울 수 있습니다.
매출액: 수백만 원
구매 전환율: 2~5%단위가 다른 데이터를 함께 표현하려면 별도의 그래프를 사용하거나 보조축을 신중하게 검토해야 합니다.
10. 범례 표시하기
여러 선이나 막대를 함께 표시할 때는 각 데이터가 무엇인지 구분할 수 있도록 범례를 추가합니다.
ax.plot(
months,
online_sales,
label="온라인 매출"
)
ax.plot(
months,
offline_sales,
label="오프라인 매출"
)
ax.legend()범례는 각 그래프 요소의 `label` 값을 이용합니다.
label="온라인 매출"범례 위치를 지정할 수도 있습니다.
ax.legend(
loc="upper left"
)주요 위치는 다음과 같습니다.
upper left
upper right
lower left
lower right
center
bestax.legend(
loc="best"
)`best`를 사용하면 Matplotlib가 데이터와 최대한 겹치지 않는 위치를 선택합니다.
범례는 `label`이 지정된 그래프 요소를 자동으로 탐색할 수 있습니다. 밑줄로 시작하는 라벨은 자동 범례에서 제외됩니다.
11. 막대그래프 만들기
막대그래프는 서로 독립된 항목의 크기를 비교할 때 적합합니다.
import matplotlib.pyplot as plt
products = [
"키보드",
"마우스",
"모니터",
"USB 허브"
]
sales = [
42,
58,
25,
36
]
fig, ax = plt.subplots()
ax.bar(
products,
sales
)
ax.set_title("상품별 판매량")
ax.set_xlabel("상품")
ax.set_ylabel("판매량")
plt.show()막대그래프는 `bar()`로 만듭니다.
ax.bar(x값, 높이)공식 API에서 `bar()`는 x 위치에 높이와 너비를 가진 세로 막대를 생성하는 함수로 정의됩니다.
막대 색상 설정하기
ax.bar(
products,
sales,
color="cornflowerblue"
)각 막대에 서로 다른 색상을 지정할 수도 있습니다.
ax.bar(
products,
sales,
color=[
"royalblue",
"orange",
"green",
"tomato"
]
)막대 테두리 설정하기
ax.bar(
products,
sales,
edgecolor="black",
linewidth=1
)막대 너비 설정하기
ax.bar(
products,
sales,
width=0.6
)12. 가로 막대그래프 만들기
카테고리 이름이 길거나 항목이 많다면 가로 막대그래프가 더 읽기 좋습니다.
import matplotlib.pyplot as plt
categories = [
"전자기기 및 액세서리",
"생활용품",
"도서 및 교육",
"식품",
"스포츠용품"
]
sales = [
520,
380,
290,
450,
240
]
fig, ax = plt.subplots()
ax.barh(
categories,
sales
)
ax.set_title("카테고리별 매출")
ax.set_xlabel("매출액")
ax.set_ylabel("카테고리")
plt.show()가로 막대그래프는 `barh()`를 사용합니다.
ax.barh(
y값,
너비
)큰 값부터 위쪽에 표시하고 싶다면 데이터를 정렬하거나 y축을 뒤집을 수 있습니다.
ax.invert_yaxis()fig, ax = plt.subplots()
ax.barh(
categories,
sales
)
ax.invert_yaxis()
plt.show()항목이 여덟 개, 열 개, 스무 개로 늘어나기 시작하면 세로 막대의 글자들이 서로 어깨싸움을 벌입니다.
그럴 때는 가로 막대그래프가 좌석 배치를 깔끔하게 정리해 줍니다. 🪑
13. 막대 위에 숫자 표시하기
막대의 정확한 값을 그래프 위에 표시해 보겠습니다.
import matplotlib.pyplot as plt
products = [
"키보드",
"마우스",
"모니터",
"USB 허브"
]
sales = [
42,
58,
25,
36
]
fig, ax = plt.subplots()
bars = ax.bar(
products,
sales
)
ax.bar_label(
bars,
padding=3
)
ax.set_title("상품별 판매량")
ax.set_ylabel("판매량")
plt.show()`bar()`가 반환한 막대 객체를 변수에 저장합니다.
bars = ax.bar(
products,
sales
)그다음 `bar_label()`에 전달합니다.
ax.bar_label(
bars
)숫자 형식을 지정할 수도 있습니다.
ax.bar_label(
bars,
fmt="%d개",
padding=3
)직접 텍스트 표시하기
조금 더 세밀하게 조절하려면 반복문과 `text()`를 사용할 수 있습니다.
for bar in bars:
height = bar.get_height()
ax.text(
bar.get_x() + bar.get_width() / 2,
height + 1,
f"{height}개",
ha="center",
va="bottom"
)`text()`는 Axes의 특정 x, y 좌표에 문자열을 추가합니다.
14. 산점도 만들기
산점도는 두 숫자 변수 사이의 관계를 확인할 때 사용합니다.
광고비와 매출의 관계를 살펴보겠습니다.
import matplotlib.pyplot as plt
ad_cost = [
10,
15,
20,
25,
30,
35,
40
]
sales = [
100,
125,
150,
170,
210,
225,
260
]
fig, ax = plt.subplots()
ax.scatter(
ad_cost,
sales
)
ax.set_title("광고비와 매출의 관계")
ax.set_xlabel("광고비")
ax.set_ylabel("매출")
plt.show()산점도는 `scatter()`로 만듭니다.
ax.scatter(
x값,
y값
)공식 API에서 산점도는 x와 y 값의 관계를 점으로 표시하며, 점의 크기와 색상도 데이터에 따라 변경할 수 있습니다.
점 크기 설정하기
ax.scatter(
ad_cost,
sales,
s=100
)`s`는 점의 면적을 의미합니다.
점 투명도 설정하기
ax.scatter(
ad_cost,
sales,
alpha=0.6
)점이 많이 겹칠 때 투명도를 낮추면 데이터 밀도를 확인하기 쉽습니다.
점마다 크기 다르게 설정하기
customer_counts = [
20,
35,
45,
60,
80,
95,
120
]
ax.scatter(
ad_cost,
sales,
s=customer_counts
)점의 크기를 세 번째 변수로 표현할 수 있습니다.
단, 너무 많은 시각적 요소를 한 그래프에 넣으면 해석이 어려워질 수 있습니다.
그래프도 액세서리를 지나치게 달면 데이터보다 장식이 먼저 입장합니다.
15. 히스토그램 만들기
히스토그램은 숫자 데이터가 어느 구간에 많이 분포하는지 보여 줍니다.
학생 20명의 점수 데이터를 사용해 보겠습니다.
import matplotlib.pyplot as plt
scores = [
55,
62,
67,
68,
71,
73,
75,
75,
77,
78,
80,
81,
82,
84,
85,
88,
90,
91,
94,
98
]
fig, ax = plt.subplots()
ax.hist(
scores,
bins=5,
edgecolor="black"
)
ax.set_title("학생 점수 분포")
ax.set_xlabel("점수")
ax.set_ylabel("학생 수")
plt.show()bins란?
bins=5전체 데이터 범위를 몇 개의 구간으로 나눌지 지정합니다.
예를 들어 점수가 50점부터 100점까지라면 대략 다음처럼 나뉠 수 있습니다.
50~60
60~70
70~80
80~90
90~100`bins`가 너무 작으면 데이터의 세부 분포를 볼 수 없습니다.
bins=2반대로 너무 크면 그래프가 지나치게 들쭉날쭉해질 수 있습니다.
bins=50히스토그램의 `bins`는 숫자 데이터를 구간으로 나누고 각 구간에 포함된 값의 개수를 계산합니다. Matplotlib의 `hist()`는 내부적으로 NumPy의 히스토그램 계산을 사용합니다.
막대그래프와 히스토그램의 차이
막대그래프와 히스토그램은 모양이 비슷하지만 목적이 다릅니다.
| 구분 | 막대그래프 | 히스토그램 |
|---|---|---|
| 대상 | 카테고리 | 연속적인 숫자 |
| 예시 | 상품별 판매량 | 고객 나이 분포 |
| 막대 사이 | 보통 간격 있음 | 일반적으로 연결됨 |
| 주요 목적 | 항목 비교 | 분포 확인 |
키보드와 마우스 판매량 비교
→ 막대그래프
고객의 나이가 어느 구간에 많은지 확인
→ 히스토그램16. 원 그래프 만들기
원 그래프는 전체에서 각 항목이 차지하는 비율을 보여 줄 때 사용합니다.
import matplotlib.pyplot as plt
categories = [
"전자기기",
"생활용품",
"도서",
"식품"
]
sales = [
40,
25,
15,
20
]
fig, ax = plt.subplots()
ax.pie(
sales,
labels=categories,
autopct="%.1f%%"
)
ax.set_title("카테고리별 매출 비중")
plt.show()`pie()`에 전달한 값은 전체 합계를 기준으로 각 조각의 비율로 변환됩니다.
비율 표시하기
autopct="%.1f%%"소수점 첫째 자리까지 비율을 표시합니다.
40.0%
25.0%
15.0%
20.0%정수로 표시하려면 다음과 같이 작성합니다.
autopct="%.0f%%"특정 조각 강조하기
explode = [
0.1,
0,
0,
0
]
ax.pie(
sales,
labels=categories,
autopct="%.1f%%",
explode=explode
)첫 번째 조각이 원에서 조금 떨어져 표시됩니다.
시작 각도 변경하기
startangle=90ax.pie(
sales,
labels=categories,
autopct="%.1f%%",
startangle=90
)원 그래프 사용 시 주의점
원 그래프는 항목이 많아질수록 비교하기 어려워집니다.
항목 3~5개
→ 비교적 적합
항목 12개
→ 색상 피자 탄생비율 차이가 작거나 항목이 많다면 막대그래프가 더 정확하게 비교됩니다.
17. 상자 수염 그래프 만들기
상자 수염 그래프는 데이터의 중앙값, 사분위수, 분포 범위, 이상치를 확인할 때 사용합니다.
import matplotlib.pyplot as plt
scores = [
55,
62,
67,
68,
71,
73,
75,
75,
77,
78,
80,
81,
82,
84,
85,
88,
90,
91,
94,
100
]
fig, ax = plt.subplots()
ax.boxplot(scores)
ax.set_title("학생 점수 분포")
ax.set_ylabel("점수")
plt.show()상자 수염 그래프는 일반적으로 다음 내용을 보여 줍니다.
최솟값 범위
1사분위수
중앙값
3사분위수
최댓값 범위
이상치Matplotlib의 상자 수염 그래프에서 상자는 1사분위수부터 3사분위수까지를 나타내고, 상자 내부의 선은 중앙값을 나타냅니다. 기본 수염은 사분위 범위의 1.5배 안에 있는 데이터까지 확장됩니다.
여러 그룹 비교하기
class_a = [
70,
75,
78,
80,
82,
85,
90
]
class_b = [
60,
65,
68,
75,
85,
92,
98
]
fig, ax = plt.subplots()
ax.boxplot(
[
class_a,
class_b
],
tick_labels=[
"A반",
"B반"
]
)
ax.set_title("반별 점수 분포")
ax.set_ylabel("점수")
plt.show()A반과 B반의 평균만 비교하면 놓칠 수 있는 데이터 분산과 이상치를 함께 확인할 수 있습니다.
18. 여러 그래프 한 화면에 배치하기
한 화면에 여러 그래프를 배치하려면 `subplots()`를 사용합니다.
import matplotlib.pyplot as plt
fig, axes = plt.subplots(
2,
2,
figsize=(10, 8)
)
months = [1, 2, 3, 4, 5, 6]
sales = [120, 135, 128, 162, 185, 210]
products = [
"키보드",
"마우스",
"모니터"
]
quantities = [
42,
58,
25
]
scores = [
55,
62,
67,
71,
73,
78,
80,
82,
85,
88,
90,
94
]
ad_cost = [
10,
20,
30,
40
]
revenue = [
100,
160,
205,
270
]
axes[0, 0].plot(
months,
sales,
marker="o"
)
axes[0, 0].set_title(
"월별 매출"
)
axes[0, 1].bar(
products,
quantities
)
axes[0, 1].set_title(
"상품별 판매량"
)
axes[1, 0].hist(
scores,
bins=5,
edgecolor="black"
)
axes[1, 0].set_title(
"점수 분포"
)
axes[1, 1].scatter(
ad_cost,
revenue
)
axes[1, 1].set_title(
"광고비와 매출"
)
fig.tight_layout()
plt.show()subplots의 구조
fig, axes = plt.subplots(
행 개수,
열 개수
)fig, axes = plt.subplots(
2,
2
)다음과 같은 구조가 만들어집니다.
axes[0, 0] | axes[0, 1]
------------+------------
axes[1, 0] | axes[1, 1]Matplotlib는 하나의 Figure 안에 여러 Axes를 격자 형태로 배치할 수 있는 다양한 도구를 제공합니다.
그래프 사이 간격 정리하기
fig.tight_layout()제목, 축 이름, 눈금이 서로 겹치지 않도록 간격을 조정합니다.
보다 복잡한 레이아웃에서는 Figure를 만들 때 constrained layout을 사용할 수도 있습니다.
fig, axes = plt.subplots(
2,
2,
figsize=(10, 8),
layout="constrained"
)공식 문서는 복잡한 레이아웃과 색상 막대를 포함한 구성에서 constrained layout을 권장되는 배치 방식으로 안내합니다.
19. 그래프 크기와 해상도 설정하기
그래프 크기 설정하기
fig, ax = plt.subplots(
figsize=(10, 6)
)`figsize`는 인치 단위의 가로와 세로 크기입니다.
figsize=(가로, 세로)figsize=(12, 5)가로가 긴 그래프를 만듭니다.
figsize=(6, 8)세로가 긴 그래프를 만듭니다.
해상도 설정하기
fig, ax = plt.subplots(
figsize=(10, 6),
dpi=150
)`dpi`는 인치당 점의 개수를 의미합니다.
값이 높을수록 화면과 저장 이미지가 더 선명해지지만 파일 크기도 커질 수 있습니다.
화면 확인용
→ 100~150 DPI
블로그 이미지
→ 150~200 DPI
인쇄 자료
→ 300 DPI 이상 검토그래프가 너무 작으면 글자가 압축되고, 너무 크면 거대한 벽보처럼 보입니다.
데이터에 맞는 캔버스 크기를 선택해야 합니다.
20. 축의 범위와 눈금 설정하기
x축 범위 설정하기
ax.set_xlim(
1,
6
)y축 범위 설정하기
ax.set_ylim(
0,
250
)전체 코드:
import matplotlib.pyplot as plt
months = [1, 2, 3, 4, 5, 6]
sales = [120, 135, 128, 162, 185, 210]
fig, ax = plt.subplots()
ax.plot(
months,
sales,
marker="o"
)
ax.set_xlim(
1,
6
)
ax.set_ylim(
0,
250
)
plt.show()눈금 위치 설정하기
ax.set_xticks(
[1, 2, 3, 4, 5, 6]
)눈금 이름 설정하기
ax.set_xticks(
[1, 2, 3, 4, 5, 6],
labels=[
"1월",
"2월",
"3월",
"4월",
"5월",
"6월"
]
)눈금 글자 회전하기
카테고리 이름이 길면 글자를 회전할 수 있습니다.
ax.tick_params(
axis="x",
labelrotation=45
)또는 다음과 같이 작성할 수 있습니다.
plt.xticks(
rotation=45
)y축 천 단위 쉼표 표시하기
from matplotlib.ticker import StrMethodFormatter
ax.yaxis.set_major_formatter(
StrMethodFormatter(
"{x:,.0f}"
)
)금액 단위를 함께 표시하려면 다음과 같이 작성할 수 있습니다.
from matplotlib.ticker import FuncFormatter
def won_formatter(
value,
position
):
return f"{value:,.0f}원"
ax.yaxis.set_major_formatter(
FuncFormatter(
won_formatter
)
)21. 격자 표시하기
격자는 값의 위치를 보다 쉽게 읽도록 도와줍니다.
ax.grid()y축 방향의 가로 격자만 표시하려면 다음과 같이 작성합니다.
ax.grid(
axis="y"
)격자 스타일도 조절할 수 있습니다.
ax.grid(
axis="y",
linestyle="--",
alpha=0.5
)그래프 요소 뒤로 격자 보내기
ax.set_axisbelow(True)fig, ax = plt.subplots()
ax.bar(
products,
sales
)
ax.grid(
axis="y",
linestyle="--",
alpha=0.4
)
ax.set_axisbelow(True)
plt.show()격자가 너무 진하면 데이터보다 격자가 먼저 보입니다.
격자는 주연 배우가 아니라 바닥의 희미한 안내선 정도가 적당합니다.
22. 그래프에 설명과 화살표 추가하기
특정 데이터에 설명을 추가하면 그래프가 전달하는 메시지를 더욱 분명하게 만들 수 있습니다.
import matplotlib.pyplot as plt
months = [1, 2, 3, 4, 5, 6]
sales = [120, 135, 128, 162, 185, 210]
fig, ax = plt.subplots()
ax.plot(
months,
sales,
marker="o"
)
ax.annotate(
"3월 매출 감소",
xy=(3, 128),
xytext=(3.5, 105),
arrowprops={
"arrowstyle": "->"
}
)
ax.annotate(
"상반기 최고 매출",
xy=(6, 210),
xytext=(4.5, 230),
arrowprops={
"arrowstyle": "->"
}
)
ax.set_title(
"월별 매출 변화"
)
ax.set_xlabel("월")
ax.set_ylabel("매출액")
plt.show()주요 설정
xy=(3, 128)화살표가 가리킬 실제 데이터 위치입니다.
xytext=(3.5, 105)설명 문구를 표시할 위치입니다.
arrowprops={
"arrowstyle": "->"
}화살표 모양을 설정합니다.
그래프의 모든 점에 설명을 붙일 필요는 없습니다.
중요한 변화, 최고점, 최저점, 이상치처럼 해석에 필요한 부분만 강조하는 것이 좋습니다.
모든 데이터가 동시에 마이크를 잡으면 그래프는 토론장이 아니라 시장통이 됩니다. 🎙️
23. 한글 깨짐 해결하기
Matplotlib에서 한글 제목을 입력하면 다음과 같이 네모 상자가 나타날 수 있습니다.
□□□□ □□기본 글꼴이 해당 한글 문자를 지원하지 않기 때문입니다. Matplotlib의 기본 글꼴은 DejaVu Sans이며, 지원하지 않는 문자 체계는 사용자가 다른 글꼴을 설정해야 할 수 있습니다.
한글 글꼴은 운영체제에 설치된 글꼴 중 하나를 지정해야 합니다.
Windows
import matplotlib.pyplot as plt
plt.rcParams[
"font.family"
] = "Malgun Gothic"
plt.rcParams[
"axes.unicode_minus"
] = FalsemacOS
import matplotlib.pyplot as plt
plt.rcParams[
"font.family"
] = "AppleGothic"
plt.rcParams[
"axes.unicode_minus"
] = FalseLinux
Linux에서는 별도로 설치한 한글 글꼴을 지정할 수 있습니다.
import matplotlib.pyplot as plt
plt.rcParams[
"font.family"
] = "NanumGothic"
plt.rcParams[
"axes.unicode_minus"
] = False설치된 글꼴 확인하기
from matplotlib import font_manager
font_names = sorted({
font.name
for font in font_manager.fontManager.ttflist
})
for font_name in font_names:
if (
"Gothic" in font_name
or "Nanum" in font_name
or "Noto" in font_name
):
print(font_name)운영체제별 한글 글꼴 자동 선택하기
import matplotlib.pyplot as plt
from matplotlib import font_manager
def configure_korean_font() -> None:
installed_fonts = {
font.name
for font in font_manager.fontManager.ttflist
}
candidates = [
"Malgun Gothic",
"AppleGothic",
"NanumGothic",
"Noto Sans CJK KR",
"Noto Sans KR"
]
for font_name in candidates:
if font_name in installed_fonts:
plt.rcParams[
"font.family"
] = font_name
break
plt.rcParams[
"axes.unicode_minus"
] = False
configure_korean_font()Matplotlib는 `rcParams`를 이용해 기본 글꼴 계열을 설정할 수 있으며, 시스템에 설치된 특정 글꼴 이름을 지정할 수도 있습니다.
`axes.unicode_minus=False`는 음수 부호가 한글 글꼴에서 깨지는 현상을 방지할 때 자주 사용합니다.
24. 스타일 적용하기
Matplotlib는 미리 준비된 스타일을 적용할 수 있습니다.
import matplotlib.pyplot as plt
plt.style.use(
"ggplot"
)그다음 평소처럼 그래프를 작성합니다.
fig, ax = plt.subplots()
ax.plot(
[1, 2, 3, 4],
[10, 18, 15, 25],
marker="o"
)
plt.show()사용 가능한 스타일 확인하기
import matplotlib.pyplot as plt
print(
plt.style.available
)스타일 이름은 설치된 Matplotlib 환경에 따라 확인해야 합니다.
공식 스타일 참고 문서에서도 `plt.style.use()`로 스타일을 적용하고 `matplotlib.style.available`에서 사용 가능한 스타일 목록을 확인할 수 있다고 안내합니다.
스타일을 특정 구간에만 적용하기
import matplotlib.pyplot as plt
with plt.style.context(
"ggplot"
):
fig, ax = plt.subplots()
ax.plot(
[1, 2, 3, 4],
[10, 18, 15, 25]
)
plt.show()`with` 블록 밖에서는 기존 스타일로 돌아갑니다.
rcParams로 기본 설정 변경하기
import matplotlib.pyplot as plt
plt.rcParams[
"figure.figsize"
] = (10, 6)
plt.rcParams[
"axes.titlesize"
] = 16
plt.rcParams[
"axes.labelsize"
] = 12
plt.rcParams[
"lines.linewidth"
] = 2Matplotlib의 사용자 지정 설정은 런타임의 `rcParams`, 스타일 시트, `matplotlibrc` 설정 파일을 통해 관리할 수 있습니다. 런타임 설정이 스타일 시트보다 우선 적용됩니다.
25. 그래프 이미지로 저장하기
그래프를 화면에만 표시하지 않고 이미지 파일로 저장할 수 있습니다.
import matplotlib.pyplot as plt
fig, ax = plt.subplots()
ax.plot(
[1, 2, 3, 4],
[10, 20, 15, 30]
)
ax.set_title(
"월별 매출"
)
fig.savefig(
"monthly_sales.png"
)`savefig()`는 현재 Figure를 이미지 또는 벡터 그래픽 파일로 저장합니다.
해상도 지정하기
fig.savefig(
"monthly_sales.png",
dpi=300
)불필요한 여백 줄이기
fig.savefig(
"monthly_sales.png",
dpi=300,
bbox_inches="tight"
)배경을 투명하게 저장하기
fig.savefig(
"monthly_sales.png",
transparent=True
)다양한 파일 형식
fig.savefig(
"chart.png"
)
fig.savefig(
"chart.jpg"
)
fig.savefig(
"chart.svg"
)
fig.savefig(
"chart.pdf"
)PNG
→ 블로그와 웹 이미지
JPG
→ 사진 중심 문서
SVG
→ 확대해도 깨지지 않는 벡터 이미지
PDF
→ 인쇄와 보고서show보다 먼저 저장하기
환경에 따라 `plt.show()`를 호출한 후 Figure 상태가 달라질 수 있으므로 저장 작업을 먼저 수행하는 편이 안전합니다.
fig.savefig(
"chart.png",
dpi=300,
bbox_inches="tight"
)
plt.show()공식 `show()` 문서에서도 화면을 표시하면서 저장하려는 경우 `show()`보다 먼저 `savefig()`를 호출하도록 안내합니다.
26. pandas와 Matplotlib 함께 사용하기
지난 시간에 배운 pandas DataFrame에서 바로 그래프를 만들 수 있습니다.
import pandas as pd
import matplotlib.pyplot as plt
data = {
"월": [
"1월",
"2월",
"3월",
"4월",
"5월",
"6월"
],
"매출": [
120,
135,
128,
162,
185,
210
]
}
df = pd.DataFrame(data)
df.plot(
x="월",
y="매출",
kind="line",
marker="o"
)
plt.title(
"월별 매출"
)
plt.ylabel(
"매출액"
)
plt.show()pandas의 `plot()`은 내부적으로 Matplotlib를 이용해 그래프를 생성합니다.
막대그래프
df.plot(
x="월",
y="매출",
kind="bar"
)
plt.show()가로 막대그래프
df.plot(
x="월",
y="매출",
kind="barh"
)
plt.show()히스토그램
df["매출"].plot(
kind="hist",
bins=5
)
plt.show()pandas 결과를 Axes에 그리기
객체 지향 방식과 결합하면 더 세밀하게 조절할 수 있습니다.
import pandas as pd
import matplotlib.pyplot as plt
data = {
"월": [
"1월",
"2월",
"3월",
"4월",
"5월",
"6월"
],
"온라인": [
120,
135,
128,
162,
185,
210
],
"오프라인": [
150,
145,
138,
140,
152,
160
]
}
df = pd.DataFrame(data)
fig, ax = plt.subplots(
figsize=(10, 6)
)
df.plot(
x="월",
y=[
"온라인",
"오프라인"
],
marker="o",
ax=ax
)
ax.set_title(
"판매 채널별 월간 매출"
)
ax.set_xlabel("월")
ax.set_ylabel("매출액")
ax.grid(
axis="y",
alpha=0.3
)
plt.show()`ax=ax`를 지정하면 pandas가 새로운 그래프를 만들지 않고 우리가 준비한 Axes에 데이터를 그립니다.
pandas가 데이터를 정리하는 주방장이라면 Matplotlib는 완성된 요리를 보기 좋게 담는 플레이팅 담당입니다. 🍽️
27. 그래프 선택 기준
그래프는 예쁘다고 선택하는 것이 아닙니다.
데이터에서 무엇을 전달하고 싶은지에 따라 선택해야 합니다.
시간에 따른 변화
월별 매출
일별 방문자 수
연도별 인구 변화
서버 CPU 사용률추천 그래프:
선 그래프항목별 크기 비교
상품별 판매량
부서별 비용
언어별 점수
지역별 주문 건수추천 그래프:
막대그래프
가로 막대그래프두 숫자 변수의 관계
광고비와 매출
공부 시간과 시험 점수
상품 가격과 판매량
키와 몸무게추천 그래프:
산점도데이터 분포
고객 나이 분포
학생 점수 분포
배송 시간 분포
상품 가격 분포추천 그래프:
히스토그램
상자 수염 그래프전체 구성 비율
채널별 매출 비중
예산 구성
시장 점유율추천 그래프:
원 그래프
막대그래프빠른 선택표
| 분석 목적 | 추천 그래프 |
|---|---|
| 시간의 흐름 | 선 그래프 |
| 항목 비교 | 막대그래프 |
| 순위 비교 | 정렬된 가로 막대그래프 |
| 두 변수 관계 | 산점도 |
| 숫자 분포 | 히스토그램 |
| 중앙값과 이상치 | 상자 수염 그래프 |
| 전체 비율 | 원 그래프 |
| 여러 지표 비교 | 여러 Axes 또는 별도 그래프 |
28. 잘못된 데이터 시각화 피하기
그래프는 데이터를 이해하게 만들 수도 있지만, 잘못 사용하면 데이터를 왜곡할 수도 있습니다.
막대그래프의 y축을 중간에서 시작하기
다음 데이터가 있다고 가정해 보겠습니다.
A 상품: 95
B 상품: 100y축을 90부터 시작하면 B 상품이 A 상품보다 몇 배나 커 보일 수 있습니다.
ax.set_ylim(
90,
101
)막대그래프에서는 막대 길이가 값의 크기를 의미하므로 특별한 이유가 없다면 y축을 0부터 시작하는 편이 좋습니다.
ax.set_ylim(
0,
110
)너무 많은 색상 사용하기
항목마다 강한 색상을 사용하면 그래프가 정보보다 색상 경연장이 됩니다.
핵심 데이터만 강조하고 나머지는 차분하게 표현하는 것이 좋습니다.
원 그래프에 너무 많은 항목 넣기
상품 15개의 판매 비율
→ 원 그래프보다 막대그래프3차원 효과로 크기 왜곡하기
3차원 원 그래프와 입체 막대그래프는 일부 영역을 실제보다 크게 보이게 만들 수 있습니다.
분석 그래프에서는 단순한 2차원 표현이 더 정확한 경우가 많습니다.
제목과 단위 생략하기
다음 그래프 제목은 정보가 부족합니다.
판매량다음처럼 기간과 단위를 명확히 표시합니다.
2026년 상반기 상품별 판매량
단위: 개모든 데이터를 한 그래프에 넣기
매출
사용자 수
전환율
광고비
반품률
서버 응답 시간모든 지표를 하나의 그래프에 넣으면 데이터들이 한 이불을 두고 싸우게 됩니다.
서로 관련 있는 데이터만 묶고 필요하면 여러 그래프로 나누어야 합니다.
29. 실전 미니 프로젝트: 온라인 쇼핑몰 판매 분석 대시보드
지금까지 배운 내용을 이용해 CSV 판매 데이터를 읽고 분석한 뒤, 네 개의 그래프로 구성된 판매 분석 이미지를 만들어 보겠습니다.
프로젝트 목표
다음 작업을 수행합니다.
CSV 파일 읽기
→ 날짜와 숫자 데이터 정리
→ 월별 매출 계산
→ 카테고리별 매출 계산
→ 상품별 판매량 계산
→ 가격 분포 분석
→ 4개의 그래프 생성
→ PNG 이미지 저장예제 CSV 파일
`shopping_sales.csv` 파일을 다음과 같이 준비합니다.
주문일,상품명,카테고리,가격,판매량
2026-01-05,무선 키보드,전자기기,35000,12
2026-01-12,텀블러,생활용품,18000,20
2026-02-03,마우스,전자기기,25000,18
2026-02-18,노트북 거치대,전자기기,42000,8
2026-03-02,손목 받침대,생활용품,15000,25
2026-03-20,Python 입문서,도서,28000,15
2026-04-07,모니터,전자기기,250000,4
2026-04-22,텀블러,생활용품,18000,22
2026-05-09,USB 허브,전자기기,29000,16
2026-05-25,SQL 실전서,도서,32000,14
2026-06-08,기계식 키보드,전자기기,89000,10
2026-06-21,데스크 매트,생활용품,24000,19전체 코드
from pathlib import Path
import matplotlib.pyplot as plt
import pandas as pd
from matplotlib import font_manager
from matplotlib.ticker import FuncFormatter
INPUT_FILE = Path(
"shopping_sales.csv"
)
OUTPUT_FILE = Path(
"sales_dashboard.png"
)
def configure_korean_font() -> None:
"""설치된 한글 글꼴을 찾아 Matplotlib에 설정합니다."""
installed_fonts = {
font.name
for font in font_manager.fontManager.ttflist
}
candidates = [
"Malgun Gothic",
"AppleGothic",
"NanumGothic",
"Noto Sans CJK KR",
"Noto Sans KR"
]
for font_name in candidates:
if font_name in installed_fonts:
plt.rcParams[
"font.family"
] = font_name
break
plt.rcParams[
"axes.unicode_minus"
] = False
def format_won(
value: float,
position: int
) -> str:
"""숫자를 원 단위 문자열로 변환합니다."""
return f"{value:,.0f}원"
def load_and_clean_data(
file_path: Path
) -> pd.DataFrame:
"""판매 데이터를 읽고 분석 가능한 형태로 정리합니다."""
if not file_path.exists():
raise FileNotFoundError(
f"파일을 찾을 수 없습니다: {file_path}"
)
df = pd.read_csv(
file_path
)
required_columns = {
"주문일",
"상품명",
"카테고리",
"가격",
"판매량"
}
missing_columns = (
required_columns
- set(df.columns)
)
if missing_columns:
raise ValueError(
"필수 열이 없습니다: "
+ ", ".join(
sorted(missing_columns)
)
)
df["주문일"] = pd.to_datetime(
df["주문일"],
errors="coerce"
)
df["가격"] = pd.to_numeric(
df["가격"],
errors="coerce"
)
df["판매량"] = pd.to_numeric(
df["판매량"],
errors="coerce"
)
df = df.dropna(
subset=[
"주문일",
"상품명",
"카테고리",
"가격",
"판매량"
]
).copy()
df["매출"] = (
df["가격"]
* df["판매량"]
)
df["주문월"] = (
df["주문일"]
.dt.to_period("M")
.astype("string")
)
return df
def create_dashboard(
df: pd.DataFrame,
output_file: Path
) -> None:
"""판매 분석 그래프를 생성하고 이미지로 저장합니다."""
monthly_sales = (
df
.groupby(
"주문월",
as_index=False
)["매출"]
.sum()
)
category_sales = (
df
.groupby(
"카테고리",
as_index=False
)["매출"]
.sum()
.sort_values(
"매출",
ascending=True
)
)
product_quantity = (
df
.groupby(
"상품명",
as_index=False
)["판매량"]
.sum()
.sort_values(
"판매량",
ascending=False
)
.head(5)
)
fig, axes = plt.subplots(
2,
2,
figsize=(14, 10),
layout="constrained"
)
won_formatter = FuncFormatter(
format_won
)
# 월별 매출 선 그래프
axes[0, 0].plot(
monthly_sales["주문월"],
monthly_sales["매출"],
marker="o",
linewidth=2.5
)
axes[0, 0].set_title(
"월별 매출 추이"
)
axes[0, 0].set_xlabel(
"주문월"
)
axes[0, 0].set_ylabel(
"매출"
)
axes[0, 0].yaxis.set_major_formatter(
won_formatter
)
axes[0, 0].grid(
axis="y",
linestyle="--",
alpha=0.4
)
# 카테고리별 매출 가로 막대그래프
category_bars = axes[0, 1].barh(
category_sales["카테고리"],
category_sales["매출"]
)
axes[0, 1].set_title(
"카테고리별 매출"
)
axes[0, 1].set_xlabel(
"매출"
)
axes[0, 1].xaxis.set_major_formatter(
won_formatter
)
axes[0, 1].bar_label(
category_bars,
labels=[
f"{value:,.0f}원"
for value
in category_sales["매출"]
],
padding=3
)
# 판매량 상위 상품 막대그래프
product_bars = axes[1, 0].bar(
product_quantity["상품명"],
product_quantity["판매량"]
)
axes[1, 0].set_title(
"판매량 상위 5개 상품"
)
axes[1, 0].set_xlabel(
"상품명"
)
axes[1, 0].set_ylabel(
"판매량"
)
axes[1, 0].tick_params(
axis="x",
labelrotation=30
)
axes[1, 0].bar_label(
product_bars,
fmt="%.0f개",
padding=3
)
# 상품 가격 히스토그램
axes[1, 1].hist(
df["가격"],
bins=6,
edgecolor="black",
alpha=0.8
)
axes[1, 1].set_title(
"상품 가격 분포"
)
axes[1, 1].set_xlabel(
"가격"
)
axes[1, 1].set_ylabel(
"상품 수"
)
axes[1, 1].xaxis.set_major_formatter(
won_formatter
)
fig.suptitle(
"2026년 상반기 온라인 쇼핑몰 판매 분석",
fontsize=18
)
fig.savefig(
output_file,
dpi=300,
bbox_inches="tight"
)
plt.show()
def main() -> None:
try:
configure_korean_font()
sales_df = load_and_clean_data(
INPUT_FILE
)
create_dashboard(
sales_df,
OUTPUT_FILE
)
print(
"판매 분석 그래프 생성 완료"
)
print(
f"저장 위치: {OUTPUT_FILE.resolve()}"
)
except (
FileNotFoundError,
ValueError
) as error:
print(
f"입력 데이터 오류: {error}"
)
except Exception as error:
print(
f"그래프 생성 중 오류 발생: {error}"
)
if __name__ == "__main__":
main()결과 구성
실행하면 하나의 Figure 안에 다음 그래프가 배치됩니다.
┌────────────────────┬────────────────────┐
│ 월별 매출 추이 │ 카테고리별 매출 │
│ 선 그래프 │ 가로 막대그래프 │
├────────────────────┼────────────────────┤
│ 판매량 상위 상품 │ 상품 가격 분포 │
│ 막대그래프 │ 히스토그램 │
└────────────────────┴────────────────────┘그리고 다음 이미지 파일이 생성됩니다.
sales_dashboard.png이제 숫자로만 존재하던 CSV 파일이 한 장의 판매 분석 보고서로 변신했습니다.
엑셀 셀 안에서 조용히 살던 데이터들이 드디어 단체 사진을 찍은 셈입니다. 📸
30. 자주 발생하는 오류
오류 1. Matplotlib를 찾을 수 없음
ModuleNotFoundError:
No module named 'matplotlib'해결 방법
python -m pip install matplotlib현재 실행 중인 Python과 Matplotlib를 설치한 Python이 같은 환경인지 확인해야 합니다.
python -m pip show matplotlib오류 2. 그래프 창이 나타나지 않음
코드 마지막에 `plt.show()`가 있는지 확인합니다.
plt.show()Jupyter Notebook에서는 다음 명령을 사용할 수 있습니다.
%matplotlib inline일부 서버나 터미널 환경에서는 화면 출력용 백엔드를 사용할 수 없을 수 있습니다.
이 경우 그래프를 파일로 저장합니다.
fig.savefig(
"chart.png"
)Matplotlib의 백엔드는 그래프를 화면에 표시하거나 파일로 출력하는 역할을 담당합니다.
오류 3. x와 y 데이터 길이가 다름
ValueError:
x and y must have same first dimension다음 데이터의 길이를 확인합니다.
months = [
1,
2,
3,
4
]
sales = [
100,
120,
130
]months: 4개
sales: 3개x와 y는 서로 대응해야 하므로 길이가 같아야 합니다.
print(
len(months)
)
print(
len(sales)
)오류 4. 한글이 네모로 표시됨
설치된 한글 글꼴을 지정합니다.
plt.rcParams[
"font.family"
] = "Malgun Gothic"macOS에서는 다음 글꼴을 검토합니다.
plt.rcParams[
"font.family"
] = "AppleGothic"실제 설치 여부를 반드시 확인해야 합니다.
오류 5. 음수 부호가 깨짐
plt.rcParams[
"axes.unicode_minus"
] = False한글 글꼴을 설정할 때 함께 지정합니다.
오류 6. 제목과 축 이름이 잘림
fig.tight_layout()또는 다음과 같이 Figure를 생성합니다.
fig, ax = plt.subplots(
layout="constrained"
)이미지로 저장할 때는 다음 옵션을 추가합니다.
fig.savefig(
"chart.png",
bbox_inches="tight"
)오류 7. 이전 그래프가 다음 그래프와 겹침
반복문에서 여러 그래프를 만들 때는 Figure를 닫아야 합니다.
for index in range(5):
fig, ax = plt.subplots()
ax.plot(
[1, 2, 3],
[
index,
index + 1,
index + 2
]
)
fig.savefig(
f"chart_{index}.png"
)
plt.close(fig)`plt.close(fig)`를 호출하면 사용이 끝난 Figure를 정리할 수 있습니다.
오류 8. 범례가 표시되지 않음
그래프 요소에 `label`이 지정되었는지 확인합니다.
ax.plot(
months,
sales,
label="매출"
)
ax.legend()다음처럼 `label` 없이 `legend()`만 호출하면 범례가 비어 있을 수 있습니다.
ax.plot(
months,
sales
)
ax.legend()오류 9. 저장한 이미지가 비어 있음
`show()`보다 먼저 저장합니다.
fig.savefig(
"chart.png",
dpi=300,
bbox_inches="tight"
)
plt.show()31. 연습 문제
문제 1
다음 데이터를 이용해 선 그래프를 만들어 보세요.
days = [
"월",
"화",
"수",
"목",
"금"
]
visitors = [
120,
150,
135,
170,
210
]힌트
ax.plot(
days,
visitors
)문제 2
선 그래프에 다음 설정을 추가해 보세요.
제목: 요일별 방문자 수
x축: 요일
y축: 방문자 수
원형 마커
점선문제 3
다음 데이터를 막대그래프로 표현해 보세요.
languages = [
"Python",
"Java",
"JavaScript",
"Go"
]
scores = [
90,
75,
82,
68
]문제 4
막대 위에 각 점수를 표시해 보세요.
힌트
bars = ax.bar(
languages,
scores
)
ax.bar_label(
bars
)문제 5
다음 데이터로 산점도를 만들어 보세요.
study_hours = [
1,
2,
3,
4,
5,
6
]
exam_scores = [
55,
62,
70,
78,
86,
93
]공부 시간과 시험 점수 사이에 어떤 관계가 있는지 생각해 보세요.
문제 6
다음 나이 데이터의 분포를 히스토그램으로 표현해 보세요.
ages = [
18,
19,
20,
20,
21,
22,
24,
25,
25,
27,
30,
31,
35,
38,
42
]`bins` 값을 3, 5, 10으로 변경하면서 그래프의 차이를 비교해 보세요.
문제 7
다음 데이터를 원 그래프로 표현해 보세요.
channels = [
"검색",
"SNS",
"직접 방문",
"광고"
]
visitors = [
40,
30,
20,
10
]비율을 소수점 첫째 자리까지 표시해 보세요.
문제 8
하나의 Figure에 다음 두 그래프를 나란히 배치해 보세요.
왼쪽
→ 월별 매출 선 그래프
오른쪽
→ 상품별 판매량 막대그래프힌트
fig, axes = plt.subplots(
1,
2
)문제 9
완성한 그래프를 다음 조건으로 저장해 보세요.
파일명: report.png
해상도: 300 DPI
불필요한 여백 제거힌트
fig.savefig(
"report.png",
dpi=300,
bbox_inches="tight"
)문제 10
pandas로 CSV 파일을 읽고 `카테고리`별 `매출` 합계를 계산한 뒤 막대그래프로 표현해 보세요.
힌트
summary = (
df
.groupby("카테고리")["매출"]
.sum()
)
summary.plot(
kind="bar"
)32. 핵심 요약
Matplotlib 불러오기
import matplotlib.pyplot as pltFigure와 Axes 만들기
fig, ax = plt.subplots()선 그래프
ax.plot(
x,
y
)막대그래프
ax.bar(
categories,
values
)가로 막대그래프
ax.barh(
categories,
values
)산점도
ax.scatter(
x,
y
)히스토그램
ax.hist(
values,
bins=10
)원 그래프
ax.pie(
values,
labels=labels,
autopct="%.1f%%"
)상자 수염 그래프
ax.boxplot(
values
)제목과 축 이름
ax.set_title(
"그래프 제목"
)
ax.set_xlabel(
"x축 이름"
)
ax.set_ylabel(
"y축 이름"
)범례
ax.plot(
x,
y,
label="매출"
)
ax.legend()격자
ax.grid(
axis="y",
alpha=0.3
)여러 그래프 배치
fig, axes = plt.subplots(
2,
2
)이미지 저장
fig.savefig(
"chart.png",
dpi=300,
bbox_inches="tight"
)화면 표시
plt.show()Figure 정리
plt.close(fig)33. 마무리
이번 시간에는 Matplotlib를 이용해 숫자 데이터를 다양한 그래프로 변환하는 방법을 알아보았습니다.
Matplotlib를 사용하면 다음과 같은 작업을 할 수 있습니다.
* 시간에 따른 변화 표현* 항목별 값 비교* 두 변수 사이의 관계 확인* 데이터 분포 분석* 전체 구성 비율 표현* 중앙값과 이상치 확인* 여러 그래프를 하나의 화면에 배치* pandas 분석 결과 시각화* 블로그와 보고서용 이미지 저장
Matplotlib를 처음 접하면 다음과 같은 코드가 복잡해 보일 수 있습니다.
fig, ax = plt.subplots()
ax.plot(
months,
sales,
marker="o"
)
ax.set_title(
"월별 매출"
)
ax.set_xlabel("월")
ax.set_ylabel("매출액")
ax.grid(
axis="y",
alpha=0.3
)
fig.savefig(
"monthly_sales.png",
dpi=300,
bbox_inches="tight"
)
plt.show()하지만 코드를 순서대로 읽으면 하나의 그래프를 만드는 과정이 보입니다.
도화지를 준비한다
→ 데이터를 그린다
→ 제목을 붙인다
→ 축 이름을 붙인다
→ 격자를 추가한다
→ 이미지로 저장한다
→ 화면에 보여 준다Matplotlib의 핵심은 화려한 색상이나 복잡한 효과가 아닙니다.
데이터가 전달하려는 내용을 가장 빠르고 정확하게 보여 주는 것입니다.
시간의 변화인가?
→ 선 그래프
항목의 비교인가?
→ 막대그래프
두 값의 관계인가?
→ 산점도
값의 분포인가?
→ 히스토그램
전체의 비율인가?
→ 원 그래프pandas가 수천 개의 데이터를 정리해 표로 만들었다면, Matplotlib는 그 표에 목소리와 표정을 만들어 줍니다.
숫자는 말이 없지만 그래프에 올라가는 순간 꽤 수다스러워집니다.
우리가 해야 할 일은 그 이야기가 왜곡되지 않도록 좋은 무대를 준비하는 것입니다. 📈✨
다음 편 예고
[Python 완전정복 시리즈 #26] NumPy 완벽 이해하기 | 수백만 개의 숫자를 빠르게 계산하는 배열의 마법
다음 시간에는 Python 데이터 분석과 인공지능 생태계의 핵심 기반인 NumPy를 알아봅니다.
일반 Python 리스트와 NumPy 배열의 차이부터 배열 생성, 인덱싱, 형태 변경, 브로드캐스팅, 통계 계산까지 숫자 군단을 빠르게 움직이는 방법을 배워 보겠습니다.
#Python #파이썬 #Python강좌 #파이썬기초 #Matplotlib #데이터시각화 #그래프그리기 #선그래프 #막대그래프 #산점도 #히스토그램 #원그래프 #pandas #데이터분석 #파이썬데이터분석 #CSV분석 #Excel자동화 #코딩공부 #프로그래밍
