반응형

시각화를 진행하다보면 데이터로 그려진 그래프만으로는 부족한 경우가 있습니다. 아래와 같은 사례가 있을 수 있죠.

  • 특정 값 (최대, 최소 등)에 대한 지칭이 필요하다. 
  • 어느 한점으로부터 얼마나 멀리 떨어져 있는지 시각적으로 바로 알아차리게 하고 싶다.
  • 특정한 구간을 표시하고 싶다. 

이번 글에서는 시각화 효과를 높이기 위해 다양한 도구들에 대해  살펴보려고 합니다. 

다양한 그리드 생성하기 

matplotlib에서는 pyplot.grid를 통해 그리드를 생성할 수 있습니다. 하지만, 그리드의 사전적 의미처럼 격자 형태의 비교적 단순한 형태의 그리드만 생성할 수 있어 유연성에 있어서는 조금 아쉽습니다. 대신에 matplotlib에서 제공하고 있는 다양한 차트 시각화 도구를 이용해 색상, 선의 유형, 두께 등을 조절해서 조금 덜 보이도록 해서 다양한 그리드를 생성할 수 있습니다. 여기선 직선과 원 형태의 그리드의 간단한 형태를 생성해보도록 하겠습니다. 

   

먼저, 아래와 같이 [0,1] 사이에 10개의 랜덤 데이터를 생성하겠습니다. 이 데이터를 바탕으로 다양한 보조선을 그려보도록 하겠습니다.

 

import numpy as np
import matplotlib.pyplot as plt

x = np.random.uniform(0, 1, size=10)
y = np.random.uniform(0, 1, size=10)
np.random.seed(1)

 

# 실습 1. x + y = c 그리기

x + y = c (c는 바뀜)직선을 그리는 방법은 1차 함수의 x, y 절편을 변화시키면서 그 값을 변화시켜주면 됩니다. 주된 그래프가 아니기 때문에 잘 보이지 않게 점선(--), 회색, 투명도를 설정하고 그려줄 수 있습니다. 

 

fig, ax = plt.subplots()
ax.scatter(x, y)

# Grid : x + y = c
x_start = np.linspace(0, 2.2, 12, endpoint=True) # 절편 값 변화에 따라 나눔

for xs in x_start:
    ax.plot([xs, 0], [0, xs], linestyle='--', color='gray', alpha=0.5, linewidth=1)

ax.set_title(r"Grid ($x+y=c$)", fontsize=15,va= 'center', fontweight='semibold')
ax.set_xlim(0, 1.1) 
ax.set_ylim(0, 1.1)

plt.show()

 

# 실습 2. y = cx 그리기

y = cx (c는 바뀜) 직선은 위와 다르게 기울기가 변화하는 직선입니다. 이를 그리는 방법은 기울기의 변화를 원하는 방식으로 변화를 주면서 직선을 그려주면 됩니다. 메인 그래프가 아니라 그리드이기 때문에 잘 보이지 않게 점선(--), 회색, 투명도를 설정하고 그려줄 수 있습니다. 

 

fig, ax= plt.subplots()
ax.scatter(x, y)

# Grid : y = cx
radian = np.linspace(0, np.pi/2, 11, endpoint=True) # (여기선 동일하게) 각도를 나눔 

for rad in radian:
    ax.plot([0,2], [0, 2*np.tan(rad)], linestyle='--', color='gray', alpha=0.5, linewidth=1)

ax.set_title(r"Grid ($y=cx$)", fontsize=15,va= 'center', fontweight='semibold')
ax.set_xlim(0, 1.1)
ax.set_ylim(0, 1.1)

plt.show()

 

# 실습 3. (a, b)가 중심인 원 그리기

특정 점에서 얼마나 떨어져 있는지 살펴보기 위해선 원형 그리드가 효과적입니다. 실제로 (유클리드 공간에서) 원의 정의가 같은 거리에 있는 점들의 집합이기 때문에 정확한 활용이죠. 여기선 x[2], y[2] 값을 중심으로 얼마나 떨어져 있는지 살펴보는 코드는 아래와 같습니다. (그림을 보면 조금 이상하긴 하지만... 조금씩만 조정해주면 될 것 같습니다)

 

