본문 바로가기

Matplotlib 데이터 시각화, 꼭 알아야 할 이론부터 실습까지! 총정리!

Derrick 발행일 : 2023-09-29
728x90
반응형
지금까지 학습한 Numpy, Pandas의 내용과
matplotlib 라이브러리의 시각화 기능으로 실습을 통해 데이터를 시각화해보자

 

 

 

1. Matplotlib이란?

Matplotlib이란, 파이썬에서 데이터를 그래프나 차트로 시각화할 수 있는 라이브러리
Numpy, Pandas와 같은 라이브러리들과 함께 결합해서 다양한 그래프들을 손쉽게 그릴 수 있음

1) 그래프 그리기 (Statement & Object-Oriented Interface)

'matplotlib.pyplot'을 import하고 plt.plot에 데이터를 넣어주면 그래프가 출력된다.
> 아래의 코드에서는 plt.plot(x, y)에 순차적으로 x와 y값이 들어가게 된다.

 

# Statement Interface (자동으로 Figure와 ax 생성)
import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [1, 2, 3, 4, 5]

plt.plot(x, y)

 

[ 직선 그래프 실행 결과 ]

 

출력할 그래프에 title, xlabel, ylabel도 추가할 수 있다.
→ plt.title("제목"), plt.xlabel(), plt.ylabel()

 

# Object-Oriented Interface (객체지향으로 Figure와 ax를 user가 그려서 그래프 출력)
import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [1, 2, 3, 4, 5]

fig, ax = plt.subplots()

ax.plot(x, y)
ax.set_title("First Plot")
ax.set_xlabel("x")
ax.set_ylabel("y")

 

[ Title과 Label 추가 ]

- fig, ax = plt.subplots()
 : plt.subplots()로부터 fig와 ax를 가져온다. 

- ax.plot(x, y)
 : x와 y 데이터를 불러와서 넣는다.

2) matplotlib 구조

matplotlib 구조를 보면서 figure와 ax를 포함한 그래프를 그릴 때의 도구들을 살펴보자
> Figure, Axes

 

[ matplotlib 구조 / line plot(위), scatter plot(아래) ]

- Figure : 가장 큰 도화지 
  → 표현되는 그래프들은 가장 큰 범주인 Figure 내에서 모두 출력된다.
- Axes : Figure(도화지) 안에서 표현되는 그래프들의 영역
- Marker : scatter plot(산점도)에서 표현되는 점들
- Grid : 그래프에서 격자모양으로 점선들이 겹치는 부분
- Major tick : x label 혹은 y label에서 큰 눈금
- Minor tick : Major tick 사이에 있는 작은 눈금
- Legend : 각 그래프 우측 상단에 있으며, 어떤 그래프인지 알려주는 범례

3) 그래프 저장하기

시각화한 그래프를 저장하기 위해서는 전체 도화지, 즉 Figure를 저장해야한다.

 

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [1, 2, 3, 4, 5]

fig, ax = plt.subplots()

ax.plot(x, y)
ax.set_title("First Plot")
ax.set_xlabel("x")
ax.set_ylabel("y")

fig.set_dpi(300)
fig.savefig("first_plot.png")

 

- fig.set_dpi(300)
 : dpi (=dot per inch)로 1인치 제곱당 몇 dot까지 들어갈 수 있는지를 지정할 수 있다.
  → 300 정도로 지정하면, 출력물에 대해서는 모두 잘 표현된다.
  → 더 작게 저화질로 저장하고 싶다면, 300보다 낮춰서 저장하면 된다.

- fig.savefig("first_plot.png")
 : savefig()를 통해서 'first_plot' 라는 이름으로 png 확장자로 그래프 저장
  → 현재 작업하고 있는 디렉토리에 저장된다.

4) 여러 개의 그래프 그리기

하나의 Figure(도화지) 안에 여러 개의 그래프를 시각화해보자

 

x = np.linspace(0, np.pi*4, 100)

fig, axes = plt.subplots(2, 1)

axes[0].plot(x, np.sin(x))
axes[1].plot(x, np.cos(x))

 

[ 여러 그래프 그리기 / sin(x), cos(x) ]

- x = np.linspace(0, np.pi*4, 100)
 : numpy의 linspace 함수를 통해 0~4π 까지 100개의 균등한 구간으로 나누어서 나온 데이터를 x라고 지정

- plt.subplots(2, 1)
 : 세로축으로 2개(0, 1), 가로축으로 1개의 데이터를 가진 Fig와 axes를 출력
  → 위부터 axes[0], axes[1] 순서대로 시각화된다. 
  → subplot()을 통해서 Figure 내에 몇 개의 그래프를 시각화시킬 것인지 지정할 수 있다.

