Matplotlib 기초 - 데이터 시각화의 핵심 도구
Matplotlib 기초 - 데이터 시각화의 핵심 도구
Matplotlib 기초 - 데이터 시각화의 핵심 도구
개요
Matplotlib은 Python에서 가장 널리 사용되는 데이터 시각화 라이브러리입니다:
- 기본 구조: 그래프 생성과 커스터마이징
- 폰트 설정: 한글 폰트 설정과 스타일링
- 시각화: 히스토그램, 박스플롯, 히트맵 활용
- 실무 적용: 효과적인 데이터 시각화 기법
1. Matplotlib 기본 구조
1-1. 기본 그래프 생성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import matplotlib.pyplot as plt
import numpy as np
# 기본 선 그래프
plt.plot([10, 20, 30, 40])
plt.show()
# y값만 지정 (x는 자동으로 0, 1, 2, 3...)
y = [10, 20, 30, 40]
plt.plot(y)
plt.show()
# x, y값 모두 지정
x = [1, 2, 3, 4]
y = [12, 43, 25, 15]
plt.plot(x, y)
plt.show()
1-2. 그래프 스타일링
1
2
3
4
5
6
7
8
9
10
11
# 제목, 색상, 선 스타일, 범례 설정
plt.title('Color and Line Style Example')
plt.plot([10, 20, 30, 40],
color='skyblue',
linestyle='--', # 또는 ls='--'
label='skyblue line')
plt.plot([40, 30, 20, 10],
color='pink',
label='pink line')
plt.legend() # 범례 표시
plt.show()
1-3. 마커 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
plt.title('Marker Examples')
# 빨간색 원형 마커
plt.plot([10, 20, 30, 40], 'r.', label='circle marker')
# 초록색 삼각형 마커
plt.plot([40, 30, 20, 10], 'g^', label='triangle up marker')
plt.legend()
plt.show()
# 다양한 마커 스타일
markers = ['o', 's', '^', 'v', '<', '>', 'p', '*', 'h', 'H', '+', 'x', 'D', 'd']
colors = ['red', 'blue', 'green', 'orange', 'purple', 'brown', 'pink', 'gray']
plt.figure(figsize=(12, 8))
for i, (marker, color) in enumerate(zip(markers, colors)):
plt.subplot(3, 5, i+1)
x = np.linspace(0, 10, 10)
y = np.sin(x) + i
plt.plot(x, y, marker=marker, color=color, markersize=8)
plt.title(f'{marker} - {color}')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
1-4. 축 범위 설정
1
2
3
4
5
6
y = [10, 20, 30, 40]
plt.plot(y)
plt.xlim((-5, 5)) # x축 범위 지정
plt.ylim((-10, 60)) # y축 범위 지정
plt.grid(True)
plt.show()
2. 여러 개의 그래프
2-1. subplot을 활용한 다중 그래프
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import numpy as np
import matplotlib.pyplot as plt
x1 = np.arange(1, 11)
y1 = np.exp(-x1)
# 2행 1열 구조
plt.subplot(2, 1, 1) # nrows=2, ncols=1, index=1
plt.plot(x1, y1, 'o-')
plt.title('1st Graph')
plt.grid(True)
plt.subplot(2, 1, 2) # nrows=2, ncols=1, index=2
plt.plot(x1, y1, '.-')
plt.title('2nd Graph')
plt.grid(True)
plt.tight_layout() # 전체 레이아웃 조정
plt.show()
2-2. for문을 활용한 다중 그래프
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1행 5열 구조
plt.figure(figsize=(15, 3))
for i in range(5):
x1 = np.arange(1, 11)
y1 = np.exp(-x1) * (i + 1) # 각 그래프마다 다른 스케일
plt.subplot(1, 5, i+1)
plt.plot(x1, y1, 'o-')
plt.title(f'{i+1}st Graph')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
2-3. 고급 다중 그래프 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
x = np.arange(1, 5) # [1, 2, 3, 4]
# 3행 2열 구조, 축 공유 설정
fig, ax = plt.subplots(3, 2,
sharex=True, # x축 공유
sharey=True, # y축 공유
squeeze=True,
figsize=(10, 12))
# 각 서브플롯에 다른 그래프 그리기
ax[0][0].plot(x, np.sqrt(x), 'gray', linewidth=3)
ax[0][0].set_title('Square Root')
ax[0][1].plot(x, x, 'g^-', markersize=10)
ax[0][1].set_title('Linear')
ax[1][0].plot(x, -x+5, 'ro--')
ax[1][0].set_title('Negative Linear')
ax[1][1].plot(x, np.sqrt(-x+5), 'b.-.')
ax[1][1].set_title('Square Root (Negative)')
ax[2][0].plot(x, x**2, 'purple', marker='s')
ax[2][0].set_title('Quadratic')
ax[2][1].plot(x, np.log(x), 'orange', marker='D')
ax[2][1].set_title('Logarithm')
plt.tight_layout()
plt.show()
3. 히스토그램 (Histogram)
3-1. 기본 히스토그램
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import pandas as pd
import seaborn as sns
# 샘플 데이터 생성
np.random.seed(42)
data = np.random.normal(100, 15, 1000) # 평균 100, 표준편차 15
# 기본 히스토그램
plt.figure(figsize=(10, 6))
plt.hist(data, bins=30, alpha=0.7, edgecolor='black')
plt.title('Basic Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.grid(True, alpha=0.3)
plt.show()
3-2. 다양한 bins 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 다양한 bins 설정으로 분포 비교
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
bins_list = [10, 30, 50, 100]
titles = ['Bins = 10', 'Bins = 30', 'Bins = 50', 'Bins = 100']
for i, (bins, title) in enumerate(zip(bins_list, titles)):
row = i // 2
col = i % 2
axes[row, col].hist(data, bins=bins, alpha=0.7, edgecolor='black')
axes[row, col].set_title(title)
axes[row, col].set_xlabel('Value')
axes[row, col].set_ylabel('Frequency')
axes[row, col].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
3-3. 실제 데이터 활용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Iris 데이터셋 활용
iris = sns.load_dataset('iris')
# 각 특성별 히스토그램
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
features = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width']
for i, feature in enumerate(features):
row = i // 2
col = i % 2
axes[row, col].hist(iris[feature], bins=20, alpha=0.7, edgecolor='black')
axes[row, col].set_title(f'{feature.replace("_", " ").title()} Distribution')
axes[row, col].set_xlabel(feature.replace("_", " ").title())
axes[row, col].set_ylabel('Frequency')
axes[row, col].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
4. 박스플롯 (Boxplot)
4-1. 기본 박스플롯
1
2
3
4
5
6
7
8
9
10
# 단일 컬럼 박스플롯
np.random.seed(42)
data = np.random.normal(100, 15, 100)
plt.figure(figsize=(8, 6))
plt.boxplot(data)
plt.title('Basic Boxplot')
plt.ylabel('Value')
plt.grid(True, alpha=0.3)
plt.show()
4-2. 여러 컬럼 박스플롯
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Iris 데이터셋의 수치형 컬럼들
iris_numeric = iris[['sepal_length', 'sepal_width', 'petal_length', 'petal_width']]
# 방법 1: pandas의 boxplot 메서드
plt.figure(figsize=(10, 6))
iris_numeric.boxplot()
plt.title('Iris Dataset - All Features')
plt.ylabel('Value')
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.show()
# 방법 2: matplotlib의 boxplot
plt.figure(figsize=(10, 6))
plt.boxplot(iris_numeric.values, labels=iris_numeric.columns)
plt.title('Iris Dataset - All Features (Matplotlib)')
plt.ylabel('Value')
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.show()
4-3. 박스플롯 통계값 계산
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# IQR (Interquartile Range) 계산
feature = 'sepal_width'
Q1 = iris[feature].quantile(0.25)
Q3 = iris[feature].quantile(0.75)
IQR = Q3 - Q1
print(f"=== {feature} 박스플롯 통계값 ===")
print(f"Q1 (1사분위수): {Q1:.2f}")
print(f"Q3 (3사분위수): {Q3:.2f}")
print(f"IQR (사분위수 범위): {IQR:.2f}")
# 이상치 경계값 계산
lower_bound = Q1 - 1.5 * IQR
upper_bound = Q3 + 1.5 * IQR
print(f"이상치 하한: {lower_bound:.2f}")
print(f"이상치 상한: {upper_bound:.2f}")
# 이상치 확인
outliers = iris[(iris[feature] < lower_bound) | (iris[feature] > upper_bound)]
print(f"이상치 개수: {len(outliers)}개")
# 박스플롯과 이상치 시각화
plt.figure(figsize=(10, 6))
plt.boxplot(iris[feature], vert=True)
plt.title(f'{feature.replace("_", " ").title()} Boxplot with Outliers')
plt.ylabel('Value')
plt.grid(True, alpha=0.3)
# 이상치를 별도로 표시
if len(outliers) > 0:
plt.scatter([1] * len(outliers), outliers[feature],
color='red', s=50, alpha=0.7, label='Outliers')
plt.legend()
plt.show()
5. 히트맵 (Heatmap)
5-1. 기본 히트맵
1
2
3
4
5
6
7
8
9
10
11
12
import seaborn as sns
# 상관관계 행렬 생성
titanic = sns.load_dataset('titanic')
correlation_matrix = titanic.corr(numeric_only=True)
# 기본 히트맵
plt.figure(figsize=(10, 8))
sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0)
plt.title('Titanic Dataset Correlation Heatmap')
plt.tight_layout()
plt.show()
5-2. 고급 히트맵 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 상세한 히트맵 설정
plt.figure(figsize=(12, 10))
sns.heatmap(correlation_matrix,
annot=True, # 수치 표시
annot_kws={'size': 8}, # 수치 크기
cmap=plt.cm.RdYlBu_r, # 색상 맵
fmt=".2f", # 소수점 둘째 자리
linewidth=0.5, # 선 두께
vmin=-1.0, # 최소값
vmax=1.0, # 최대값
square=False, # 정사각형 모양
cbar_kws={'shrink': 0.8}) # 컬러바 설정
plt.title('Titanic Dataset - Detailed Correlation Heatmap')
plt.tight_layout()
plt.show()
5-3. 생존률과의 상관관계 분석
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 생존(Survived)과 가장 상관도가 높은 피처 찾기
survived_corr = correlation_matrix['survived'].abs().sort_values(ascending=False)
print("생존률과의 상관관계 (절댓값 기준):")
print(survived_corr)
# 상위 상관관계 피처들만 시각화
top_features = survived_corr.head(6).index
top_corr_matrix = correlation_matrix.loc[top_features, top_features]
plt.figure(figsize=(10, 8))
sns.heatmap(top_corr_matrix,
annot=True,
cmap='RdYlBu_r',
center=0,
square=True,
fmt=".2f")
plt.title('Top Features Correlation with Survival')
plt.tight_layout()
plt.show()
6. 폰트 설정
6-1. 한글 폰트 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import matplotlib.font_manager as fm
# 시스템에 설치된 한글 폰트 확인
font_list = [f.name for f in fm.fontManager.ttflist if '한글' in f.name or 'Korean' in f.name]
print("사용 가능한 한글 폰트:")
for font in font_list:
print(f"- {font}")
# 한글 폰트 설정
plt.rcParams['font.family'] = 'DejaVu Sans' # 기본 폰트
plt.rcParams['axes.unicode_minus'] = False # 마이너스 기호 깨짐 방지
# 또는 특정 폰트 지정
# plt.rcParams['font.family'] = 'Malgun Gothic' # Windows
# plt.rcParams['font.family'] = 'AppleGothic' # Mac
# plt.rcParams['font.family'] = 'NanumGothic' # Linux
6-2. 폰트 스타일 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 전역 폰트 설정
plt.rcParams.update({
'font.size': 12,
'font.family': 'DejaVu Sans',
'axes.titlesize': 14,
'axes.labelsize': 12,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'legend.fontsize': 10,
'figure.titlesize': 16
})
# 테스트 그래프
plt.figure(figsize=(10, 6))
x = np.linspace(0, 10, 100)
y = np.sin(x)
plt.plot(x, y, label='sin(x)')
plt.title('폰트 설정 테스트')
plt.xlabel('X축 라벨')
plt.ylabel('Y축 라벨')
plt.legend()
plt.grid(True, alpha=0.3)
plt.show()
7. 실무 활용 예제
7-1. 종합 시각화 대시보드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
def create_dashboard(data):
"""종합 시각화 대시보드 생성"""
fig, axes = plt.subplots(2, 3, figsize=(18, 12))
# 1. 히스토그램
axes[0, 0].hist(data, bins=30, alpha=0.7, edgecolor='black')
axes[0, 0].set_title('Distribution')
axes[0, 0].set_xlabel('Value')
axes[0, 0].set_ylabel('Frequency')
axes[0, 0].grid(True, alpha=0.3)
# 2. 박스플롯
axes[0, 1].boxplot(data)
axes[0, 1].set_title('Boxplot')
axes[0, 1].set_ylabel('Value')
axes[0, 1].grid(True, alpha=0.3)
# 3. Q-Q 플롯 (정규성 검정)
from scipy import stats
stats.probplot(data, dist="norm", plot=axes[0, 2])
axes[0, 2].set_title('Q-Q Plot')
axes[0, 2].grid(True, alpha=0.3)
# 4. 누적 분포 함수
sorted_data = np.sort(data)
y_vals = np.arange(1, len(sorted_data) + 1) / len(sorted_data)
axes[1, 0].plot(sorted_data, y_vals, 'b-', linewidth=2)
axes[1, 0].set_title('Cumulative Distribution')
axes[1, 0].set_xlabel('Value')
axes[1, 0].set_ylabel('Cumulative Probability')
axes[1, 0].grid(True, alpha=0.3)
# 5. 시계열 플롯 (인덱스를 시간으로 가정)
axes[1, 1].plot(data, 'g-', alpha=0.7)
axes[1, 1].set_title('Time Series')
axes[1, 1].set_xlabel('Index')
axes[1, 1].set_ylabel('Value')
axes[1, 1].grid(True, alpha=0.3)
# 6. 통계 요약
axes[1, 2].axis('off')
stats_text = f"""
통계 요약:
평균: {np.mean(data):.2f}
중앙값: {np.median(data):.2f}
표준편차: {np.std(data):.2f}
최소값: {np.min(data):.2f}
최대값: {np.max(data):.2f}
왜도: {stats.skew(data):.2f}
첨도: {stats.kurtosis(data):.2f}
"""
axes[1, 2].text(0.1, 0.5, stats_text, fontsize=12,
verticalalignment='center', fontfamily='monospace')
plt.suptitle('Data Analysis Dashboard', fontsize=16, fontweight='bold')
plt.tight_layout()
plt.show()
# 샘플 데이터로 대시보드 생성
np.random.seed(42)
sample_data = np.random.normal(100, 15, 1000)
create_dashboard(sample_data)
7-2. 커스텀 스타일 함수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
def set_plot_style(style='default'):
"""그래프 스타일 설정 함수"""
if style == 'professional':
plt.style.use('seaborn-v0_8-whitegrid')
plt.rcParams.update({
'font.size': 11,
'axes.titlesize': 14,
'axes.labelsize': 12,
'xtick.labelsize': 10,
'ytick.labelsize': 10,
'legend.fontsize': 10,
'figure.titlesize': 16,
'axes.grid': True,
'grid.alpha': 0.3
})
elif style == 'minimal':
plt.style.use('default')
plt.rcParams.update({
'axes.spines.top': False,
'axes.spines.right': False,
'axes.grid': False,
'figure.facecolor': 'white',
'axes.facecolor': 'white'
})
else: # default
plt.style.use('default')
# 스타일 적용 예제
set_plot_style('professional')
plt.figure(figsize=(10, 6))
x = np.linspace(0, 10, 100)
y1 = np.sin(x)
y2 = np.cos(x)
plt.plot(x, y1, label='sin(x)', linewidth=2)
plt.plot(x, y2, label='cos(x)', linewidth=2)
plt.title('Professional Style Example')
plt.xlabel('X')
plt.ylabel('Y')
plt.legend()
plt.show()
마무리
Matplotlib은 데이터 시각화의 핵심 도구입니다:
핵심 학습 내용
- 기본 구조: 그래프 생성, 스타일링, 다중 그래프 구성
- 히스토그램: 데이터 분포 시각화와 bins 설정의 중요성
- 박스플롯: 데이터 분포와 이상치 탐지
- 히트맵: 상관관계 분석과 패턴 발견
- 폰트 설정: 한글 폰트 설정과 스타일링
실무 적용
- 시각화 대시보드: 종합적인 데이터 분석 시각화
- 스타일 관리: 일관된 그래프 스타일 설정
- 통계 시각화: 기술 통계와 분포 분석
- 상관관계 분석: 변수 간 관계 파악
Matplotlib의 기본기를 익혀 효과적인 데이터 시각화를 통해 인사이트를 도출할 수 있습니다.
This post is licensed under CC BY 4.0 by the author.