fig, ax= plt.subplots()
ax.scatter(x, y)

## Grid : (x-a)**2 + (y-b)**2 = r**2
a = x[2]
b = y[2]
rs = np.linspace(0.1, 0.8, 8, endpoint=True)

for r in rs:
    xx = r*np.cos(np.linspace(0, 2*np.pi, 100))
    yy = r*np.sin(np.linspace(0, 2*np.pi, 100))
    ax.plot(xx+a, yy+b, linestyle='--', color='gray', alpha=0.5, linewidth=1)

    ax.text(a+r*np.cos(np.pi/4), b-r*np.sin(np.pi/4), f'{r:.1}', color='gray')

ax.set_title(r"Grid ($(x-a)^2+(y-b)^2=c$)", fontsize=15,va= 'center', fontweight='semibold')
ax.set_xlim(0, 1.1)
ax.set_ylim(0, 1.1)

plt.show()

 

왼쪽으로 길어서 찌그러져 있어 보이지만.. 원(에 가까운 다각형) 맞습니다.

보조 선/면 그리기

시각화는 데이터를 보기 좋게 만드는 것입니다. 앞서 그리드 외에도 데이터를 살펴보기 좋게끔 만들기 위해 보조 선/면을 그리는 방법이 있습니다. 아래 그림은 kaggle에서 볼 수 있는 시각화 사례입니다.

 

면적을 활용해 효과적인 시각화 사례 : 연령대별 넷플릭스 평가 분포 [1]

 

pyplot에서 보조선(axhline, axvline)과 보조면(axhspan, axvspan)을 그릴 수 있는 다양한 메서드를 제공하고 있습니다.

# 실습 4. 보조 선 그리기 

보조 선을 그리는 방법은 앞에서 설명한 메서드(axvline, axhline)을 사용하거나 pyplot.plot 을 사용하는 방법이 있습니다. 정답은 없고, 둘 중 편한 것을 사용하면 될 것 같습니다. 아래 코드는 두가지 모두 사용한 방법을 기재했습니다. 조금 주의할 것은 axvline, axhline에서 xmin과 xmax는 0~1 사이의 상대적인 위치를 넣어야 하기 때문에 표화가 필요합니다. 

 

import numpy as np
import matplotlib.pyplot as plt

fig = plt.figure()

x = np.arange(20)
y = np.random.rand(20)

ax = fig.add_subplot(111)
ax.plot(x, y,
       color='lightgray',
       linewidth=2,)

ax.set_xlim(-1, 21)

# max
# ax.plot([-1, x[np.argmax(y)]], [np.max(y)]*2,
#         linestyle='--', color='tomato')
ax.axhline(y=np.max(y), xmin=0, xmax= x[np.argmax(y)] / len(x), 
           linestyle='--', color='tomato')
ax.scatter(x[np.argmax(y)], np.max(y),
            c='tomato',s=50, zorder=20)

# min
# ax.plot([-1, x[np.argmin(y)]], [np.min(y)]*2,
#         linestyle='--', color='royalblue')
ax.axhline(y=np.min(y), xmin=0, xmax= x[np.argmin(y)] / len(x), 
           linestyle='--', color='royalblue')
ax.scatter(x[np.argmin(y)], np.min(y),
            c='royalblue',s=50, zorder=20)

plt.show()

 

# 실습 5. 보조 면 그리기

보조 면의 사용은 axvspan, axhspan을 통해 사용이 가능합니다. 사용방법은 위에 보조선과 거의 유사합니다.

 

import matplotlib.pyplot as plt

fig, ax = plt.subplots()

ax.set_aspect(1)
ax.axvspan(0,0.5, ymin=0.3, ymax=0.7, color='red')
ax.axhspan(0.3,0.7, xmin=0.3, xmax=0.7, color='blue')

plt.show()

ax.set_xlim(-0.1, 1)
ax.set_ylim(-0.1, 1)

plt.show()

 

참고자료

[1] 🎬 Storytelling with Data - Netflix ver. (kaggle.com)

 

 

 

반응형