11 분 소요

dash_icon

(3) 레이아웃(Layouts) 구성

구성 요소


Dash 의 레이아웃은 html.Divdcc.Graph 와 같은 구성요소가 트리(tree) 구조로 되어있습니다. 따라서 사용자가 원하는 레벨에 맞게 구성 요소를 배치해 주면 레이아웃이 만들어지는 원리라고 생각하시면 됩니다.

예를 들어 Dash 가 제공하는 dash_html_components 함수를 통해 HTML 태그를 페이지에 표현할 수 있습니다. 이전 포스팅에서 다루었던 app.py 파일에서 html.H1(children='Hello Dash') 는 실행되면 <h1>Hello Dash</h1> 라는 HTML 요소가 만들어 집니다.

그리고, dash_core_components 함수를 활용하면 기존에 JavaScript, CSS 로 만들어진 상위 레벨의 요소도 레이아웃에 표현할 수 있습니다.

Dash는 기본적으로 ‘hot-reloading’ 기능을 제공하는데, 코드가 변경되면 Dash 가 자동으로 브라우저를 새로고침하는 기능입니다. (만약에 이 기능을 끄고 싶다면 app.run_server(dev_tools_hot_reload=False) 로 앱 실행 옵션을 변경해 줄 수 있습니다)


레이아웃 변경


자, 그럼 이제 지난번에 실행했던 앱에서 HTML 요소를 조금 변경해서 어떻게 바뀌는지 보겠습니다. 대시보드에 출력되는 레이아웃 스타일을 조금 수정 해보겠습니다.

# Dash 관련 라이브러리 로딩
import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import pandas as pd

# Dash 앱 인스턴스 생성
app = dash.Dash(__name__)

# 스타일 속성 딕셔너리
colors = {
    'background': '#111111',
    'text': '#7FDBFF'
}

# Pandas 데이터 프레임 생성
df = pd.DataFrame({
    "Fruit": ["Apples", "Oranges", "Bananas", "Apples", "Oranges", "Bananas"],
    "Amount": [4, 1, 2, 2, 4, 5],
    "City": ["SF", "SF", "SF", "Montreal", "Montreal", "Montreal"]
})

# Bar 차트 생성
fig = px.bar(df, x="Fruit", y="Amount", color="City", barmode="group")

# 레이아웃 스타일 변경
fig.update_layout(
    plot_bgcolor=colors['background'],
    paper_bgcolor=colors['background'],
    font_color=colors['text']
)

# 레이아웃 생성
app.layout = html.Div(style={'backgroundColor': colors['background']}, children=[
    html.H1(
        children='Hello Dash',
        style={
            'textAlign': 'center',
            'color': colors['text']
        }
    ),

    html.Div(children='Dash: A web application framework for your data.', style={
        'textAlign': 'center',
        'color': colors['text']
    }),

    dcc.Graph(
        id='example-graph-2',
        figure=fig
    )
])

if __name__ == '__main__':
  # Dash 앱 실행
    app.run_server(debug=True)


이전 예제와 달라진 부분은 레이아웃의 배경 색상이 검은색으로 변경되었고, 폰트의 정렬과 색상이 바뀐 것을 확인 할 수 있습니다.

Dash 레이아웃에서 모든 HTML 속성과 태그를 Python 컨텍스트로 표현할 수 있지만, 여기서 스타일을 변경할 때 주의해야할 부분은 dash_html_components 가 HTML 문법과는 조금 차이가 있다는 점입니다. HTML은 기본적으로 세미콜론으로 스타일 속성을 구분합니다. 하지만 Dash 는 딕셔너리 형태로 속성을 정의하는 점이 다릅니다. 이때 스타일 속성 딕셔너리의 키는 camelCased 형태를 사용하는 것이 컨벤션입니다.


Pandas 테이블 추가


Dash 에서는 그래프 figure 뿐만 아니라, Pandas 라이브러리의 데이터 프레임을 그대로 HTML 의 Table 요소로 파싱할 수 있습니다. 아래는 테이블을 레이아웃에 추가하는 app.py 예제입니다.

import dash
import dash_html_components as html
import pandas as pd

# Pandas DataFrame 로드
df = pd.read_csv('https://gist.githubusercontent.com/chriddyp/c78bf172206ce24f77d6363a2d754b59/raw/c353e8ef842413cae56ae3920b8fd78468aa4cb2/usa-agricultural-exports-2011.csv')


