갈루아의 반서재

 

 

인터랙티브 데이터 시각화는 실험 데이터 분석에 중요한 역할을 한다. 데이터셋에 기술적 또는 예측적 알고리즘을 적용하기에 앞서, 특성간 연관성이 어떤지 그리고 내부적으로 어떻게 분포되어 있는지 파악하는 것이 중요하다. 이를 위해 수많은 시각화 라이브러리가 수많은 형태의 차트를 제공하고 있지만, 분명한 점은 각각의 속성에 대해 매번 차트 작업을 하고, 해당 챠트를 다른 특성과 매번 서로 비교하는 작업은 결코 간단하지는 않다는 것이다. 이러한 고민을 해결해주는 2가지 라이브러리가 있는데, 인터랙티브 시각화를 제공해주는 Plotly.py 와 웹기반 파이썬 어플리케이션의 프레임워크를 제공해주는 Dash 가 바로 그것이다. 이하 그 사용법에 대해 알아보자. 

Dash Installation

먼저 예제 실행에 필요한 몇 가지 dash 라이브러리를 설치해보자. 파이썬 2 와 3 모두를 지원한다.

(AnnaM) founder@hilbert:~/annam/dash$ pip install dash==1.8.0
Successfully installed Flask-1.1.1 dash-1.8.0 dash-core-components-1.7.0 dash-html-components-1.0.2 dash-renderer-1.2.3 dash-table-4.6.0 flask-compress-1.4.0 itsdangerous-1.1.0

Note: dash 0.37.0 버전부터 자동으로 dash-renderer, dash-core-components, dash-html-components, 그리고 dash-table 을 설치하게 된다. 더이상 개별적으로 상기 라이브러리를 설치할 필요가 없다.

https://dash.plot.ly/installation

 

Part 1. Installation

 

dash.plot.ly

 

A Simple Dash App

먼저 6줄의 코드로 구성된 간단한 Dash 웹 어플리케이션을 만들어보자. 아래의 코드를 입력한 후 적당한 이름의 .py 파일로 저장하고 호출하면 된다. 그게 전부다.

#this is the dash_test.py file

import dash
import dash_html_components as html

app = dash.Dash(__name__)
app.layout = html.H1('hello dash')

if __name__ == '__main__':
    app.run_server(debug=True, port=8080, host='0.0.0.0')

다음과 같이 터미널에서 실행 후 웹브라우저에서 실행결과를 확인해보자.

(AnnaM) founder@hilbert:~/annam/dash$ python dash_test.py
Running on http://0.0.0.0:8080/
Debugger PIN: 806-329-265
 * Serving Flask app "dash_test" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
Running on http://0.0.0.0:8080/
Debugger PIN: 051-718-914

코드를 한 줄씩 살펴보자. 먼저 아래 두 줄은 필요한 dash 라이브러리를 가져오는 코드다. 

import dash 
import dash_html_components as html 

3번째 줄은 dash 앱을 초기화시킨 후 4번째 라인에서 웹페이지에서 보여줄 header tag 를 가진 페이지 레이아웃을 준비한다. 

app = dash.Dash(__name__) 
app.layout = html.H1('hello dash') 

마지막 2줄은 서버를 디버그 모드에서 구동하는 부분으로, 특정 포트 및 아이피를 부여했음을 볼 수 있다. 

if __name__ == '__main__': 
    app.run_server(debug=True, port=8080, host='0.0.0.0')

이제 app.layout 을 수정하여 버튼과 라벨 요소를 div 에 넣어보자. 버튼과 라벨 이상 2개의 요소는 div 요소의 자식 요소로 리스트 형식으로 들어가게된다. Dash 는 html 요소를 dash_html_components 라이브러리에 저장한다. 전체 리스트는 website  github repo 에서 확인가능하다.

#this is the dash_test.py file

import dash
import dash_html_components as html

app = dash.Dash(__name__)
app.layout = html.Div(
[
    html.Button('create random number', id='button1'),
    html.Label('...', id='label1')
]
)

if __name__ == '__main__':
    app.run_server(debug=True, port=8080, host='0.0.0.0')

 

방금 넣은 요소에 스타일링을 가미해보자. css 태그의 딕셔너리 형식으로 스타일 속성을 넣어보자. 

#this is the dash_test.py file

import dash
import dash_html_components as html

app = dash.Dash(__name__)
app.layout = html.Div(
[
    html.Button('create random number',
               id='button1',
               style={'display':'block', 'background-color':'#aabbcc'}
               ),

    html.Label('...',
               id='label1',
               style={'display':'inline-block','margin':'10'}
              )
]
)

if __name__ == '__main__':
    app.run_server(debug=True, port=8080, host='0.0.0.0')

이제 몇 가지 반응성 요소를 넣어보자. 먼저 필요한 라이브러리부터 가져오자. 그리고 콜백 데코레이터를 더하고, 콜백에서 실행하고자하는 함수를 넣는다. 다음을 보자.

#this is the dash_test.py file

import dash
import dash_html_components as html

from dash.dependencies import Input, Output
import random

app = dash.Dash(__name__)
app.layout = html.Div(
[
    html.Button('create random number',
               id='button1',
               style={'display':'block', 'background-color':'#aabbcc'}
               ),

    html.Label('...',
               id='label1',
               style={'display':'inline-block','margin':'10'}
              )
]
)

@app.callback(
    Output(component_id='label1', component_property='children'),
    [Input(component_id='button1', component_property='n_clicks')]
)

