본문 바로가기

Data Handling/Data Visualizing

matplotlib 완벽 정리

데이터 분야 공부를 시작할때 가장 먼저 만나는 세 가지 라이브러리를 꼽자면 numpy, pandas, matplotlib 입니다.

오늘은 그 중 matplotlib 에 대해서 정리해볼텐데요, 

개인적으로 처음 이 라이브러리를 접했을때 정말 헷갈렸습니다.

 

어떤 커널에서는 plt.plot으로 표현하고, 또 다른 커널에서는 ax.plot 혹은 axes[0,0].plot으로 표현되어있기 때문입니다.

그리고 가령 히스토그램을 그린다면 누구는 plt.hist로 구현했는데, 또 다른 누구는 plt.plot(kind='hist)로 구현했기 때문에 일목요연하게 정리되지 않았습니다.

 

그래서 오늘 포스팅을 기획하게 되었는데요, 해당 포스팅의 목적은 두 가지 입니다.

첫 번째, 왜 이렇게 표현방식이 다양하고, 어떻게 정리할 수 있을까?

두 번째, 자주쓰이는 표현들을 모아두고 필요할 때마다 다시 볼 수 있는 페이지를 남기자

 

그럼 바로 시작해볼게요!

 


- 왜 이렇게 표현방식이 다양하고, 어떻게 정리할 수 있을까?

 

matplotlib는 아래와 같이 크게 두 가지 방법으로 사용할 수 있습니다.

- stateless API (objected-based)

- stateful API (state-based)

 

stateless 방법은 내가 지정한 figure, 내가 지정한 ax에 그림을 그리는 방법이고,

stateful 방법은 현재의 figure, 현재의 ax에 그림을 그리는 방법입니다.

* figure : 그래프를 그릴 공간(종이) / ax(axes) : 그 공간 중 지금 내가 사용할 부분

 

따라서 stateless 방법은 figure와 ax를 직접 만들어야 하고, 이런 특징으로 객체지향적이라고 할 수 있습니다.

반면 stateful 방법은 직접 지정하지 않고, 현재의 figure와 ax를 자동으로 찾아 그곳에 plotting 하는 방식입니다.

 

 

처음에는 stateless 방법만 있었습니다. 직접 figure와 ax를 생성하고, plotting 했죠.

하지만 matplotlib는 더 편리한 사용을 위해 pyplot이라는 wrapper 모듈을 만들었고,

놀랍게도 이 모듈을 이용하는 방법이 stateful 방법입니다.

 

따라서 저희가 matplotlib를 import 할 때, 그냥 import matplotlib가 아닌 import matplotlib.pyplot 을 했던 것입니다.

(stateless 방법만 사용한다면 import matplotlib 만 하면 됩니다)

* 아직 궁금증이 풀리지 않으셨다면 여기에 설명이 잘 되어있으니 참고하시면 좋습니다.

 

 

그럼 여기서 이런 궁금증이 생깁니다.

그냥 모든 사람이 stateful 방법만 사용하면 안돼?? 

 

아까 말한것처럼 stateful 방법은 stateless 방법을 쉽게 사용하기 위한 방법입니다.

따라서 stateless 만큼 정교한 작업은 할 수 없습니다.

만약 matplotlib를 사용하는 용도가 본인만을 위한 EDA 라면 stateful 방법만으로 충분하겠지만,

좀 더 깊이있는 시각화를 위해서는 stateless 방법도 숙지해야 합니다.

그리고 많은 사람들의 커널을 원활하게 공부하기 위해서라도 두 가지 방법을 모두 아는게 바람직합니다.

 


- 자주 쓰이는 표현들을 모아두고 필요할 때마다 다시 볼 수 있는 페이지를 남기자

- stateless API

* stateless 포스팅 관련 출처 : github.com/Apress/numerical-python-second-ed

 

* figure 와 ax 객체를 생성하는 방법

    #1. fig = plt.figure() : ax 없는 빈 figure 생성 (후에 ax를 추가해줘야함)

    #2. fig, ax = plt.subplots() : 하나의 ax 만을 가지는 하나의 figure 생성

    #3. fig, axes = plt.subplots(2,2) : 4개(2*2)이 ax들을 가지는 하나의 figure 생성

 

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

# 데이터 준비
x = np.linspace(-2, 2, 1000)
y1 = np.cos(40 * x)
y2 = np.exp(-x**2)

# 방법 1: 빈 figure를 생성하고 그 안에 ax를 추가하기
fig = plt.figure(figsize=(8, 2.5), facecolor="#c1f1f1")   # ax가 없는 빈 figure 생성
ax = fig.add_axes((left=0.1, bottom=0.1, width=0.8, height=0.8), facecolor="#e1e1e1") # ax 추가

# 방법 2: 하나의 ax 를 가지는 하나의 figure 생성(ax의 색깔 지정 못함)
fig, ax = plt.subplots(figsize=(8, 2.5), facecolor="#c1f1f1")

# 그래프 그리기
ax.plot(x, y1 * y2) # ax 에 plotting
ax.plot(x, y2, 'g')
ax.plot(x, -y2, 'g')
ax.set_xlabel("x") # x축 이름 설정
ax.set_ylabel("y") # y축 이름 설정

방법 1(왼) / 방법 2(오)

 

# 데이터 준비
x1 = np.random.randn(100)
x2 = np.random.randn(100)

r = np.linspace(0, 5, 100)
a = 4 * np.pi * r ** 2  # area
v = (4 * np.pi / 3) * r ** 3  # volume

x = np.linspace(0, 50, 500)
y = np.sin(x) * np.exp(-x/10)

# 방법 3: 여러개의 ax를 가지는 하나의 figure 생성
fig, axes = plt.subplots(2, 2, figsize=(10, 10)) # 4개의 ax를 가진 하나의 figure 생성

axes[0, 0].set_title("Draw twinx", fontsize=16) # ax 중에서 0행 0열의 제목 설정
axes[0, 0].set_xlabel("radius [m]", fontsize=16)

axes[0, 0].plot(r, a, lw=2, color="blue") # 0행 0열에 그리기
axes[0, 0].set_ylabel(r"surface area ($m^2$)", fontsize=16, color="blue") # 수학식을 나타낼대 $ 사이에 넣음
for label in axes[0, 0].get_yticklabels(): # y축 tick 색깔 지정
    label.set_color("blue")
    
ax2 = axes[0, 0].twinx() # 이중축 그리기
ax2.plot(r, v, lw=2, color="red")
ax2.set_ylabel(r"volume ($m^3$)", fontsize=16, color="red") 
for label in ax2.get_yticklabels():
    label.set_color("red")

axes[0, 1].plot(x, np.sin(x) * np.exp(-x/10), lw=2) # 0행 1열에 그리기
axes[0, 1].set_xlabel("x", labelpad=5, fontsize=18, fontname='serif', color="blue") # label 위치, 색깔, 글꼴 조절
axes[0, 1].set_ylabel("f(x)", labelpad=1, fontsize=18, fontname='serif', color="blue")
axes[0, 1].set_title("axis label", loc='left', fontsize=16, fontname='serif', color="blue") # 제목 왼쪽 정렬

axes[1, 0].set_title("axis('equal')") 
axes[1, 0].scatter(x1, -x1 + x2) # 1행 0열에 그리기
axes[1, 0].axis('equal') # x,y축의 범위를 동일하게 하기

axes[1, 1].set_title("axis('set_lim')") 
axes[1, 1].scatter(x1, x1 + 0.15 * x2) # 1행 1열에 그리기
axes[1, 1].set_xlim(-5, 8) # x축 범위 직접 설정하기
axes[1, 1].set_ylim(-5, 5)
axes[1, 1].annotate("Here", fontsize=14, family="serif", xy=(2.5, 2.5), 
			xytext=(5, 4),arrowprops=dict(arrowstyle="->", connectionstyle="arc3, rad=.5"))

# subplot 간 간격 조절
plt.subplots_adjust(left=0.1, right=0.95, bottom=0.1, top=0.95, wspace=0.7, hspace=0.5)

 

방법 3

 

 

 

- stateful API

* stateless 포스팅 관련 출처 : matplotlib.org/tutorials/introductory/pyplot.html

 

* 자세한 파라미터 종류 : matplotlib.org/api/_as_gen/matplotlib.pyplot.html

* 영리한 사용법 : 예를 들어 히스토그램을 그리고 싶은데 메소드 명을 모르겠다? 링크에 들어가서 ctrl+f -> histogram

 

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

# 한글 폰트 가져오기 - 예시로 H2GTRM 폰트 사용
from matplotlib import font_manager,rc
font_path = "C:/Windows/Fonts/H2GTRM.TTF"
font_name = font_manager.FontProperties(fname=font_path).get_name()
plt.rc('font',family=font_name)

# 데이터 준비
def f(t):
    return np.exp(-t) * np.cos(2*np.pi*t)

t2 = np.arange(0.0, 5.0, 0.02)

data = {'a': np.arange(50),
        'c': np.random.randint(0, 50, 50),
        'd': np.random.randn(50)}
data['b'] = data['a'] + 10 * np.random.randn(50)
data['d'] = np.abs(data['d']) * 100

# 그래프 그리기
plt.figure(figsize=(15,10)) # 종이 크기 지정
plt.suptitle('plotting method', fontsize = 20, y=0.9) # 종이의 제목, y는 제목의 위치(default=0.98)

plt.subplot(2,2,1) # 2행 2열에서 첫번째 부분/ * stateless의 plt.subplots()와 다름
plt.plot(1.98, 0.15, 'ro', t2, f(t2), 'k') # x=1.98, y=0.15 에 빨간 점 찍고, x=t2, y=f(t2)에 그림 그려라
plt.title('1st plot') # 제목
plt.xlabel('x') # x축 이름 지정
plt.ylabel('y blue', fontdict = {'size':15, 'color': 'blue'}) # y축 이름 지정
plt.grid(True, color='g', linestyle='--')
plt.annotate('3rd max', xy=(2, 0.17), xytext=(2.5, 0.6), fontsize=15, arrowprops=dict(facecolor='blue', shrink=0.05)) # 화살표 추가

plt.subplot(2,2,3) # 2행 2열에서 세번째 부분
plt.plot(t2, np.cos(2*np.pi*t2), 'r--', label= 'cos')
plt.plot(4,1,marker='x', ms=8, mec = 'b', mew = 2) # ms: markersize/ mec: markeredgecolor, mew: markeredgewidth
plt.title('2nd plot')
plt.legend(loc='best')

plt.subplot(2,2,(2,4)) # 2행 2열에서 두번째, 네번째 부분
plt.scatter(data['a'], data['b'], c=data['c'], s=data['d'], cmap='jet') # c: color, s: size
plt.title('3rd plot')
plt.xlabel('x 축')
plt.ylabel('y 축')

plt.subplots_adjust(top=0.8, bottom=0.28, left=0.10, right=0.95, hspace=0.5, wspace=0.2) # subplot layout 조절 /hspace : subplot간 위아래 공간, wspace : subpot간 좌우 공간

 

 


* 참고

matplotlib의 해부도 

 

'Data Handling > Data Visualizing' 카테고리의 다른 글

seaborn 완벽 정리  (4) 2020.10.15