# HTML 테이블 요소 파싱
def generate_table(dataframe, max_rows=10):
    return html.Table([
        html.Thead(
            html.Tr([html.Th(col) for col in dataframe.columns])
        ),
        html.Tbody([
            html.Tr([
                html.Td(dataframe.iloc[i][col]) for col in dataframe.columns
            ]) for i in range(min(len(dataframe), max_rows))
        ])
    ])


# Dash 앱 인스턴스 생성
app = dash.Dash(__name__)

# 레이아웃 생성
app.layout = html.Div([
    html.H4(children='US Agriculture Exports (2011)'),
    generate_table(df)
])

if __name__ == '__main__':
    # Dash 앱 실행
    app.run_server(debug=True)

US Agriculture Exports (2011)

Unnamed: 0 state total exports beef pork poultry dairy fruits fresh fruits proc total fruits veggies fresh veggies proc total veggies corn wheat cotton
0 Alabama 1390.63 34.4 10.6 481.0 4.06 8.0 17.1 25.11 5.5 8.9 14.33 34.9 70.0 317.61
1 Alaska 13.31 0.2 0.1 0.0 0.19 0.0 0.0 0.0 0.6 1.0 1.56 0.0 0.0 0.0
2 Arizona 1463.17 71.3 17.9 0.0 105.48 19.3 41.0 60.27 147.5 239.4 386.91 7.3 48.7 423.95
3 Arkansas 3586.02 53.2 29.4 562.9 3.53 2.2 4.7 6.88 4.4 7.1 11.45 69.5 114.5 665.44
4 California 16472.88 228.7 11.1 225.4 929.95 2791.8 5944.6 8736.4 803.2 1303.5 2106.79 34.6 249.3 1064.95
5 Colorado 1851.33 261.4 66.0 14.0 71.94 5.7 12.2 17.99 45.1 73.2 118.27 183.2 400.5 0.0
6 Connecticut 259.62 1.1 0.1 6.9 9.49 4.2 8.9 13.1 4.3 6.9 11.16 0.0 0.0 0.0
7 Delaware 282.19 0.4 0.6 114.7 2.3 0.5 1.0 1.53 7.6 12.4 20.03 26.9 22.9 0.0
8 Florida 3764.09 42.6 0.9 56.9 66.31 438.2 933.1 1371.36 171.9 279.0 450.86 3.5 1.8 78.24
9 Georgia 2860.84 31.0 18.9 630.4 38.38 74.6 158.9 233.51 59.0 95.8 154.77 57.8 65.4 1154.07


Interactive 그래프 생성


Dash 에서는 dash_core_components 함수를 사용해서 기존 JavaScript 로 개발된 그래프 라이브러리를 사용해서 좀 더 고차원의 그래프를 표현할 수 있습니다.

Graph 컴포넌트 내의 figure 속성은 일반적으로 Plotly 라이브러리에서 지원되는 figure 가 모두 호환됩니다. 관련해서 더 궁금하신 분들은 plotly 갤러리 에서 확인해주세요.

아래는 마우스 Hover 동작으로 값을 확인하거나 줌인 줌아웃 기능을 포함하는 Scatter 그래프를 만드는 예제입니다. 마찬가지로 app.py 파일을 수정하고 실행시키면 아래와 같은 Interactive 그래프가 대시보드에 랜더링 됩니다.


import dash
import dash_core_components as dcc
import dash_html_components as html
import plotly.express as px
import pandas as pd

# Dash 앱 인스턴스 생성
app = dash.Dash(__name__)

# 데이터 프레임 로드
df = pd.read_csv('https://gist.githubusercontent.com/chriddyp/5d1ea79569ed194d432e56108a04d188/raw/a9f9e8076b837d541398e999dcbac2b2826a81f8/gdp-life-exp-2007.csv')

# Scatter Plot 생성 (plotly.py figure)
fig = px.scatter(df, x="gdp per capita", y="life expectancy",
                 size="population", color="continent", hover_name="country",
                 log_x=True, size_max=60)

# 레이아웃 생성
app.layout = html.Div([
    dcc.Graph(
        id='life-exp-vs-gdp',
        figure=fig
    )
])

if __name__ == '__main__':
    # Dash 앱 실행
    app.run_server(debug=True)


