IT/AI\ML

ipywidgets 사용법 (1)

개발자 두더지 2021. 4. 6. 16:55
728x90

1. ipywidgets이란


 ipywidgets는 UI 라이브러리로 함수를 전달하면 셀렉트 박스나 슬라이더의 조작으로 인수를 변경하면서 함수를 실행할 수 있게 된다. 

 예를 들어 아래의 그림과 같이 tsne로 2차원화하여 납작하게 한 것을 셀렉트박스로 선택한 샘플만을 표시하게 할 수도 있다.

 

 이외에도 EDA할 때에 x축과 y축을 셀렉트 박스로 선택하여 플롯하게 만들거나 변수의 파라미터를 변경하면서 플롯하게 만들 수도 있다. 플롯 이외에도 함수를 나열해 조작할 수 있도록 할 수 있으므로 여러모로 편리하다.

 그러나 ipywidgets는 함수를 호출하는 것 뿐이므로 빠른 속도로 실행하거나 그래프 등을 그려주거나 해주지는 않는다.  또한 참고로 여기서 추가로 matplotlib를 그래프 함수로 호출한 경우, 매번 그래프를 인치 단위부터 조정해서 다시 작성해야하는 경우가 있어 matplotlib만으로 원하는 그래프를 만들어 내는 일이 번거롭다. 따라서 인터렉티브하고 간단히 조정할 수 있는 그래프를 만들고 싶은 경우는 bokeh등의 인터렉티브 그래프 패키지를 쓸 필요가 있다.

 다만 제목에서 알 수 있듯 이번 포스팅에서는 ipywidgets의 중심으로 설명하도록 하겠다. 그렇지만 모든 내용을 다 다룰 수는 없으므로 ipywidgets 사이트를 확인하면서 어떠한 기능이 있는지 확인하고 싶다면 여기서 확인할 수 있다.

 

 

2. 설치


 Jupyter lab을 설치하면 기본적으로 함께 설치되는 듯하나, 설치가 되지 않은 경우 다음의 커맨드를 실행하여 설치할 수있다.

pip install ipywidgets

 참고로 pip install에서 Sysntax Error가 난 경우에는 pip앞에 !를 붙여서 작성해서 (!pip) 해결 할 수 있고, jupyter notebook에서 바로 설치하는 경우에는 아래의 커맨드로 오류를 해결 할 수 있다.

import sys
!{sys.executable} -m pip install ipywidgets

 

 

3. 기본 활용 예(1) :  그래프


 아래의 코드와 같이 라이브러리를 import한다. 

import ipywidgets as widgets

 물론 특정 위젯만 import하고 싶은 경우 다음과 같이 지정하여 import할 수 있다.

from ipywidgets import interact, interactive, fixed, interact_manual
import ipywidgets as widgets

 

1) 인터렉티브한 그래프 만들기

(1) %matplotlib inline 을 기재하고 interact를 import한다.

(2) 그래프의 표시부를 함수화하고 interact의 첫 번째 인수로 함수를, 이후의 인수로 함수의 인수를 전달한다.

(3) 이 "함수의 인수"에 1개의 값이 아닌 값의 범위를 전달한다. 그럼 범위의 슬라이더가 생성되어 인터렉티브한 그래프가 된다.

이는 아래의 예에서 k=(0.0,5.0,0.1)의 부분으로, 0부터 5까지 0.1간격으로 FloatSlider을 작성한다.

%matplotlib inline
import matplotlib.pyplot as plt
from ipywidgets import interact
import numpy as np

def f(k):
    x = np.linspace(0, 10, num=1000)
    y = np.sin(k*x)
    plt.plot(x, y)
    plt.show()

interact(f, k=(0.0,5.0,0.1) )

 위의 예에서는 함수 속에 데이터를 생성하고 있지만, 아래의 예에서는 미리 작성된 여러 개의 데이터를 슬라이더로 구분하여 표시하고 있다.

 k=(0,param-1)의 세 번째 인수를 생략하면 정수 정수 단위의 IntSlider이 된다.

%matplotlib inline
import matplotlib.pyplot as plt
from ipywidgets import interact
import numpy as np

