본문 바로가기
Data Science/Data Visualization

[matplotlib] Figure에서 Axes 요리하기(실습)

by Finn# 2024. 10. 30.
728x90

GDGoC_CNU_10월_시각화_(1).ipynb
0.27MB

 

Intro

이전 게시글에서 하나의 Figure에 여러 개의 Ax를 다루는 방법을 총 3가지 학습했습니다. 아주 원초적인 접근으로 Ax의 위치를 좌측 상단의 점으로 보고 좌표평면을 도입하는 방법과 Figure 자체를 격자구조로 나뉘어 한 공간씩 Ax를 정의하는 방법 그리고 이렇게 나뉜 격자구조를 이어서 좀 더 유연하게 공간을 정의하는 방법까지 공부해 보았습니다. 이번 칼럼을 통해서 저희는 실제 코드를 통해 학습했던 내용을 구현해 보겠습니다.


[실습] Figure에 여러 개의 Ax를 그려보자

Figure에서 Ax를 담는 코드는 여러 가지 방법 중 저희가 처음 배웠던 가장 자유도가 높은 방법부터 코드 작성을 시작하겠습니다.

 

해당 방법은 Ax(x, y, width, height) 값을 주어 Figure에 Ax의 직접적인 위치와 크기 정보 나타냅니다. 사용하는 함수는 add_axes([x, y, width, height])입니다.  또한 하나의 Figure에 하나의 Ax로 제약되는 것이 아니라 Figure에 필요한 만큼 Ax(x, y, width, height) 쌍 정보를 전달해 준다면 하나의 Figure에 여러 Axes를 담을 수 있다고 소개했습니다. 아래 코드를 참고해 보시면 실제로 하나의 Figure에 4개의 Axes를 생성한 것을 알 수 있습니다. 실제 코드와 결과를 확인해 보세요.

 

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

ax1 = fig.add_axes([0, 0.5+0.1, 0.5, 0.5])
ax1.set_title('ax1')

ax2 = fig.add_axes([0.5+0.1,0.5+0.1, 0.5, 0.5], sharey=ax1)
ax2.set_title('ax2')

ax3 = fig.add_axes([0, 0, 0.5, 0.5], sharey=ax1)
ax3.set_title('ax3')

ax4 = fig.add_axes([0.5+0.1, 0, 0.5, 0.5], sharey=ax1)
ax4.set_title('ax4')

 

코드의 결과가 이런식으로 나왔다. (0,0)이 어디인지 확인해보자 !

 

한 가지 살펴봐야 할 내용은 (0, 0), (0, 0.5), (0.5, 0), (0.5, 0.5)가 아니라 중간에 0.1씩 더해진 부분들이 보입니다. 이는 저희가 Point를 기점으로 Ax 공간을 펼치기에 Point가 겹치게 되면 추후 축값도 아예 겹쳐버리는 상황이 와서 그래프의 가독성을 떨어뜨리게 됩니다. 따라서 가독성 유지를 위해 일부로 0.1 정도의 간격을 뒀다 정도로 이해해 주시면 좋을 것 같습니다. 사실 코드 자체도 어렵지 않은 코드라서 지금까지 배웠던 내용들을 상기시키면서 코드가 무엇을 의미하는지 생각해 보며 따라 쳐보시면 좋을 것 같습니다.


[실습] 여러 개의 Ax를 반듯하게 배치할 수 있을까?

지금까지 다뤘던 (x, y, width, height)를 통해서 격자구조에 맞게 각가의 Axes를 배치할 수도 있으나 이렇게 하면 너무 비효율적이고 불편하다고 느끼실 겁니다. 이런 불편함을 해결해 줄 수 있는 방법이 있을까요? 이전에 소개해드린 대로 subplot을 통해 Figure를 지정한 행과 열의 크기에 맞게 잘라서 각각 공간을 활용할 수 있는 방법이 있습니다.

subplot을 활용하면 Figure가 격자구조로 나뉜 모습을 알 수 있다.

 

add_axes 함수와 사용하는 방법은 비슷하나 행과 열을 정의하고 byrow를 기준으로 순차적으로 공간에 Index를 부여합니다. add_subplot()의 argument로서 행과 열을 표기하는 방식은 여러 가지가 있습니다만 저는 아래 코드에서 편의상 2,2, n을 22n으로 표기했습니다. 여러분들은 2,2, n으로 표기하시길 추천합니다.

 

fig = plt.figure(figsize=(6.5,6.5))

ax1 = fig.add_subplot(221)
ax1.set_title('ax1')

ax2 = fig.add_subplot(222, sharey=ax1)
ax2.set_title('ax2')

ax3 = fig.add_subplot(223, sharey=ax1)
ax3.set_title('ax3')

ax4 = fig.add_subplot(224, sharey=ax1)
ax4.set_title('ax4')

plt.tight_layout()
plt.show()

결과를 확인해보면 반듯하게 나온 것을 확인해볼 수 있습니다

 

아마 평소에 하나의 Figure에 여러 Axes를 넣을 때 subplot을 많이 사용하셨을 것 같습니다. 하지만 꼭 Ax의 x, y, width, height를 입력해서 Point 방식으로 Ax평면을 정의하는 것도 익혀두시기 바랍니다.