axes[0].plot(x, np.sin(x))
 : 첫번째 그래프에 x값에 따른 sin값을 시각화
  → axes[1]인 두번째 그래프는 cos값을 시각화

 

2. Matplotlib 그래프 정리

지금까지 Matplotlib의 기초적인 부분들을 학습했고, 이를 기반으로 어떤 그래프들을 그릴 수 있는지 살펴보자

1) Line plot & 옵션(Line style, color, marker)

Line plot을 아래 코드로 출력해보며, ax.plot() 안에 3가지 옵션을 추가해보자

 

fig, ax = plt.subplot()

x = np.arange(15)
y = x ** 2

ax.plot(
    x, y, 
    linestyle = ":",
    marker = "*",
    color = "#524FA1"
)

 

[ Line plot ]

- x = np.arange(15)
 : 0~14까지의 데이터를 가져와서 x에 넣는다

- ax.plot() 내 옵션
 → linestyle, marker, color ... 위의 시각화된 그래프 참고

 

# Line Style

Line plot을 그릴 때 참고할만한 4가지의 Line Style을 출력해서 각각 비교해보자
→ 위에 있는 코드부터 순서대로 출력된 모습 (사진 참고)

 

x = np.arange(10)

fig, ax = plt.subplots()

# dotted 
ax.plot(x, x+6, linestyle = ":")

# dashdot
ax.plot(x, x+4, linestyle = "-.")

# dashed
ax.plot(x, x+2, linestyle = "--")

# solid
ax.plot(x, x, linestyle = "-")

 

[ Line Style 비교 ]

# Line Color

Plot을 그릴 때, Line에 색상도 4가지 방법으로 추가할 수 있으며, 아래 코드와 실행결과를 확인해보자

 

x = np.arange(10)

fig, ax = plt.subplots()

# RGB에 대한 16진수 코드
ax.plot(x, x+6, color = "#524FA1")

# 0 ~ 1 사이의 값이 문자열 - 0이면 검은색, 1이면 투명한 흰색
ax.plot(x, x+4, color = '0.8')

# 색상 이름의 풀네임
ax.plot(x, x+2, color = "green")

# RGB, CMYK 등의 문자열
ax.plot(x, x, color = "r")

 

[ Line Color ]

# Marker

Marker에도 종류가 많지만, 대표적으로 쓰이는 5개를 아래와 같이 출력해보자
→ 코드 순서대로 시각화된 결과 확인

 

x = np.arange(10)

fig, ax = plt.subplots()

ax.plt(x, x+8, marker="*")
ax.plt(x, x+6, marker="s")
ax.plt(x, x+4, marker="v")
ax.plt(x, x+2, marker="o")
ax.plt(x, x, marker=".")

 

[ Marker 비교 ]
[ Marker별 의미 ]

2) 그래프 속성 (축 경계, 범례(legend))

지금까지 Line Plot 에 어떤 속성이 들어가는지를 확인했다면, 이제부터 그래프 자체에는 어떤 옵션들이 있는지 확인해보자 

 

# 축 경계 조정하기

축 경계란, x와 y축이 어디서부터 시작되고 어디까지 끝나는 지에 대한 조정을 의미한다.
set_xlim(), set_ylim() 를 통해서 경계를 설정할 수 있다.
→ 축 경계를 조정하지 않으면, matplotlib에 의해 최적화된 그래프로 시각화된다.

 

x = np.linspace(0, 10, 1000)

fig, ax = plt.subplots()

ax.plot(x, np.sin(x))
ax.set_xlim(-2, 12)
ax.set_ylim(-1.5, 1.5)

 

[ 축 경계 조정하기 ]

- x = np.linspace(0, 10, 1000)
 : linspace() 함수를 통해 0부터 10사이의 1000개의 데이터를 뽑아서 x로 가져오기

- ax.plot(x, np.sin(x))
 : ax.plot()를 통해 x값과 x값에 따른 sin(x) 그래프를 출력

- ax.set_xlim(-2, 12)
 : x축을 -2부터 12까지 경계 조정 

- ax.set_ylim(-1.5, 1.5)
 : y축을 -1.5부터 1.5까지 경계 조정

 

# 범례 (legend)

아래 코드는 x값이 0~9까지의 정수라고 가정할 때, 'y=x'와 'y=x^2' 그래프로 표현하며, 각각 label 값을 넣어준다. 그리고 x와 y에 각각 label과 legend를 지정

 

fig, ax = plt.subplots()

