더 이상 tistory 블로그를 운영하지 않습니다. glanceyes.github.io에서 새롭게 시작합니다.

새소식

Data Science/데이터 시각화

Matplotlib 모듈로 그린 Chart에서 Facet 사용하기

  • -

 

2022년 2월 3일(목)부터 4일(금)까지 네이버 부스트캠프(boostcamp) AI Tech 강의를 들으면서 개인적으로 중요하다고 생각되거나 짚고 넘어가야 할 핵심 내용들만 간단하게 메모한 내용입니다. 틀리거나 설명이 부족한 내용이 있을 수 있으며, 이는 학습을 진행하면서 꾸준히 내용을 수정하거나 추가해 나갈 예정입니다.

 

 

Facet in Chart

Facet

화면에 대한 분할 → Multiple Vew

 

화면 상에 View를 분할 및 추가하여 다양한 관점을 전달할 수 있다.

  • 같은 데이터셋에 서로 다른 인코딩을 통해 다른 인사이트를 보여줄 수 있다.
    • 예) 막대 그래프, 파이 차트를 인접하게 배치하는 경우
  • 같은 방법으로 동시에 여러 feature를 볼 수 있다.
  • 큰 틀에서 볼 수 없는 부분 집합을 세세하게 보여줄 수 있다.

 

 

Matplotlib에서의 구현

Figure와 Ax

Figure는 큰 틀, Ax는 각 플롯이 들어가는 공간(서브 플롯)이다.

Figure는 언제나 1개, 플롯은 N개가 될 수 있다.

  • N × M 서브플롯을 만드는 3가지 방법
    • plt.subplot()
      • 서브 플롯을 하나씩 그리는 방법
    • plt.figure() + fig.add_subplot()
      • Figure를 만들고, 여기에 서브 플롯을 추가하는 방법
    • plt.subplots()
      • 서브 플롯을 동시에 여러 개 그리는 방법

 

 

Grid Spec

Grid 형태의 subplots을 각각 다른 사이즈로 만들려면 다음과 같은 방법이 있다.

  • Slicing 사용하는 방법
    • numpy의 slicing을 생각해볼 수 있다.
    • 예) axex[0,:3], axes[1:,:3], axes[3,:]
    • fig.add_grid_spec()
  • $x$, $y$, $dx$, $dy$ 사용하는 방법
    • 시작 위치 $x$, $y$와 차이 $dx$, $dy$로 표현
    • 예) (0, 0), colspan = 1, rowspan = 3
    • fig.subplot2grid()
  • Ax 내부에 서브 플롯을 추가하는 방법
    • 미니맵과 같은 형태를 추가
    • 외부 정보를 적은 비중으로 추가
    • ax.inset_axes()
  • Grid를 사용하지 않고 사이드에 추가하는 방법
    • make_axes_locatable(ax)

 

 

Facet 사용 예시

서브 플롯 Ax

아래 세 가지 예시는 모두 같은 형태로 서브 플롯을 두 개 추가하는 방법이다.

fig = plt.figure()
ax = fig.add_subplot(121)
ax = fig.add_subplot(122)
fig, (ax1, ax2) = plt.subplots(1, 2)
fig, axes = plt.subplots(1, 2)

 

.set_facecolor()를 통해 Figure의 바탕색을 설정할 수 있다.

fig, ax = plt.subplots()
fig.set_facecolor('lightgray')
plt.show()

1644931853755

 

 

Figure & Ax Properties

dpi 는 Dots per Inch의 약자이며 인치에 해당하는 dot 수를 정하는 인자로 해상도를 의미한다. 기본값은 100이며, 150, 200, 300 값 등을 조정하며 원하는 해상도로 출력할 수 있다.

fig = plt.figure(dpi=150)
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax1.plot([1, 2, 3], [1, 4, 9])
ax2.plot([1, 2, 3], [1, 2, 3])
plt.show()

1644931868955

 

.savefig()에서 파라미터로 dpi를 넘기면 Figure를 저장할 때 해상도를 지정할 수 있다.

fig.savefig('file_name', dpi = 150)

1644931877500

 

개별 ax에 대해서나 subplots 함수를 사용할 때는 sharex, sharey를 사용하여 축을 공유할 수 있습니다.

fig = plt.figure()
ax1 = fig.add_subplot(121)
ax1.plot([1, 2, 3], [1, 4, 9])
ax2 = fig.add_subplot(122, sharey=ax1)
ax2.plot([1, 2, 3], [1, 2, 3])
plt.show()

1644931886546

 

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

axes[0].plot([1, 2, 3], [1, 4, 9])
axes[1].plot([1, 2, 3], [1, 2, 3])
plt.show()

1644931902165

 

subplots()squeeze=True 파라미터를 넘겨서 서브플롯을 생성하면 기본적으로 다음과 같이 서브플롯 ax 배열이 반환된다.

  • $1 × 1$ : 객체 1개 (ax)
  • $1 × N$ 또는 $N × 1$ : 길이 $N$인 1차원 배열 (axes[i])
  • $N × M$: N by M 배열 (axes[i][j]) (단, $N > 1$이고 $M > 1$)

PyTorch에서 tensor에 squeeze 함수를 적용했을 때 크기가 1인 차원을 제거하는 것과 유사하다고 볼 수 있다.

