티스토리 뷰

반응형

사용자의 입력에 따라 변하는 어플리케이션을 개발해야하는 경우가 있다. (사실 대부분 그렇다)

아래의 간단한 콜백함수를 사용하는 예제를 보면서 dash에서 콜백함수를 사용하는 법에 대해 알아보자.

import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    html.H6("Change the value in the text box to see callbacks in action!"),
    html.Div(["Input: ",
              dcc.Input(id='my-input', value='initial value', type='text')]),
    html.Br(),
    html.Div(id='my-output'),

])


@app.callback(
    Output(component_id='my-output', component_property='children'),
    Input(component_id='my-input', component_property='value')
)
def update_output_div(input_value):
    return 'Output: {}'.format(input_value)


if __name__ == '__main__':
    app.run_server(debug=True)

어플리케이션 인터페이스의 "입력"및 "출력"은 @app.callback 데코레이터의 인수로 선언적으로 표현된다.

@ app.callback 데코레이터 사용에 대해 알아보자.

  • 이 데코레이터를 작성하는 것은 Dash에게 "Input"(입력) 컴포넌트의 값(value)이 변할 때마다 "Output"(출력) 컴포넌트의 chlildren을 업데이트하라고 알려주는 것이다.
  • @ app.callback 데코레이터로 래핑된 함수의 이름은 사용자가 원하는 대로 지정할 수 있다. 컨벤션은 콜백 아웃풋을 나타내는 함수명을 사용하는 것이다.
  • 함수 인수도 어떤 이름이든 사용할 수 있다. 하지만 인수의 순서는 맞춰줘야 한다.(데코레이터와 동일한 순서로)
  • @ app.callback 데코레이터의 입력 또는 출력으로 참조 할 때 app.layout에서 Dash 컴포넌트에 지정한 것과 동일한 ID를 사용해야 한다.
  • @ app.callback 데코레이터는 콜백 함수 선언 바로 위에 있어야합니다. 데코레이터와 함수 정의 사이에 빈 줄이 있으면 콜백 등록이 되지 않는다.

Dash에서 애플리케이션의 입력과 출력은 단순히 특정 컴포넌트의 속성이다. 위 예제에서 입력은 ID가 "my-input"인 컴포넌트의 "value"속성이고, 출력은 ID가 "my-output"인 컴포넌트의 "children"속성이다.

입력 속성이 변경 될 때마다 콜백 데코레이터가 래핑하는 함수가 자동으로 호출된다. Dash는 입력 속성의 새 값을 입력 인수로 함수에 제공하고 Dash는 함수에서 반환된 항목으로 출력 컴포넌트의 속성을 업데이트한다.

component_idcomponent_property 키워드는 선택 사항이다. (@ app.callback 데코레이터의 각 객체에 대해 두 개의 인수만 있으므로 생략 가능하다.).

dash.dependencies.Input 객체와 dash_core_components.Input 객체를 혼동하지 말자. 전자는 이러한 콜백에서 사용되며 후자는 실제 컴포넌트다.

레이아웃에서 출력 컴포넌트의 children 속성 값을 따로 지정하지 않은 것에 주의하라. Dash 앱이 시작되면 출력 컴포넌트의 초기 상태를 채우기 위해 입력 컴포넌트의 초기 값으로 모든 콜백을 자동으로 호출한다. 이 예제에서 html.Div (id = 'my-output', children = 'Hello world')와 같은 것을 지정해도 앱이 시작될 때 콜백이 자동으로 호출되고 값이 덮어 쓰여진다.


콜백함수에 여러개의 입력과 출력을 사용할 수 있다. @app.callback 데코레이터 내에 정의한 순서만 맞춰주자.

html의 form과 비슷한 패턴으로 입력을 받아야하는 경우가 있는데 이때는 콜백함수에 해당하는 모든 인풋을 넣는 것으로 해결 가능하다. 

아래 예제 참고:

# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

external_stylesheets = ["https://codepen.io/chriddyp/pen/bWLwgP.css"]

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div(
    [
        dcc.Input(id="input-1", type="text", value="Montréal"),
        dcc.Input(id="input-2", type="text", value="Canada"),
        html.Div(id="number-output"),
    ]
)


@app.callback(
    Output("number-output", "children"),
    Input("input-1", "value"),
    Input("input-2", "value"),
)
def update_output(input1, input2):
    return u'Input 1 is "{}" and Input 2 is "{}"'.format(input1, input2)


if __name__ == "__main__":
    app.run_server(debug=True)

 

하지만 제출 버튼을 누르는 등의 경우만 결과(출력)를 바꾸고 싶다면 버튼만 input으로 두고 나머지 입력을 state로 처리하자. 

# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output, State

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

app.layout = html.Div([
    dcc.Input(id='input-1-state', type='text', value='Montréal'),
    dcc.Input(id='input-2-state', type='text', value='Canada'),
    html.Button(id='submit-button-state', n_clicks=0, children='Submit'),
    html.Div(id='output-state')
])


@app.callback(Output('output-state', 'children'),
              Input('submit-button-state', 'n_clicks'),
              State('input-1-state', 'value'),
              State('input-2-state', 'value'))
def update_output(n_clicks, input1, input2):
    return u'''
        The Button has been pressed {} times,
        Input 1 is "{}",
        and Input 2 is "{}"
    '''.format(n_clicks, input1, input2)


if __name__ == '__main__':
    app.run_server(debug=True)

state가 바뀌어도 콜백함수가 자동 호출되지 않는다. 하지만 Input으로 지정된 버튼의 n-clicks가 바뀔때마다 호출된다. 결과(출력)값에는 사용되지만 값이 변할 때 자동으로 콜백함수를 호출하고 싶지 않은 경우는 State로 처리하자.


Chained Callbacks (연쇄 콜백) 사용하기

# -*- coding: utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']

app = dash.Dash(__name__, external_stylesheets=external_stylesheets)

all_options = {
    'America': ['New York City', 'San Francisco', 'Cincinnati'],
    'Canada': [u'Montréal', 'Toronto', 'Ottawa']
}
app.layout = html.Div([
    dcc.RadioItems(
        id='countries-radio',
        options=[{'label': k, 'value': k} for k in all_options.keys()],
        value='America'
    ),

    html.Hr(),

    dcc.RadioItems(id='cities-radio'),

    html.Hr(),

    html.Div(id='display-selected-values')
])


@app.callback(
    Output('cities-radio', 'options'),
    Input('countries-radio', 'value'))
def set_cities_options(selected_country):
    return [{'label': i, 'value': i} for i in all_options[selected_country]]


@app.callback(
    Output('cities-radio', 'value'),
    Input('cities-radio', 'options'))
def set_cities_value(available_options):
    return available_options[0]['value']


@app.callback(
    Output('display-selected-values', 'children'),
    Input('countries-radio', 'value'),
    Input('cities-radio', 'value'))
def set_display_children(selected_country, selected_city):
    return '{} is a city in {}'.format(
        selected_city, selected_country,
    )


if __name__ == '__main__':
    app.run_server(debug=True)

위 예제처럼 한 입력 컴포넌트의 변화가 다른 입력 컴포넌트의 변화를 이끌어내는 연쇄적인 콜백을 사용가능하다.

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함