x = np.linspace(0, 2*np.pi, num=5000)
y = []
param = 50

for i in range(1,param+1):
    y.append([np.sin(i*j) for j in x])

def f(k):
    plt.plot(x, y[k])
    plt.show()

interact(f, k=(0,param-1) )

 

2) 데코레이터(*)를 사용하여 표시

* python 데코레이터(Decorator)란?  함수를 받아 명령을 추가한 뒤 이를 다시 함수의 형태로 반환하는 함수이다.  함수의 내부를 수정하지 않고 기능에 변화를 주고 싶을 때 사용한다. 라이브러리 내의 함수의 기능을 변경하고 싶은 경우 등에 도움이 된다. 구체적인 내용에 대해서는 다른 포스팅에서 다루도록 하겠다.

그래프를 표시하는 함수를 interact로 데코레이터하는 것만으로도 그래프를 표시할 수 있다. Jupyter에서는 함수를 호출하지 않고, 아래의 코드를 그대로 실행하면 그래프가 표시된다. 

%matplotlib inline
import matplotlib.pyplot as plt
from ipywidgets import interact
import numpy as np

x = np.linspace(0, 2*np.pi, num=5000)
y = []
param = 50

for i in range(1,param+1):
    y.append([np.sin(i*j) for j in x])

@interact(k=(0,param-1))
def f(k):
    plt.plot(x, y[k])
    plt.show()

 

3) 여러 개의 그래프를 표시

단순하지만 2번 기재하면 그래프를 2개 표시할 수 있다.

%matplotlib inline
import matplotlib.pyplot as plt
from ipywidgets import interact
import numpy as np

x = np.linspace(0, 2*np.pi, num=5000)
y1, y2 = [], []

param = 50

for i in range(1,param+1):
    y1.append([np.sin(i*j) for j in x])
    y2.append([np.cos(i*j)+np.cos(j) for j in x])

@interact(k=(0,param-1))
def f1(k):
    plt.plot(x, y1[k])
    plt.show()

@interact(k=(0,param-1))
def f2(k):
    plt.plot(x, y2[k])
    plt.show()

 

4) 선택지를 표시

함수의 인수가 숫자가 아닌 경우에는 Dropdown형식이 된다.

%matplotlib inline
import matplotlib.pyplot as plt
from ipywidgets import interact
import numpy as np

x = np.linspace(0, 2*np.pi, num=5000)
y1, y2 = [], []

param = 50

for i in range(1,param+1):
    y1.append([np.sin(i*j) for j in x])
    y2.append([np.cos(i*j)+np.cos(j) for j in x])

@interact(k=(0,param-1), mode=['A','B'])
def f(k,mode):
    if mode=='A':
        plt.plot(x, y1[k])   
    elif mode=='B':        
        plt.plot(x, y2[k])
    else:
        print('Error')

    plt.show()

 

5) subplot을 사용하는 표시

subplot으로도 사용할 수 있다.

%matplotlib inline
import matplotlib.pyplot as plt
from ipywidgets import interact
import numpy as np

x = np.linspace(0, 2*np.pi, num=5000)
y, y1, y2, y3 = [], [], [], []

param = 50

for i in range(1,param+1):
    y1.append([np.sin(i*j) for j in x])
    y2.append([np.cos(i*j)+np.cos(j) for j in x])
    y3.append([np.tan(i*j)+np.cos(j) for j in x])

y = [y1, y2, y3]

# 그래프를 생성
@interact(k=(0,param-1))
def f(k):
    fig = plt.figure(figsize=(17,4))

    # 타이틀을 배열에 저장
    title=['title1','title2','title3']    

    # 그래프 간의 폭을 조정
    plt.subplots_adjust(wspace=0.25, hspace=0.6)

    for i in range(3):
        ax = fig.add_subplot(1, 3, i+1)
        ax.plot(x, y[i][k])
        ax.set_xlabel('x-axis label') # x축의 라벨
        ax.set_ylabel('y-axis label') # y축의 라벨
        ax.set_title(title[i]) # 타이틀

    plt.show()

다음과 같이도 쓸 수 있다.