def update_output(input_value):
    return random.random()

if __name__ == '__main__':
    app.run_server(debug=True, port=8080, host='0.0.0.0')

update_output 함수는 단순히 난수를 생성하고 결과로 보여주는 기능을 한다. 그리고 @app.callback 데코레이터는 버튼 클릭 이벤트를 update_output 함수로, 그리고 함수의 실행결과를 label1 요소로 묶는 기능을 한다. 이 부분이 반응성의 핵심파트다. 실행결과를 보자. 

 

 

Adding a Simple Chart

이제 몇 가지 챠트를 넣어보자. 먼저 버튼 클릭시마다 생기는 난수를 바차트로 나타내보자. 이를 위해 레이아웃에 그래프 객체를 추가한다. 그리고 챠트를 생성할 수 있도록 콜백 함수도 아래와 같이 수정한다.

#this is the dash_test.py file

import dash
import dash_html_components as html

from dash.dependencies import Input, Output
import dash_core_components as dcc
import random

app = dash.Dash(__name__)
app.layout = html.Div(
[
    html.Button('create random number',
               id='button1',
               style={'display':'block', 'padding':'5', 'background-color':'#aabbcc'}
               ),

    html.Label('...',
               id='label1',
               style={'display':'inline-block','margin':'10'}
              ),
    
    dcc.Graph(id='graph1')
]
)

@app.callback(
    Output(component_id='graph1', component_property='figure'),
    [Input(component_id='button1', component_property='n_clicks')]
)

def update_output(input_value):
    
    random_x = [i for i in range(5)]
    random_y = [random.random() for _ in range(5)]
    figure = {
        'data':[
            {'x':random_x, 'y':random_y, 'type':'bar', 'name':'Series1'}
        ],
        'layout':{
            'title':'Dash Data Visualization'
        }
        
    }

    return figure

if __name__ == '__main__':
    app.run_server(debug=True, port=8080, host='0.0.0.0')

먼저 콜백 데코레이터에서 Output statement 의 라벨을 graph 객체로 대체하였고, 함수내에 챠트에 쓰일 x 와 y 값과 figure 객체를 생성했다. 실행결과는 다음과 같다.

 

Some more complexity

만약 위의 샘플 차트가 여러분의 생각만큼 팬시하지 못하다면, 다음의 또 다른 예를 살펴보자. 전체 코드는 하단 내용을 참고하면 되고, 코드 전체의 구조는 위의 코드와 마찬가지의 구조를 가지고 있다. 먼저 앱을 초기화한 다음, 

  • 데이터를 읽어오는 2줄을 추가했다
  • app.layout 섹션에서, 2개의 드랍다운 리스트를 추가하고, 데이터 컬럼의 루프로 옵션을 채웠다
  • @app.callback 데코레이터에서는 2개의 드랍다운을 인풋 컴포넌트로 추가했다
  • 그리고 update_output 함수에서, 드랍다운 리스트에서 선택한 데이터와 컬럼으로 산점도를 그리도록 했다. 각 클래스별로 산점도를 그리도록 했음에 주목하자. 보다시피 함수의 끝과 ‘data’ 리스트내에 루프문이 있다. list comprehension 이라고 부르기도 하는데, Scatter() 객체를 n 번 반환한다. 여기서 n 은 데이터의 'class' 컬럼의 유일한 레코드의 수이다.
  • 그리고 이어지는 라인은 챠트의 레이아웃 속성에 관한 것이다.
# coding=utf8
import random
import pandas as pd
import dash
from dash.dependencies import Input, Output
import dash_html_components as html
import dash_core_components as dcc
import plotly.graph_objs as go
app = dash.Dash(__name__)
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class']
data = pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data', names=names)
app.layout = html.Div(
    [
        html.Div([
            dcc.Dropdown(
                id='ddl_x',
                options=[{'label': i, 'value': i} for i in names],
                value='sepal-width',
                style={'width':'50%'}
            ),
            dcc.Dropdown(
                id='ddl_y',
                options=[{'label': i, 'value': i} for i in names],
                value='petal-width',
                style={'width':'50%'}
            ),
        ],style={'width':'100%','display':'inline-block'}),
        html.Div([
            dcc.Graph(id='graph1') 
        ],style={'width':'100%','display':'inline-block'})
    ]
)
@app.callback(
    Output(component_id='graph1', component_property='figure'),
    [
        Input(component_id='ddl_x', component_property='value'),
        Input(component_id='ddl_y', component_property='value')
    ]
)
def update_output(ddl_x_value, ddl_y_value):
    figure={
        'data': [
            go.Scatter(
                x=data[data['class'] == cls][ddl_x_value],
                y=data[data['class'] == cls][ddl_y_value],
                mode='markers',
                marker={ 'size': 15 },
                name=cls
            ) for cls in data['class'].unique()
        ],
        'layout': 
            go.Layout(
                height= 350,
                hovermode= 'closest',
                title=go.layout.Title(text='Dash Interactive Data Visualization',xref='paper', x=0)
            )
        
    }
    return figure
if __name__ == '__main__':
    app.run_server(debug=True, port=8080, host='0.0.0.0')

실행결과는 다음과 같다.

 

[원문보기] https://towardsdatascience.com/interactive-visualization-with-dash-and-plotly-29eaccc90104

 

Interactive Visualization with Dash and Plotly

Interactive data visualization has an important impact on exploratory data analysis. Before applying any descriptive or predictive…

towardsdatascience.com