ax.plot(x, x, label='y=x')
ax.plot(x, x**2, label='y=x^2')

ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend(
    loc = 'upper right',
    shadow = True,
    fancybox = True,
    borderpad = 2
)

 

[ 범례 설정 ]

- ax.set_xlabel("x") 
 : x축 label에 'x'라고 지정. ylabel도 동일

- loc = 'upper right'
 : legend 속성값으로 안에는 그래프의 선과 Label값이 표시된다. 우측 상단에 표시(loc = location)
  → lower left, center 등으로도 설정 가능

- shadow = True
 : 범례(legend)의 그림자 표시 On 설정

- fancybox = True
 : legend가 표현되는 박스를 둥글게 출력할 수 있다. (True일 경우)

- borderpad = 2
 : 범례 박스 안(표시되는 데이터 밖)에 있는 흰색 영역의 크기 (숫자가 클수록 여백이 커진다)

3) Matplotlib 그래프 출력 연습

지금까지 학습한 내용을 기반으로 어떤 그래프들을 그리고 옵션을 추가하는 연습을 해보자
→ 취향에 따라 ax.plot() 함수의 marker, color, linestyle의 옵션을 변경해보자

 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# 2가지의 그래프 출력 (x = 0~9)
x = np.arange(10)
fig, ax = plt.subplots()

ax.plot(
    x, x, label='y=x',
    marker='o',
    color='blue',
    linestyle=":"
)

ax.plot(
   x, x**2, label='y=x^2',
   marker='^',
   color='red',
   linestyle='--'
)

ax.set_xlabel("x")
ax.set_ylabel("y")
ax.legend(
    loc='upper left',
    shadow=True,
    fancybox=True,
    borderpad=2
)

 

[ 실행 결과 ]

예시 코드에서는 figure와 ax가 각각 1개인데, ax.plot 함수를 2번 호출으로써
하나의 ax 안에 여러개의 그래프를 출력하면 겹쳐서 그릴 수 있게 된다. 

 

3. Scatter (산점도)

1) Scatter 그래프란?

 Scatter 그래프는 산점도라고도 하며, 이를 사용하게 되면 값 사이의 관계를 파악하기 용이해지고 데이터셋에서 이상값을 찾기도 용이하다. 두 개 이상의 측정값의 상관 관계를 파악하고 시각화 할 수 있는 그래프의 유형이다.
 그래프는 아래와 같이 표현될 수 있으며, 코드를 통해 학습해보자

 

fig, ax = plt.subplots()

# x = 0 ~ 9
x = np.arange(10)

ax.plot(
    x, x**2, "o"
    markersize = 15,
    markerfacecolor = 'white',
    markeredgecolor = 'blue'
)

 

[ Scatter 그래프 ]

- ax.plot( ~, "o", ~)
 : ax.plot() 안에 세번째 인자에 "o"을 입력하면, 라인이 아닌 원으로 그래프가 표현된다.

- markersize = 15
 : 출력되는 원의 크기

- markfacecolor = 'white'
 : 원 안의 색상 지정

- markteredgecolor = 'blue'
 : 원을 그리는 가장 바깥쪽의 edge 색상

2) Scatter 그래프의 Size와 Color 지정

Scatter 그래프에서의 원의 Size와 Color를 각각 지정한 채로 만들어줄 수 있다.
→ 아래 코드에서는 x, y, colors, sizes 값 모두 랜덤하게 추출해서 scatter 그래프를 그려보자

 

fig, ax = plt.subplots()
x = np.random.randn(50)
y = np.random.randn(50)

colors = np.random.randint(0, 100, 50)
sizes = 500 * np.pi * np.random.rand(50) **2

ax.scatter(
     x, y, c=colors, s=sizes, alpha=0.3
)

 

[ 사이즈가 다른 Scatter 그래프 실행 결과 ]

- x = np.random.randn(50)
 : randn()을 통해서 정규분포에서 50개씩 x값을 추출 (y도 동일)

- colors = np.random.randint(0, 100, 50)
 : randint() 함수를 통해 0부터 100 사이 50개의 랜덤한 수를 colors에 넣어준다

- sizes = 500 * np.pi * np.random.rand(50) ** 2
 : sizes라는 변수 안에도 임의의 수가 곱혀지도록 하여 값이 랜던하게 

- ax.scatter(x, y, c=colors, s=sizes, alpha=0.3)
 : x, y값을 통해 원의 중심이 어디에 찍힐지 정하고, c는 color, s는 size를 지정, alptha는 투명도 설정(데이터가 잘 보이도록)

 