마크다운(Markdown) 요소


Dash 는 dash_html_components 를 통한 HTML 텍스트를 추가하는 방식 외에도 dash_core_components 를 활용하면 마크다운을 사용 할 수 있습니다. 아무래도 자동 포멧팅 기능으로 깔끔한 문서를 작성할 때 아래 예시처럼 마크다운 요소를 추가하시면 좋을 것 같습니다.

import dash
import dash_core_components as dcc
import dash_html_components as html

app = dash.Dash(__name__)

markdown_text = '''
#### Dash 와 마크다운

Dash 앱은 마크다운으로 작성할 수 있습니다.
Dash 는 [CommonMark](http://commonmark.org/) 사양을 기준으로 사용합니다.
만약, 마크다운 문서작성이 처음이시라면
마크다운 튜토리얼 [60 Second Markdown Tutorial](http://commonmark.org/help/) 을 확인해 보세요!
'''

app.layout = html.Div([
    dcc.Markdown(children=markdown_text)
])

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

Dash 와 마크다운

Dash 앱은 Markdown으로 작성할 수 있습니다. Dash 는 CommonMark 사양을 기준으로 사용합니다. 만약, 마크다운 문서작성이 처음이시라면 마크다운 튜토리얼 60 Second Markdown Tutorial 을 확인해 보세요!


그 외 구성 요소


Dash 의 dash_core_components 에는 이 외에도 드롭다운, 슬라이더, 체크 박스, 라디오 버튼 같은 구성 요소를 나타낼 수 있습니다. Dash Core Components 에 사용할 수 있는 구성 요소들이 설명되어 있으니, 필요에 따라 찾아서 사용하시면 될 것 같습니다.

이번 장의 마지막 예제는 드롭다운, 버튼, 슬라이더 요소를 레이아웃에 랜더링하는 app.py 예시입니다.

import dash
import dash_core_components as dcc
import dash_html_components as html

# Dash 앱 인스턴스 생성
app = dash.Dash(__name__)

# 레이아웃 생성
app.layout = html.Div([
    # 기본 드롭다운
    html.Div(children=[
        html.Label('Dropdown'),
        dcc.Dropdown(
            options=[
                {'label': 'New York City', 'value': 'NYC'},
                {'label': u'Montréal', 'value': 'MTL'},
                {'label': 'San Francisco', 'value': 'SF'}
            ],
            value='MTL'
        ),
        # 다중 선택 드롭다운
        html.Br(),
        html.Label('Multi-Select Dropdown'),
        dcc.Dropdown(
            options=[
                {'label': 'New York City', 'value': 'NYC'},
                {'label': u'Montréal', 'value': 'MTL'},
                {'label': 'San Francisco', 'value': 'SF'}
            ],
            value=['MTL', 'SF'],
            multi=True
        ),
        
        # 라디오 버튼
        html.Br(),
        html.Label('Radio Items'),
        dcc.RadioItems(
            options=[
                {'label': 'New York City', 'value': 'NYC'},
                {'label': u'Montréal', 'value': 'MTL'},
                {'label': 'San Francisco', 'value': 'SF'}
            ],
            value='MTL'
        ),
    ], style={'padding': 10, 'flex': 1}),

    # 체크 박스
    html.Div(children=[
        html.Label('Checkboxes'),
        dcc.Checklist(
            options=[
                {'label': 'New York City', 'value': 'NYC'},
                {'label': u'Montréal', 'value': 'MTL'},
                {'label': 'San Francisco', 'value': 'SF'}
            ],
            value=['MTL', 'SF']
        ),
        
        # 텍스트 박스
        html.Br(),
        html.Label('Text Input'),
        dcc.Input(value='MTL', type='text'),

        # 슬라이더
        html.Br(),
        html.Label('Slider'),
        dcc.Slider(
            min=0,
            max=9,
            marks={i: 'Label {}'.format(i) if i == 1 else str(i) for i in range(1, 6)},
            value=5,
        ),
    ], style={'padding': 10, 'flex': 1})
], style={'display': 'flex', 'flex-direction': 'row'})

if __name__ == '__main__':
    # Dash 앱 실행
    app.run_server(debug=True)

dash_ex3


본 포스트는 Dash 공식 가이드 를 참고하였습니다.

댓글남기기