Line Plot은 연속적으로 변화하는 값을 순서대로 점으로 나타내고 이를 선으로 연결한 그래프
꺽은선 그래프, 선 그래프, line chart, line graph 등으로 불리움
시간/순서에 대한 변화에 적합하여 추세를 살피기 위해 사용
.plot()
으로 사용할 수 있다.
5개 이하의 선을 사용하는 것을 추천
이를 구별하는 요소는 아래와 같다.
시시각각 변하는 데이터는 Noise로 인해 패턴 및 추세 파악이 어려움
Noise의 인지적인 방해를 줄이기 위해 smoothing을 사용한다.
Bar Plot과 다르게 꼭 축을 0에 초점을 둘 필요는 없음
너무 구체적인 line plot보다는 생략된 line plot이 더 나을 수 있다.
생략되지 않는 선에서 범위를 조정하여 변화율 관찰(.set_ylim()
)
규칙적인 간격이 아니라면 오해를 줄 수 있음
Line은 점을 이어 만들기 때문에 점과 점 사이의 데이터가 없기에 이를 잇는 방법(보간)
데이터의 error나 noise가 포함되어 있는 경우, 데이터의 이해를 돕는 방법
Moving Average
Smooth Curve with Scipy
scipy.interpolate.make_interp_spline()
scipy.interpolate.interp1d()
scipy.ndimage.gaussian_filter1d()
Presentation에는 좋은 방법이나 아래와 같은 오해를 일으킬 수 있다.
한 plot에 대해 2개의 축을 이중 축(dual axis)라고 한다.
같은 시간 축에 대해 서로 다른 종류의 데이터를 표현하기 위하여
.twinx()
한 데이터에 대해 다른 단위(ex. radian과 degree)
- .secondary_xaxis()
, .secondary_yaxis()
2개의 plot을 그리는 것은 이중 축을 사용한다. 이중 축을 사용하는거보다 그래프를 2개 사용하는게 가독성이 좋은 경우가 많다.
범례 대신 라인 끝 단에 레이블을 추가하면 식별에 도움이 된다.
min/max 정보는 추가해주면 도움이 될 수 있다.(annotation)
연한색을 사용하여 uncertainty 표현(신뢰구간, 분산 등)
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()
fig = plt.figure(figsize=(5,5))
ax = fig.add_subplot(1, 1, 1)
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()
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='*',
linestyle='solid',
)
plt.show()
line style
solid
, dashed
, dashdot
, dotted
, None
'--'
, -.
, -.
, :
위의 2가지 방식으로 설정 가능
Data : New York Stock Exchange - prices.csv
Date 컬럼을 index로 설정하여 다룸(시간은 삭제하여 지정)
편의를 위해 google, apple의 주식을 가지고 실습을 진행한다.
시시각각 변하는 데이이기 때문에 어떤 구간에 대해 평균으로 대체를 하는 방법
# window로 몇 개의 구간을 볼지 설정
google_rolling = google.rolling(window=4).mean()
# dpi: 해상도, sharex: x축 공유
fig, axes = plt.subplots(2, 1, figsize=(12, 7), dpi=300, sharex=True)
axes[0].plot(google.index,google['close'])
axes[1].plot(google_rolling.index,google_rolling['close'])
plt.show()
ax.xaxis.set_major_locator(MultipleLocator(1)
: x축에 대한 정보
ax.yaxis.set_major_locator(MultipleLocator(0.5)
: y축에 대한 정보
ax.grid(linewidth=0.3)
: grid 두께를 조정하여 line의 두께와 구별
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()
secondary-xaxis()
사용하기 : 같은 정보를 다룰 때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()
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()
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)
plt.show()