numpy ndarray에서 각각 차원이 0, 1, 2로 나타나는데, 이렇게 되면 경우에 따라 반복문을 사용할 수 있을 수도 있고 없을 수도 있다.

squeeze를 사용하면 항상 2차원으로 배열을 받을 수 있고, 차원의 크기를 알지 못하거나 가변 크기에 대해 반복문을 사용하기에 유용하다.

n, m = 2, 3

fig, axes = plt.subplots(n, m, squeeze=True, figsize=(m*2, n*2))
idx = 0
for i in range(n):
    for j in range(m):
        axes[i][j].set_title(idx)
        axes[i][j].set_xticks([])
        axes[i][j].set_yticks([])
        idx+=1

plt.show()

1644931916985

 

plt.subplots() 또는 plt.gca()로 받는 ax 리스트는 numpy ndarray로 전달되므로, 1중 반복문을 쓰고 싶다면 flatten() 메서드를 사용할 수 있다.

n, m = 2, 3

fig, axes = plt.subplots(n, m, figsize=(m*2, n*2))

for i, ax in enumerate(axes.flatten()):
    ax.set_title(i)
    ax.set_xticks([])
    ax.set_yticks([])


plt.show()

1644931925495

 

aspect는 $x$축 한 칸과 $y$축 한 칸의 비율을 의미하며, aspect = 0.5일 때는 $x$축 한 칸이 $y$축 두 칸과 길이가 같아진다.

fig = plt.figure(figsize=(12, 5))
ax1 = fig.add_subplot(121, aspect=1)
ax2 = fig.add_subplot(122, aspect=0.5)

ax2.set_xlim(0, 1)
ax2.set_ylim(0, 2)
plt.show()

1644931941539

 

 

Gridspec

Slicing을 사용하는 방법의 예시이다.

fig = plt.figure(figsize=(8, 5))

gs = fig.add_gridspec(3, 3) # make 3 by 3 grid (row, col)

ax = [None for _ in range(5)]

ax[0] = fig.add_subplot(gs[0, :]) 
ax[0].set_title('gs[0, :]')

ax[1] = fig.add_subplot(gs[1, :-1])
ax[1].set_title('gs[1, :-1]')

ax[2] = fig.add_subplot(gs[1:, -1])
ax[2].set_title('gs[1:, -1]')

ax[3] = fig.add_subplot(gs[-1, 0])
ax[3].set_title('gs[-1, 0]')

ax[4] = fig.add_subplot(gs[-1, -2])
ax[4].set_title('gs[-1, -2]')

for ix in range(5):
    ax[ix].set_xticks([])
    ax[ix].set_yticks([])

plt.tight_layout()
plt.show()

1644931948520

 

$x$, $y$, $dx$, $dy$를 사용하는 방법의 예시이다.

fig = plt.figure(figsize=(8, 5)) # initialize figure

ax = [None for _ in range(6)] # list to save many ax for setting parameter in each

ax[0] = plt.subplot2grid((3,4), (0,0), colspan=4)
ax[1] = plt.subplot2grid((3,4), (1,0), colspan=1)
ax[2] = plt.subplot2grid((3,4), (1,1), colspan=1)
ax[3] = plt.subplot2grid((3,4), (1,2), colspan=1)
ax[4] = plt.subplot2grid((3,4), (1,3), colspan=1,rowspan=2)
ax[5] = plt.subplot2grid((3,4), (2,0), colspan=3)


for ix in range(6): 
    ax[ix].set_title('ax[{}]'.format(ix)) # make ax title for distinguish:)
    ax[ix].set_xticks([]) # to remove x ticks
    ax[ix].set_yticks([]) # to remove y ticks
    
fig.tight_layout()
plt.show()

1644931971867

 

add_axes는 특정 플롯을 임의의 위치에 만드는 메소드인데, 위치를 조정하여 그래프를 그리는 게 쉽지는 않기 때문에 권장되지 않는다.

 

inset_axes는 미니맵 등 원하는 서브플롯을 그릴 때 사용할 수 있다. 표현하고자 하는 메인시각화를 해치지 않는 선에서 사용하는 것이 권장된다.

fig, ax = plt.subplots()

color=['royalblue', 'tomato']
ax.bar(['A', 'B'], [1, 2],
       color=color
      )

ax.margins(0.2)
axin = ax.inset_axes([0.8, 0.8, 0.2, 0.2])
axin.pie([1, 2], colors=color, 
         autopct='%1.0f%%')
plt.show()

1644931993543

 

make_axes_locatable는 사이드바를 추가할 때 사용하며, 일반적으로 colorbar 생성에 많이 쓰인다.

fig, ax = plt.subplots(1, 1)

# 이미지를 보여주는 시각화
# 2D 배열을 색으로 보여줌
im = ax.imshow(np.arange(100).reshape((10, 10)))

divider = make_axes_locatable(ax)
cax = divider.append_axes("right", size="5%", pad=0.05)

fig.colorbar(im, cax=cax)
plt.show()

1644932007848

 

 

Contents

글 주소를 복사했습니다

부족한 글 끝까지 읽어주셔서 감사합니다.
보충할 내용이 있으면 언제든지 댓글 남겨주세요.