[실습] 여러 개의 Ax를 반듯하게 배치하되 좀 더 유연하게 할 수 있을까?

앞서 소개한 add_subplot 방식으로 행, 열을 반듯하게 자르고 배치하는 방식은 너비와 높이가 지나치게 제한되어 데이터를 표현하기 어려울 수도 있다고 소개했었습니다. 이럴 때는 어떻게 해야 할까요?

격자구조를 활용해서 Ax 영역을 정의할 수 있었고 훨씬 깔끔하게 제어할 수 있습니다

 

이전 게시글에서도 소개했지만 격자 구조는 유지하면서 앞/뒤 양옆으로 칸을 확장하여 유연하게 Plot을 그리고 싶다면 matplotlib 모듈에서 제공하는 Gridspec을 통해 제어가능한 격자구조를 만든 후, add_subplot()의 argument로 해당 값을 활용해서 유연하게 공간 Ax를 정의할 수 있습니다. 실제 코드를 통해서 살펴보면서 add_subplot이랑 어떤 부분에서 차이가 있는지 확인해 보세요!

 

import matplotlib.gridspec as gridspec

fig = plt.figure(figsize=(8, 8))
grid = gridspec.GridSpec(3, 3, figure=fig)

ax1 = fig.add_subplot(grid[0, 0:2])
ax1.set_title('Plot 1')

ax2 = fig.add_subplot(grid[0, 2])
ax2.set_title('Plot 2')

ax3 = fig.add_subplot(grid[1:, 0])
ax3.set_title('Plot 3')

ax4 = fig.add_subplot(grid[1, 1:])
ax4.set_title('Plot 4')

ax5 = fig.add_subplot(grid[2, 1:])
ax5.set_title('Plot 5')

plt.tight_layout()
plt.show()

 

실제 코드와 매칭시켜보면 슬라이드를 허용한 [행, 열] 구조로 Ax공간을 정의한 것이 보인다

 

생성한 격자(Grid)의 을 정의해 나감에 슬라이싱을 활용해서 격자 단위로 확장한 상태로 Ax 공간이 정의된 것을 확인해 볼 수 있습니다. 이처럼 비교적 정돈된 상황에서 Plot을 정의하되 유연성을 추가하여 Ax 공간을 정의하는 방법까지 살펴보았습니다. 지금까지 소개드린 내용을 제대로 학습하셨다면 어떤 데이터가 주어졌을 때 그래프를 구성하는 기본 구조와 Axes는 어떤 식으로 나눌지 설계가 가능하실 것이라 생각합니다. 물론 설계를 바탕으로 공간 정의까지 코드로 깔끔하게 구현할 수 있을 것입니다.

 

이렇게 나뉜 공간에는 데이터 특성에 따라 적합한 Plot을 정의해서 넣기만 하면 됩니다. 처음 칼럼에서 그래프의 기본 구조를 만든 후 마지막에 Plot을 넣었던 것처럼 이렇게 여러 공간으로 나뉜 Ax 공간을 특정하여 Plot을 그려주면 그 공간에만 Plot이 그려지게 됩니다.

 

data = pd.DataFrame({'x': range(10), 'y': range(10, 20)})

# seaborn
sns.heatmap([[1,2,3],[2,1,3]], ax=ax1, cbar=False)

# pandas
data.plot(x='x', y='y', ax=ax2)

# matplotlib
ax4.scatter(data['x'], data['y'])

# check
fig

실제로 특정 Ax로 Plot을 그리라고 지정한 곳만 Plot이 그려져 있습니다

 

그래프를 그리는 방식이 저마다 달라서 seaborn, pandas.plot, matplotlib 방식 모두 ax를 어떻게 지정하는지 코드로 다뤄봤습니다. 이 가정까지 확인해 보셨다면 Figure에서 Ax를 다루는 방법을 얼마나 중요한지 느끼실 것 같습니다. 이를 정확하게 이해하는 것이 데이터 시각화를 본격적으로 다루기 전에 반드시 선행되어야 한다고 봅니다. 이것으로 시각화를 위한 Figure, Ax 구조에 대한 설명을 마치도록 하겠습니다. 반복 숙달해서 연습하시길 바랍니다.


Outro

지금까지 배웠던 모든 내용들을 적절히 혼재해서 사용한다면 데이터 시각화를 유연하게 할 수 있는 기본적인 역량이 쌓였을 것이라 생각합니다. 그래프마다 레이블을 다는 것과 색을 지정하는 등의 부가적인 요소들은 여러분들이 필요하시다면 배워서 적용하면 충분하실 것 같습니다. 가장 중요한 것은 구조를 이해하고 Plot을 넣을 공간을 자유자재로 다룰 수 있는 능력이 선행되어야 한다고 생각하기 때문에 이런 점들을 숙고하셔서 작업하시면 많은 도움이 될 것 같습니다.

 

관련 내용은 아래 영상으로도 제공하고 있으니 참고해 보시면 좋을 것 같습니다! 구독, 좋아요, 알람설정 부탁드립니다.

 

 

인스타 주소

https://www.instagram.com/f.inn_sharp/

 

반응형