4. Bar & Histogram

 Bar 그래프(=막대 그래프)는 여러 값을 비교하는데 매우 적합한 그래프이다. 여러개의 데이터를 입력받고 그 값들을 한눈에 비교 할 수 있다.
 Histogram은 일정 시간동안의 숫자 데이터 분포를 시각화하는데 적합하다.

1) Bar Plot (Single)

 

x = np.arange(10)

fig, ax = plt.subplots(figsize=(12,4))
ax.bar(x, x*2)

 

[ Bar Plot ]

- figsize = (12, 4)
 : figure 사이즈를 지정 가로로 12, 세로로 4인 Figure 안에서 그래프 출력

- ax.bar(x, x*2)
 : bar plot. x와 y값을 넣어준다.

2) 누적된 Bar Plot 

누적된 Bar plot을 표현하기 위해서는 첫번째 데이터로 Bar plot을 하고, 그 y값을 다음 데이터의 bottom을 기준으로 다음 y값만큼 쌓아올리는 원리로 실행된다. 

 

x = np.random.rand(3)
y = np.random.rand(3)
z = np.random.rand(3)

data = [x, y, z]

fig, ax = plt.subplots()
x_ax = np.arange(3)

for i in x_ax:
    ax.bar(x_ax, data[i],
    bottom = np.sum(data[:i}, axis=0))

ax.set_xticks(x_ax)
ax.set_xticklabels(["A", "B", "C"])

 

[ bar plot 누적 그래프 ]

- x = np.random.rand(3)
 : 0부터 1사이의 3개의 데이터 추출(y, z도 동일)

- x_ax = np.arange(3)
 : 0~2까지 총 3개의 값 추출 (= 0, 1, 2) → x값의 데이터

ax.bar(x_ax, data[i, ~ 
 : for문에서 i값이 1씩 증가함으로 x_ax(=x값)은 순차적으로 (0, 1, 2)에 data의 [x, y, z] 순서대로 값이 들어간다.

- bottom = np.sum(data[:i], axis=0 ~
 : bottom 인자에는 Bar plot을 그리는 시작점이 어디인지 설정. 
  → np.sum(data[:i] ~ : 현재 data값 이전까지의 sum값 기준, 즉 이전까지의 y값의 총합. 
  → axis = 0 : x축을 기준으로

- ax.set_xticks(x_ax)
 : x축은 np.arange(3)에 의해서 (0, 1, 2)이지만, xticks으로 지정

- ax.set_xticklabels(["A", "B", "C"])
 : xtick값에 각각 "A", "B", "C"라는 문자열로 넣어준다.

3) Histogram (=도수분포표)

 

fig, ax = plt.subplots()
data = np.random.randn(1000)
ax.hist(data, bins=50)

 

[ Histogram 실행 결과 ]

- data = np.random.randn(1000)
 : randn() 함수를 통해 표준정규분포에서 1000개의 데이터 추출하여 data로 가져온다.

- ax.hist(data, bins=50)
 : ax.hist()를 통해 Histogram를 표현하며, x값에는 data로 넣는다.
  → bins 인자는 출력되는 Bar가 얼마큼 나오게 될 것인지 설정. bins값이 클수록 Bar 폭이 좁고 많이 출력되고, 작을수록 폭이 넓고 조금 출력되게 된다. 

 

4) Bar & Histogram 그래프 예제

 지금까지 학습한 Bar와 Histogram 그래프를 간단한 예제로 연습해보자
아래 x와 y 데이터는 각각 스포츠의 종목과 각 스포츠를 선호하는 학생의 수를 조사한 결과이다. (z는 난수)
x와 y 데이터에 대한 막대그래프와 z 데이터를 등급을 50개로 나눈 히스토그램을 출력해보자

# Tip
: matplotlib의 pyplot으로 그래프를 그릴 때 한글을 기본 폰트로 지원하지 않는다. 따라서 한글을 지원하는 '나눔바른고딕' 폰트로 바꾼 코드를 적용시켜야 한다.

 

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

# pyplot에서 한글 지원 폰트로 바꾸어서 한글로 표시
import matplotlib.font_manager as fm
fname = './NanumBarunGothic.ttf'
font = fm.FontProperties(fname = fname).get_name()
plt.rcParams["font.family"] = font

x = np.array(["축구", "야구", "농구", "배드민턴", "탁구"])
y = np.array([18, 7, 12, 10, 8])

# 히스토그램을 표현하기 위한 z값(난수) 추출
z = np.random.randn(1000)

fig, axes = plt.subplots(1, 2, figsize=(8,4))

# Bar 그래프
axes[0].bar(x, y)
# 히스토그램
axes[1].hist(z, bins=50)

 

[ 실행 결과 ]

- fig, axes = plt.subplots(1, 2, figsize = (8, 4))
 : 하나의 figure에 1*2 size로 2개의 그래프를 가로로 배치하도록 그리는 코드 (axes[0], axes[1])
 → figsize는 (8, 4)

# pyplot으로 그래프를 표현할 때 한글 폰트는 default로 지원되지 않기 때문에 한글 지원 폰트로 바꾸어서 한글을 사용할 수 있다.

 

5. Matplotlib with Pandas

지금까지는 Matplotlib에 numpy 데이터를 가지고 그래프를 그렸다면, 이번에는 Pandas의 DataFrame이나 Series 데이터를 넣어서 시각화하는 방법에 대해 확인해보자

1) Line plot

'president_height.csv'라는 미국 대통령의 키(height) 정보가 있는 데이터가 주어지고, 이를 통해 그래프를 그려보자

 

df = pd.read_csv("./president_height.csv")

fig, ax = plt.subplots()

ax.plot(df["order"], df["height(cm)"], label="height")
ax.set_xlabel("order")
ax.set_ylabel("height(cm)")

 

[ 코드 실행 결과(위) / 데이터프레임(아래) ]

- ax.plot(df["order"], df["height(cm)"], label="height")
 : x축에는 데이터프레임의 'order'값(=순서)으로 잡고, y축에는 height(cm)값으로 설정 (label은 'height')

- ax.set_xlabel("order"), ax.set_ylabel("height(cm)")
  → x와 y축 label을 각각 'order'와 'height(cm)'로 입력

2) Scatter plot 예제 - 포켓몬데이터

