Matplotlib 보조 축

Beginner

This tutorial is from open-source community. Access the source code

소개

Matplotlib 는 Python 에서 널리 사용되는 데이터 시각화 라이브러리입니다. 때로는 동일한 그래프에 서로 다른 스케일의 데이터를 표시해야 할 때가 있는데, 이때 보조 축 (secondary axis) 의 개념이 유용하게 사용됩니다. 이 랩에서는 Matplotlib 에서 보조 축을 만드는 방법을 배우겠습니다.

VM 팁

VM 시작이 완료되면 왼쪽 상단을 클릭하여 Notebook 탭으로 전환하여 실습을 위해 Jupyter Notebook에 액세스하십시오.

때로는 Jupyter Notebook 이 로딩을 완료하는 데 몇 초 정도 기다려야 할 수 있습니다. Jupyter Notebook 의 제한 사항으로 인해 작업의 유효성 검사는 자동화할 수 없습니다.

학습 중에 문제가 발생하면 언제든지 Labby 에게 문의하십시오. 세션 후 피드백을 제공해주시면 문제를 신속하게 해결해 드리겠습니다.

필요한 라이브러리 가져오기

먼저 필요한 라이브러리인 matplotlib, numpy, 그리고 datetime을 가져오는 것으로 시작합니다.

import datetime
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates
from matplotlib.ticker import AutoMinorLocator

데이터 플롯

보조 축의 사용법을 시연하기 위해 간단한 사인파를 생성합니다. x 축으로 도 (degrees) 를 사용하여 사인파를 플롯합니다.

fig, ax = plt.subplots(layout='constrained')
x = np.arange(0, 360, 1)
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')

보조 축 생성

이제 보조 축을 생성하고 x 축을 도 (degrees) 에서 라디안 (radians) 으로 변환합니다. 순방향 함수로 deg2rad를 사용하고 역방향 함수로 rad2deg를 사용합니다.

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

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

secax = ax.secondary_xaxis('top', functions=(deg2rad, rad2deg))
secax.set_xlabel('angle [rad]')

다른 예시 플롯

이제 파수 (wavenumber) 에서 파장 (wavelength) 으로 변환하는 또 다른 예시를 로그 - 로그 (log-log) 스케일로 플롯합니다. 이 예시에서는 임의 스펙트럼을 사용합니다.

fig, ax = plt.subplots(layout='constrained')
x = np.arange(0.02, 1, 0.02)
np.random.seed(19680801)
y = np.random.randn(len(x)) ** 2
ax.loglog(x, y)
ax.set_xlabel('f [Hz]')
ax.set_ylabel('PSD')
ax.set_title('Random spectrum')

보조 X 축 생성

이제 보조 x 축을 생성하고 주파수 (frequency) 에서 주기 (period) 로 변환합니다. 순방향 함수로 one_over를 사용하고 역방향 함수로 inverse를 사용합니다.

def one_over(x):
    """Vectorized 1/x, treating x==0 manually"""
    x = np.array(x, float)
    near_zero = np.isclose(x, 0)
    x[near_zero] = np.inf
    x[~near_zero] = 1 / x[~near_zero]
    return x

## the function "1/x" is its own inverse
inverse = one_over

secax = ax.secondary_xaxis('top', functions=(one_over, inverse))
secax.set_xlabel('period [s]')

보조 Y 축 생성

이제 데이터에서 임시로 파생되고 경험적으로 유도된 변환에서 축을 연결하는 세 번째 예시를 생성합니다. 이 경우, 순방향 및 역방향 변환 함수를 한 데이터 세트에서 다른 데이터 세트로의 선형 보간 (linear interpolation) 으로 설정합니다.

fig, ax = plt.subplots(layout='constrained')
xdata = np.arange(1, 11, 0.4)
ydata = np.random.randn(len(xdata))
ax.plot(xdata, ydata, label='Plotted data')

xold = np.arange(0, 11, 0.2)
## fake data set relating x coordinate to another data-derived coordinate.
## xnew must be monotonic, so we sort...
xnew = np.sort(10 * np.exp(-xold / 4) + np.random.randn(len(xold)) / 3)

ax.plot(xold[3:], xnew[3:], label='Transform data')
ax.set_xlabel('X [m]')
ax.legend()

def forward(x):
    return np.interp(x, xold, xnew)

def inverse(x):
    return np.interp(x, xnew, xold)

secax = ax.secondary_xaxis('top', functions=(forward, inverse))
secax.xaxis.set_minor_locator(AutoMinorLocator())
secax.set_xlabel('$X_{other}$')

여러 축 생성

이제 np.datetime64를 x 축의 연도별 날짜 (yearday) 로, 섭씨 (Celsius) 를 화씨 (Fahrenheit) 로 변환하는 마지막 예시를 생성합니다. 또한 세 번째 y 축을 추가하고 위치 인수로 float 를 사용하여 배치합니다.

dates = [datetime.datetime(2018, 1, 1) + datetime.timedelta(hours=k * 6)
         for k in range(240)]
temperature = np.random.randn(len(dates)) * 4 + 6.7
fig, ax = plt.subplots(layout='constrained')

ax.plot(dates, temperature)
ax.set_ylabel(r'$T\ [^oC]$')
plt.xticks(rotation=70)

def date2yday(x):
    """Convert matplotlib datenum to days since 2018-01-01."""
    y = x - mdates.date2num(datetime.datetime(2018, 1, 1))
    return y

def yday2date(x):
    """Return a matplotlib datenum for *x* days after 2018-01-01."""
    y = x + mdates.date2num(datetime.datetime(2018, 1, 1))
    return y

secax_x = ax.secondary_xaxis('top', functions=(date2yday, yday2date))
secax_x.set_xlabel('yday [2018]')

def celsius_to_fahrenheit(x):
    return x * 1.8 + 32

def fahrenheit_to_celsius(x):
    return (x - 32) / 1.8

secax_y = ax.secondary_yaxis(
    'right', functions=(celsius_to_fahrenheit, fahrenheit_to_celsius))
secax_y.set_ylabel(r'$T\ [^oF]$')

def celsius_to_anomaly(x):
    return (x - np.mean(temperature))

def anomaly_to_celsius(x):
    return (x + np.mean(temperature))

## use of a float for the position:
secax_y2 = ax.secondary_yaxis(
    1.2, functions=(celsius_to_anomaly, anomaly_to_celsius))
secax_y2.set_ylabel(r'$T - \overline{T}\ [^oC]$')

요약

이 랩에서는 Matplotlib 에서 보조 축을 생성하는 방법을 배웠습니다. 보조 축의 개념과 이를 생성하는 방법을 설명하기 위해 다양한 예시를 사용했습니다.