프로토타입을 위해 활용하는 도구
단 시간내에 프로토타입을 만들 수 있어 자주 활용
본래 목적 : Dashboard의 형성
Notebook에서 별도 코드 추가 없이 실행할 수 있음
Jupyter Notebook 결과를 쉽게 웹 형태로 띄울 수 있음
ipwidget, ipyleaflet 등에 사용 가능
Jupyter Notebook의 Extension이 있어 노트북에서 바로 대시보드로 변환 가능
Python, Julia, C++ 코드 지원
고유한 템플릿 생성 가능
쉬운 러닝커브
pip install voila
# 1번 과정 : Jupyter Notebook을 Jupyter Lab으로 수행시킴
jupyter-lab --VoilaConfiguration.enable_nbextensions=True
# CLI 명령어
voila {ipynb 파일 이름}.ipynb --enable_nbextensions=True
물론 CLI는 귀찮을 수도 있다
하지만, CLI만의 장점도 가지고 있는데, 가장 큰 장점은 내가 원하는 설정값을 인자를 통해 전달해줄 수 있다는 점이다.
Jupyter Notebook이나 Jupter Lab에서는 Voila를 실행시킬 때 직접 인자를 건네주기 어렵지만, CLI에서는 가능하다.
예를 들어, --strip_sources=False 를 활용하면 Voila에서 코드까지 보여주는 dashboard를 형성할 수 있게 된다
MappingKernelManager.cull_interval
: idle 커널을 확인할 시간 간격MappingKernelManager.cull_idle_timeout
: 커널을 idle 상태로 판단할 시간 간격. 설정 시간 내에 Update가 없을 경우 idle로 판단'ExecutePreprocessor.timeout
: 지정한 시간(단위 : 초)를 타임아웃으로 설정jupyter notebook --generate-config
python
# python 실행시키기
from IPython.lib import passwd
passwd()
sha1:~
으로 암호가 나타날텐데, sha1:~
모든 값을 복사c.NotebookApp.password
를 파일 내에서 찾아야 함~~~
c.NotebookApp.password = {2번에서 복사한 값 붙여넣기}
~~~
import ipywidgets as widgets
from IPython.display import display
정수형 Slider
간단한 실행 방법
int_slider
이라는 인자로 받지 말고 바로 widgets.IntSlider()
로 수행시켜도 같은 결과가 나온다. 하지만, display()
명령어를 통해 내가 무엇을 하겠다는 것을 명시해주는 것이 더 좋은 방식int_slider = widgets.IntSlider()
display(int_slider)
int_slider1 = widgets.IntSlider(
value=7,
min=0,
max=10,
step=1,
orientation='horizontal',
description='Horizontal'
)
int_slider2 = widgets.IntSlider(
value=7,
min=0,
max=10,
step=1,
orientation='vertical',
description='Vertical'
)
display(int_slider1)
display(int_slider2)
IntRangeSlider
value = [a,b]
로 범위로 지정하며, 왼쪽과 오른쪽을 움직여 범위를 변경시켜줄 수 있음int_widget.value
widgets.IntSlider()
를 int_widget
이라는 객체에 저장하였을 경우 활용할 수 있는 명령어range_slider = widgets.IntRangeSlider(
value = [4,6],
min = 0,
max = 10,
step = 1,
description="Range"
)
display(range_slider)
Slider가 아닌 Input을 입력
.value
를 통해 값 접근 가능
bound_text = widgets.BoundedIntText(
value = 7,
min = 0,
max = 10,
step = 1,
description='Text',
disabled=False
)
int_text = widgets.IntText(
value = 10,
description = 'Any',
disabled=False
)
display(bound_text)
display(int_text)
disabled
: True로 값을 설정할 경우, 처음 지정한 value에서 값을 변경할 수 없음step
: 한 번의 클릭으로 값을 얼마나 Up(혹은 Down) 시킬 것인지 정함text = widgets.Text(
value = "hello world",
placeholder = 'Type Something',
description='default text'
)
text_area = widgets.Textarea(
placeholder = 'Type Something',
description='text area'
)
password = widgets.Password(
value = "hello world2",
placeholder = 'Type Something',
description='password'
)
display(text)
display(text_area)
display(password)
함수 설명
인자 설명
value
: 처음에 Default로 띄워질 Valueplaceholder
: value
가 None일 때, 즉 아무 값도 입력되어 있지 않을 때 띄울 값.True, False를 표시할 수 있는 Widget
ToggleButton
CheckBox
default_btn_false = widgets.ToggleButton(
value=False,
description='Click',
button_style='',
icon='check'
)
default_btn_true = widgets.ToggleButton(
value=True,
description='Click',
button_style='',
icon='check'
)
success_btn = widgets.ToggleButton(
value=False,
description='Click',
button_style='success',
icon='check'
)
display(default_btn_false)
display(default_btn_true)
display(success_btn)
value
: True일 경우 선택이 된 상태, False인 경우 클릭이 되지 않은 경우를 의미button_style
: 버튼의 스타일을 정해주는 것check_box = widgets.Checkbox(
value = False,
description='Check',
indent=False
)
display(check_box)
value
: False일 경우 선택이 안 된 상태, True인 경우 선택이 된 상태를 의미함indent
: 들여쓰기 여부. False / True로 값 지정값을 "선택"할 수 있는 Widget
Dropdown
RadioButtons
widgets.Dropdown(
options=[1,2,3],
value=2,
description='Number',
diabled=False
)
options
: 선택할 수 있는 답들을 리스트 형식으로 지정options=[('One',1),('Two', 2),('Three', 3)]
widgets.RadioButtons(
options = ['A','B','C'],
description='Alphabet'
)
widgets.FileUpload(
accept='',
multiple=False
)
accept
: 허용할 확장자. 아무 값도 입력하지 않으면 모든 확장자 업로드를 허용함multiple
: 동시에 여러 파일을 업로드 할 수 있을지에 대한 설정. True일 경우 여러 파일을 동시에 업로드할 수 있음file = open('image.jpg', 'rb')
image = file.read()
widgets.Image(
value=image,
format='jpg',
width=300,
height=400
)
value
: 이미지 파일을 Byte 파일로 읽은 데이터format
: 이미지 데이터 형식Date를 선택하는 Widget
Date, Time, DateTime도 존재
widgets.DatePicker(
description = 'Pick a Date',
diabled=False
)
on_click
on_click
인자에 실행시키고 싶은 함수를 넘겨주면 됨observe
on_click
과 마찬가지로 인자로 함수를 넘겨주면 됨on_click
코드button = widgets.Button(description = 'Click')
output = widgets.Output()
display(button, output)
def on_button_clicked(button):
with output:
print("Hello world!")
print(output)
button.on_click(on_button_clicked)
widgets.Output()
아마 widgets Event에서 가장 핵심인 부분이 아닐까 싶다.
이전에는 내가 원하는 Widget만 display 시키면 되었지만, 이벤트를 적용시키고 싶을 때는 display(button, output)을 통해 2개를 출력하는 것을 볼 수 있다.
그렇다면 output은 무엇을 의마할까? print(output)을 통해 출력해 보았을 때, msg_id로써 특정 신호가 갔다는 것을 알 수 있다.
즉, widgets.Output은 display를 통해 연결된 ipywidgets 요소에서부터 메시지가 발생(혹은 이벤트가 발생) 할 경우, 메시지를 전달받는 객체라고 생각하면 된다.
with output: 이라는 의미는, output에 메시지가 발생했다는 의미이다.
즉, Event가 발생했다는 의미이므로 내가 원하는 함수를 실행시키면 되는 것이다.
여기서 재미있는 점은, widgets.Output은 단순히 현재 이벤트만 출력하는 것이 아닌 "이전 출력 내용"이 축적되는 방식으로 저장한다는 것이다. Observe에서 더 자세히 다루겠다
observe
실행int_range = widgets.IntSlider()
output2 = widgets.Output()
display(int_range, output2)
def on_value_change(change):
with output2:
print(output2)
int_range.observe(on_value_change)
일단 제대로 된 활용법을 익히기 전에 widgets.Output()
부터 확실히 잡고 가자.
위 메서드는 IntSlider
의 값이 변경될 때마다 함수가 실행되는 것이다.
그렇다면 출력값을 통해 widgets.Output()
을 알 수 있을 것이다
뭔가 복잡하다. 하지만 중요한 점은 4번째 Output만 보면 된다.
나중에 change를 출력하면 알겠지만, IntSlider가 변경될 경우 총 3개의 Message가 전달된다.
즉, 처음 3개의 Message는 사실 1개의 Event에서 발생했다는 의미이다.
따라서, 처음 Output 3개를 출력했고, 이 것이 "첫번째 Event"에 대한 Output이다.
이후 4번째 Output을 보자. 4번째 Output의 outputs에는 총 3개의 Output이 \n으로 연결되어 있는데, 해당 msg_id가 맨 위 3개 msg_id와 일치함을 알 수 있다.
즉, Output은 이전에 출력했던 내용들을 outputs라는 곳에 저장하고, 현재 발생하는 메시지는 msg_id에 새로 발생시키는 형식으로 Output을 형성하는 것이다.
그렇다면 제대로 observer
를 활용해보자
int_range = widgets.IntSlider()
output2 = widgets.Output()
display(int_range, output2)
def on_value_change(change):
with output2:
print(change)
int_range.observe(on_value_change)
위에서 말했듯 IntRange에 대한 변화는 총 3개의 Message를 발생시키는데, 위 이미지를 보면 _property_lock
에 대한 것 2개, value
에 대한 것 1개이다.
그런데 우리는 저 모든 Output이 필요 없고, 사실 'new', 즉 현재 갱신된 값만 존재하면 된다.
따라서, change['new']값만 받아오면 될 것이다
int_range = widgets.IntSlider()
output2 = widgets.Output()
display(int_range, output2)
def on_value_change(change):
with output2:
print(change['new'])
int_range.observe(on_value_change)
거의 다 왔다. 이제 우리는 값이 6으로 변경시켰을 때 3개의 Output을 출력함을 알 수 있고, 위 3개는 바뀐(갱신된) 값에 대한 정보라는 것을 알 수 있다.
문제는, 무엇이 필요할지는 모르겠지만 대부분의 경우 2번째 출력값만 알면 Value 또한 알 수 있게 되는데, 굳이 3개의 출력문이 나온다는 점이다.
발생되는 3개의 Message에 대해 다시 한 번 잘 관찰해보자.
우리는 여기서 _property_lock
에 대한 Value를 지우고 싶고, value
라는 name을 가진 값에 대해서만 출력하고 싶음을 알 수 있다.
이 떄 활용할 수 있는 Parameter는 names
이다.
names = X
로 지정한다면, 여러 Message 중 'name':'X'
인 메시지만 뽑아낼 수 있게 된다.
따라서, 최종적으로 아래와 같은 코드를 짜면 우리가 원하는, 값이 변경될 때 마다 1개의 이벤트가 발생하도록 만들 수 있을 것이다.
int_range = widgets.IntSlider()
output2 = widgets.Output()
display(int_range, output2)
def on_value_change(change):
with output2:
print(change['new'])
int_range.observe(on_value_change, names='value')
@interact
데코레이터를 활용해 UI 컨트롤러를 자동 생성시킬 수 있음
함수의 인자를 받아 인자에 적절한 UI가 생성됨
UI에 나타내고 싶지 않은 값 같은 경우 fixed()를 활용할 수 있음
from ipywidgets import interact, fixed
# ipywidgets에서 따로 import 하여 활용
@interact(x=True, y=1.0, z=fixed(10))
def g(x,y,z):
return (x,y,z)
print('='*100)
@interact(x=True, y=1.0, z=10)
def h(x,y,z):
return (x,y,z)
위 g(x,y,z)는 z가 fixed(10)으로써 값이 10으로 고정되어 있으므로 z에 대한 ipywidget은 출력되지 않음
반대로 (x,y,z)는 y와 z가 모두 fixed()가 아니므로 변경 가능한 intslider로 변환됨
x = True
이므로, true / false를 표현해 줄 수 있는 버튼 형식으로 변환됨
from ipywidgets import Button, HBox, VBox
words = ['left-up', 'right-up', 'left-down', 'right-down']
items = [Button(description=w) for w in words]
left_box = VBox([items[0], items[2]])
right_box = VBox([items[1], items[3]])
HBox([left_box, right_box])
먼저 VBox를 통해 'left-up', 'left-down'을 "수직"으로 연결시킨다. 동일하게 'right-up', 'right-down'도 "수직"으로 연결시킨다.
이렇게 수직으로 연결된 2개의 item을 HBox 명령어를 통해 Horizontal(수평) 적으로 합친다.
그렇게 되면 2*1 형식의 테이블 2개를 수평 방향으로 합치게 되어 최종적으로 2*2 형식의 테이블로 만들어지는 것이다