Skillset/Python

[시각화] 파이썬 그래프 위에 글자 쓰기 (ax.patches, ax.text)

Everly. 2022. 7. 9. 09:04

파이썬 그래프를 그렸는데, 바로 밑의 그림처럼 그래프 위에 비율까지 쓰고 싶은 경우가 있을 것이다.

이럴 때 사용하면 유용한 파이썬 seaborn에서 제공하는 ax.patches, ax.text 메서드를 활용하면 손쉽게 그릴 수 있다.

 

오늘 만들어볼 결과물

 

먼저 데이터셋은 캐글 Categorical Feature Encoding Challenge 에서 제공하는 'train.csv' 파일을 활용하였다.

NOTE: 코드는 저의 깃허브에서 내려받을 수 있습니다! 

 

import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns

df = pd.read_csv('train.csv', index_col = 'id')
df.head()

 

먼저 데이터셋을 불러왔다. 오늘 활용할 변수는 'nom_1' 이라는 범주형 변수이다. 

이 변수는 6개의 도형 값을 갖는 범주형 변수이므로, 분포 파악을 위해 seaborn의 countplot을 활용하였다.

 

plt.figure(figsize = (8, 5))
ax = sns.countplot(x = 'nom_1', data = df, color = 'skyblue')
plt.show()

 

y축인 count는 개수를 의미한다.

그래서 Trapezoid가 가장 많은 건 알겠고, 약 10만개인 것도 알겠는데.. 뭔가 좀 심심하다.

Trapezoid가 nom_1이라는 변수 내에서 차지하는 비율이 몇 %인지가 궁금하다! 

 

ax.patches

 

먼저 ax 객체의 patches를 뽑아본다.

나온 값은 위 그래프의 6개의 바(bar) 각각을 의미한다. 즉, ax.patches[0]는 가장 왼쪽 값, Triangle의 bar를 의미한다.

 

먼저 Triangle 위에 비율을 써보겠다.

Triangle을 나타내는 bar를 rec라는 객체로 따로 저장하고, height(세로길이), width(가로길이), get_x(왼쪽 테두리 x축) 값을 뽑아보자.

 

# 여기서 가장 왼쪽 bar의 값(Triangle)에 대해서만 먼저 해보자! 
rec = ax.patches[0]
    # 각각 왼쪽 bar의 높이(개수), 가로길이, 왼쪽 테두리의 x축 
print(rec.get_height(), rec.get_width(), rec.get_x())

 

이를 그림으로 나타내면 다음과 같다.

 

우리는 rec 객체의 가장 위쪽 부분에 비율을 써줄 것이므로, 이렇게 구한 숫자값들을 활용해 비율을 써줄 위치의 x좌표, y좌표를 구할 것이다.

 

그럼 x좌표와 y좌표 값은 어떻게 구할 수 있을까?

 

  • x좌표: bar의 가장 정 가운데 x좌표를 구해야 한다. 그러므로 get_x 값에, get_width의 절반을 더하자.
  • y좌표: bar의 세로길이로 지정해도 되지만, 그렇게 하면 bar에 너무 밀착되어 텍스트가 쓰여지므로 get_height에 일정 높이를 더해준다. 여기선 데이터프레임의 전체 데이터 수에 0.01을 곱한 값을 썼다.

 

마지막으로 Triangle의 비율은 get_height가 세로길이이자 Triangle의 개수와 같으므로, 이 값을 전체 데이터 수에 대해 나누면 된다.

 

# 비율을 써줄 텍스트는 왼쪽 bar의 바로 위에 써줄 것이다
#Triangle 뽑기
left_square = df['nom_1'].unique()[0]

print('x좌표: ', rec.get_x() + rec.get_width()/2)
print('y좌표: ', rec.get_height() + len(df)*0.01)
print(f'{left_square}의 비율: ', (rec.get_height()/len(df))*100, '%')

 

이렇게 해서 비율을 써줄 x,y좌표는 (x, y) = (0, 32855) 이고, 비율 값은 약 10%이다.

구한 값을 그대로 그래프에 써주자. 

 

  • ax.text 옵션
    • x: x좌표
    • y: y좌표
    • s: 텍스트로 쓰고자하는 내용 
    • ha: 데이터 수평 정렬(horizontal alignment)
# 적용
plt.figure(figsize = (8, 5))
ax = sns.countplot(x = 'nom_1', data = df, color = 'skyblue')
ax.text(x = rec.get_x() + rec.get_width()/2,
            y = rec.get_height() + len(df)*0.001,
            s =  f'{rec.get_height()/len(df)*100:1.1f}%',
           ha = 'center')

plt.rc('font', size = 11)
plt.show()

 

이렇게 10%라는 값이 나왔다.

참고로 s에 써준 텍스트에 1.1f를 썼는데, 이는 소수점 1자리수까지만 보여주게 된다.

 

나머지 Trapezoid ~ Circle 에 대해서도 비율 값을 써주자. 앞에서 ax.patches가 6개 Bar의 값을 갖고 있었으므로 for문으로 연결해주면 되겠지?

 

# for문으로 연결해서 모든 nom_1의 고유값에도 비율을 써보자
plt.figure(figsize = (8, 5))
ax = sns.countplot(x = 'nom_1', data = df, color = 'skyblue')

for patch in ax.patches:
    # 2개의 patch 값을 가짐
    ax.text(x = patch.get_x() + patch.get_width()/2,
               y = patch.get_height() + len(df)*0.001,
               s = f'{(patch.get_height()/len(df))*100: 1.1f}%',
               ha = 'center')
    
plt.rc('font', size = 11)
plt.show()

 

완성!

반응형