아래 DataFrame와 같이 포켓몬스터의 이름, Type, HP 등의 데이터가 주어지고, 이를 통해 불과 물 포켓몬의 공격(Attack)과 방어(Defense)를 비교해서 시각화를 해보자
공격과 방어에 대한 불과 물의 포켓몬의 Scatter 그래프를 시각화해보자 (빨간색 : Fire, 파란색 : Water)

 

fire = df[(df['Type 1'] == 'Fire') | (df['Type 2'] == 'Fire')]
water = df[(df['Type 1'] == 'Water') | (df['Type 2'] == 'Water')]

fig, ax = plt.subplots()

# fire와 water에 대한 scatter 그래프를 2번 그림
ax.scatter(fire['Attack'], fire['Defense'], color='R', label='Fire', marker="*", s=50)
ax.scatter(water['Attack'], water['Defense'], color='B', label='Water', s=25)
ax.set_xlabel("Attack")
ax.set_ylabel("Defense")
ax.legend(loc="upper right")

 

[ 코드 실행 결과 ]

- fire = df[(df['Type 1'] == 'Fire') | ((df['Type 2']) == 'Fire']
 : df에서 'Type 1'에 불이 있거나 'Type 2'에 불이 있을 경우, 'fire'라는 새로운 df를 만든다.
  → 마스킹 연산 활용. water도 동일 원리

# 주어진 데이터 내 포켓몬스터들의 공격과 수비 능력치가 x와 y축으로 주어지고 물 속성 포켓몬은 파란색, 불 속성 포켓몬은 빨간색으로 표현한 그래프로 시각화

 

6. Matplotlib 예제 - 토끼와 거북이 경주 결과 시각화

토끼와 거북이가 달리기 시합을 하기로 했다.
1초마다 토끼와 거북이의 위치가 기록된 데이터(the_hare_and_the_tortoise.csv)를 통해 시간별 위치를 그래프로 시각화해보자

 

from matplot import pyplot as plt
import pandas as pd
plt.rcParams["font.family"] = 'NanumBarunGothic'

# 경로 : "./data/the_hare_and_the_tortoise.csv"
# 첫번째(=0번쨰) 컬럼을 index로 설정
df = pd.read_csv('./data/the_hare_and_the_tortoise.csv', index_col=0)

# 또는 특정 컬럼을 index로 잡고 싶다면? - 아래는 '시간' 데이터를 index로 설정
df.set_index("시간", inplace=True)

# 그래프 그리기
fig, ax = plt.subplots()

ax.plot(df['토끼'], color='blue')
ax.plot(df['거북이'], color='orange')
ax.legend(loc="upper left")

 

[ 코드 실행 결과 ]

- ax.plot(df['토끼'], color='blue')
 : x축에 df['시간']을 생략해도 시간 데이터가 index로 잡힌다.
  → 첫번째 컬럼을 index로 변경했기 때문에 (index_col = 0)

- inplace = True
 : 변경한 값을 반영해서 원본도 변경된 값으로 저장됨

 

댓글