코딩하는 해맑은 거북이

[데이터시각화] Line Plot 본문

Data Analysis & Viz

[데이터시각화] Line Plot

#CJE 2023. 3. 22.
본 게시물의 내용은 '부스트캠프 AI Tech - Data Visualization(안수빈)' 강의를 듣고 작성하였다.
해당 글은 아래의 6가지를 다룬다.
🍀 Line Plot
    🚩 New York Stock Exchange
🍀 추세에 집중
🍀 간격
🍀 보간
🍀 이중 축(dual axis) 사용
🍀 ETC

 

🍀 Line Plot

- Line Plot은 연속적으로 변화하는 값을 순서대로 점으로 나타내고, 이를 선으로 연결한 그래프
- 꺾은선 그래프, 선 그래프, line chart, line graph 등의 이름으로 사용됨
- 시간/순서에 대한 변화에 적합하여 추세를 살피기 위해 사용 (시계열 분석에 특화)
- 신기하게 .line이 아니라 .plot()

- 문법 자체는 이전 점 (x1,y1)에서 (x2,y2)로 잇고, (x2,y2)에서 (x3,y3)로 잇는 순차적인 선으로 구성된 그래프이다

import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt

fig, axes = plt.subplots(1, 2, figsize=(12, 7))

x1 = [1, 2, 3, 4, 5]
x2 = [1, 3, 2, 4, 5]
y = [1, 3, 2, 1, 5]

axes[0].plot(x1, y)
axes[1].plot(x2, y)

plt.show()

* 좀 더 테크닉을 사용하면 정N각형이나 원을 그릴 수 있다

fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111, aspect=1) # aspect : 비율 = 세로비율/가로비율

x = np.sin(np.linspace(0, 2*np.pi, 4))
y = np.cos(np.linspace(0, 2*np.pi, 4))

ax.plot(x, y)

plt.show()

fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111, aspect=1)

n = 1000
x = np.sin(np.linspace(0, 2*np.pi, n))
y = np.cos(np.linspace(0, 2*np.pi, n))

ax.plot(x, y)

plt.show()

가장 위쪽부터 시계방향으로 그려짐

 

- 5개 이하의 선을 사용하는 것을 추천
  → 더 많은 선은 중첩으로 인한 가독성이 하락하는 단점이 있다

- 선을 구별하는 요소

  • 색상 (color)
  • 마커 (marker, markersize) : 마커의 종류
  • 선의 종류 (linestyle, linewidth)
fig, ax = plt.subplots(1, 1, figsize=(5, 5))

np.random.seed(97)
x = np.arange(7)
y = np.random.rand(7)

ax.plot(x, y)

plt.show()

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

np.random.seed(97)
x = np.arange(7)
y = np.random.rand(7)

ax.plot(x, y,
        color='black',
        marker='o',   # 'o', '.', '^', '*'
        linestyle='solid',  
       )

plt.show()

 

- 시시각각 변동하는 데이터는 Noise로 인해 패턴 및 추세 파악이 어려움

  → Noise의 인지적인 방해를 줄이기 위해 smoothing을 사용

🚩 데이터셋 : New York Stock Exchange

stock = pd.read_csv('./prices.csv')
stock['date'] = pd.to_datetime(stock['date'], format='%Y-%m-%d', errors='raise')
stock.set_index("date", inplace = True)
stock

apple = stock[stock['symbol']=='AAPL']
google = stock[stock['symbol']=='GOOGL']
google.head()

fig, ax = plt.subplots(1, 1, figsize=(15, 7), dpi=300)

ax.plot(google.index, google['close'], label='google')
ax.plot(apple.index, apple['close'], label='apple')

plt.legend()
plt.show()

구글과 애플의 주식변동

 

* 이동평균으로 Noise 제거

google_rolling = google.rolling(window=20).mean()   # window 만큼 평균
fig, axes = plt.subplots(2, 1, figsize=(12, 7), dpi=300, sharex=True)  # dpi : 해상도