%matplotlib inline
import matplotlib.pyplot as plt
from ipywidgets import interact
import numpy as np

x = np.linspace(0, 2*np.pi, num=5000)
y, y1, y2, y3 = [], [], [], []

param = 50

for i in range(1,param+1):
    y1.append([np.sin(i*j) for j in x])
    y2.append([np.cos(i*j)+np.cos(j) for j in x])
    y3.append([np.tan(i*j)+np.cos(j) for j in x])

y = [y1, y2, y3]

# 그래프를 생성
@interact(k=(0,param-1))
def f(k):
    # 3개의 그래프를 배치할 테두리를 만든다 
    fig,ax = plt.subplots(1,3,figsize=(17,4))

    # 타이틀을 배열에 저장한다
    title=['title1','title2','title3']

    # 그래프간의 간격을 조정한다
    plt.subplots_adjust(wspace=0.25, hspace=0.6)

    for i in range(3):
        ax[i].plot(x, y[i][k])
        ax[i].set_title(title[i]) # 타이틀
        ax[i].set_xlabel('x-axis label') # x축의 라벨
        ax[i].set_ylabel('y-axis label') # y축의 라벨

    plt.show()

세로 버전은 다음과 같다.

%matplotlib inline
import matplotlib.pyplot as plt
from ipywidgets import interact
import numpy as np

x = np.linspace(0, 2*np.pi, num=5000)
y, y1, y2, y3 = [], [], [], []

param = 50

for i in range(1,param+1):
    y1.append([np.sin(i*j) for j in x])
    y2.append([np.cos(i*j)+np.cos(j) for j in x])
    y3.append([np.tan(i*j)+np.cos(j) for j in x])

y = [y1, y2, y3]

# 그래프를 생성한다.
@interact(k=(0,param-1))
def f(k):
    fig = plt.figure(figsize=(10,10))

    # 타이틀을 배열에 저장한다.
    title=['title1','title2','title3']    

    # 그래프 간의 폭을 조정한다.
    plt.subplots_adjust(wspace=0.2, hspace=0.6)

    for i in range(3):
        ax = fig.add_subplot(3, 1, i+1)
        ax.plot(x, y[i][k])
        ax.set_xlabel('x-axis label') # x축의 라벨
        ax.set_ylabel('y-axis label') # y축의 라벨
        ax.set_title(title[i]) # 타이틀

    plt.show()

 

 

 

3. 기본 활용 예(2) :  이미지


 이미지를 2차원화는 값을 슬라이더로 조정할 수 하고 그 결과가 바로 반영되도록 해보겠다. 여기서는 Python에서 이미지 처리 툴로 많이 사용되는 Pillow를 사용한다. Pillow가 설치되어 있지 않다면 위의 설치 항목에 설명했던 커맨드에 Pillow를 작성해서 설치하면 된다.

 설치가 끝났다면 Pillow를 import하고 글로벌 변수 img에 흑백화된 이미지를 로드해둔다. 여기서 사용한 이미지는 아래와 같다.

 ipywidgets로 동적 조작하는 함수 binarize를 정의하고, 임계값 변수 th로 이진화 후의 이미지를 반환하는 함수를 작성하여 interact 데코레이터를 부여하면 ipywidgets를 이용할 수 있다.

 아래의 코드를 실시하면 다음과 같다. 슬라이드바를 움직여서 조정할 수 있다.

@interact
def binarize(th: (0, 255, 1)):
    return img.point(lambda p: 255 if p > th else 0)


참고자료

qiita.com/ciela/items/55dc860433d52228ce20

qiita.com/ground0state/items/58a576cf09a56a0dd425#%E6%89%8B%E9%A0%86

ipywidgets.readthedocs.io/en/latest/examples/Widget%20List.html#Container/Layout-widgets

qiita.com/studio_haneya/items/adbaa01b637e7e699e75

techblog.gmo-ap.jp/2019/01/08/ipywidgets%E3%81%A7%E7%B0%A1%E5%8D%98%E3%81%AEui%E3%82%92%E4%BD%9C%E3%82%8D%E3%81%86/

728x90