axes[0].plot(google.index,google['close'])
axes[1].plot(google_rolling.index,google_rolling['close'])

plt.show()

 

 

 

🍀 추세에 집중

- 추세를 보기 위한 목적이므로 Bar plot과 다르게 꼭 축을 0에 초점을 둘 필요는 없음
- 너무 구체적인 line plot보다는 생략된 line plot이 더 나을 수 있다.
  → Grid, Annotate 등 모두 제거
  → 디테일한 정보는 표로 제공하는 것을 추천
- 생략되지 않는 선에서 범위를 조정하여 변화율 관찰 (.set_ylim())

from matplotlib.ticker import MultipleLocator

fig = plt.figure(figsize=(12, 5))
np.random.seed(970725)

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


# Ax1
ax1 = fig.add_subplot(121)
ax1.plot(x, y,
         marker='o',
         linewidth=2)

ax1.xaxis.set_major_locator(MultipleLocator(1))   # x축 간격단위
ax1.yaxis.set_major_locator(MultipleLocator(0.05))    # y축 간격단위
ax1.grid(linewidth=0.3)    


# Ax2
ax2 = fig.add_subplot(122)
ax2.plot(x, y,
       linewidth=2,)

ax2.spines['top'].set_visible(False)
ax2.spines['right'].set_visible(False)

ax1.set_title(f"Line Plot (information)", loc='left', fontsize=12, va= 'bottom', fontweight='semibold')
ax2.set_title(f"Line Plot (clean)", loc='left', fontsize=12, va= 'bottom', fontweight='semibold')


plt.show()

 

 

 

🍀 간격

- 규칙적인 간격이 아니라면 오해를 줄 수 있다!

  • 그래프 상에서 규칙적일 때 : 기울기 정보의 오해
  • 그래프 상에서 간격이 다를 때 : 없는 데이터에 대해 있다고 오해

- 규칙적인 간격의 데이터가 아니라면 각 관측 값에 점으로 표시하여 오해를 줄이자

x = [2, 3, 5, 7, 9]
y = [2, 3, 4, 7, 10]

fig, ax = plt.subplots(1, 3, figsize=(13, 4))
ax[0].plot([str(i) for i in x], y)
ax[1].plot(x, y)
ax[2].plot(x, y, marker='o')

plt.show()

 

 

 

🍀 보간

- Line은 점을 이어 만드는 요소. -> 점과 점 사이에 데이터가 없기에 이를 잇는 방법(보간)
- 데이터의 error나 noise가 포함되어 있는 경우, 데이터의 이해를 돕는 방법

  • Moving Average
  • Smooth Curve with Scipy : 참고자료
    • scipy.interpolate.make_interp_spline()
    • scipy.interpolate.interp1d()
    • scipy.ndimage.gaussian_filter1d()

- Presentation에는 좋은 방법일 수 있으나, 없는 데이터를 있다고 생각하게 할 수 있으며 작은 차이를 없앨 수 있다는 단점이 있기 때문에 일반적인 분석에서는 지양한다

from scipy.interpolate import make_interp_spline, interp1d
import matplotlib.dates as dates

fig, ax = plt.subplots(1, 2, figsize=(20, 7), dpi=300)

date_np = google.index
value_np = google['close']

date_num = dates.date2num(date_np)

# smooth
date_num_smooth = np.linspace(date_num.min(), date_num.max(), 50) 
spl = make_interp_spline(date_num, value_np, k=3)
value_np_smooth = spl(date_num_smooth)

# print
ax[0].plot(date_np, value_np)
ax[1].plot(dates.num2date(date_num_smooth), value_np_smooth)

plt.show()

 

 

 

🍀 이중 축(dual axis) 사용

- 한 plot에 대해 2개의 축을 이중 축(dual axis)라고 함
- 같은 시간 축에 대해 서로 다른 종류의 데이터를 표현하기 위해서는 축이 2개가 필요

  •  .twinx()를 사용
fig, ax1 = plt.subplots(figsize=(12, 7), dpi=150)

# First Plot
color = 'royalblue'

ax1.plot(google.index, google['close'], color=color)
ax1.set_xlabel('date')
ax1.set_ylabel('close price', color=color)  
ax1.tick_params(axis='y', labelcolor=color)

# # Second Plot
ax2 = ax1.twinx()   # 이중축
color = 'tomato'

ax2.plot(google.index, google['volume'], color=color)
ax2.set_ylabel('volume', color=color)  
ax2.tick_params(axis='y', labelcolor=color)

ax1.set_title('Google Close Price & Volume', loc='left', fontsize=15)
plt.show()

- 2개의 plot을 그릴 때도 이중 축 사용할 수 있지만 상관관계가 없는데 있어보이는 단점이 있기 때문에 지양한다.

- 한 데이터에 대해 다른 단위 (ex. radian과 degree)

  • .secondary_xaxis(), .secondary_yaxis() 사용 : 참고자료
def deg2rad(x):
    return x * np.pi / 180

def rad2deg(x):
    return x * 180 / np.pi

fig, ax = plt.subplots()
x = np.arange(0, 360)
y = np.sin(2 * x * np.pi / 180)
ax.plot(x, y)
ax.set_xlabel('angle [degrees]')
ax.set_ylabel('signal')
ax.set_title('Sine wave')
secax = ax.secondary_xaxis('top', functions=(deg2rad, rad2deg))
secax.set_xlabel('angle [rad]')
plt.show()

sin 그래프 - degree, radian 축

 

 

🍀 ETC

- 라인 끝 단에 레이블을 추가하면 식별에 도움 (범례 대신)

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

x = np.linspace(0, 2*np.pi, 1000)
y1 = np.sin(x)
y2 = np.cos(x)


ax = fig.add_subplot(111, aspect=1)
ax.plot(x, y1,
       color='#1ABDE9',
       linewidth=2, label='sin')

ax.plot(x, y2,
       color='#F36E8E',
       linewidth=2, label='cos')

ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

ax.legend(loc='upper center')

plt.show()

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

x = np.linspace(0, 2*np.pi, 1000)
y1 = np.sin(x)
y2 = np.cos(x)

# Ax2
ax = fig.add_subplot(111, aspect=1)
ax.plot(x, y1,
       color='#1ABDE9',
       linewidth=2,)

ax.plot(x, y2,
       color='#F36E8E',
       linewidth=2,)

ax.text(x[-1]+0.1, y1[-1], s='sin', fontweight='bold',
         va='center', ha='left', 
         bbox=dict(boxstyle='round,pad=0.3', fc='#1ABDE9', ec='black', alpha=0.3))

ax.text(x[-1]+0.1, y2[-1], s='cos', fontweight='bold',
         va='center', ha='left', 
         bbox=dict(boxstyle='round,pad=0.3', fc='#F36E8E', ec='black', alpha=0.3))


ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)

plt.show()

 

 

- Min/Max 정보(또는 원하는 포인트)는 추가해주면 도움이 될 수 있음 (annatation)

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

np.random.seed(97)

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.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.scatter(x[np.argmin(y)], np.min(y), 
            c='royalblue',s=50, zorder=20)  # zorder : 점선이 실선보다 위에 있게

plt.show()

 

- 보다 연한 색을 사용하여 uncertainty 표현 가능 (신뢰구간, 분산 등)

ex

 

 

 

 

'Data Analysis & Viz' 카테고리의 다른 글

[데이터시각화] Text  (0) 2023.03.22
[데이터시각화] Scatter Plot  (0) 2023.03.22
[데이터시각화] Bar Plot  (0) 2023.03.22
[데이터시각화] Matplotlib  (0) 2023.03.21
[데이터시각화] 시각화의 요소  (0) 2023.03.21
Comments