Pandas dataframe이나 Numpy Data 분석 결과를 그래프로 보여줄 때 가장 많이 사용하는 Python lib는 matplotlib와 seaborn입니다. 기존보다 간편하고 Web service까지 가능한 라이브러리를 찾다가 Plotly와 Dash를 알게 되었고 사용 방법을 정리하였습니다.
일반적으로 서버단 BackEnd에서 Python이나 R로 데이터를 처리하고, 이를 Web Chart를 제공하기 위해서는 Java script으로(e.g. chart.js)로 FrontEnd를 구현해야 합니다. 즉, 개발자 측면에서는 DB 연동, Data 전처리, AI와 같은 동작은 BackEnd에서 Python으로 개발하고, FrontEnd는 Java script를 사용했어야 했어야 합니다. Plotly와 Dash는 2개의 언어를 사용할 필요 없이, Python 언어로만 Web 기반으로 Visualization이 가능합니다. 즉 Python으로 구현한 AI나 Data 분석의 결과를 그대로 (다른 언어 변경 없이) Web visualization이 가능합니다. 단점은 matplotlib 대비 reference code가 적습니다.
Plotly는
- Python으로 만들어진 Grapy lib로 matplotlib의 대체할 수 있음
- Scatter, Line, Area, Bar chart, Histogram, Polar 등의 기본 차트와 Animation, Heat map, Tree map, Map 등의 다양한 chart 지원
- MIT 라이선스의 Open Source이며 무료임
Dash는
- Plotly에 기반하여 Web Service를 개발할 수 있는 라이브러리로 Flask+matplotlib 구현을 대체할 수 있음 (Python, R, Jullia와 호환)
- MIT라이선스의 Open Source이며 무료임.
- Dash Enterprise와 같은 유료 서비스도 제공함
Plotly에 대한 설명은 아래 유튜브 채널에 자세히 설명되어 있습니다. 공식 홈 페이지와 함께 유튜브를 확인하는 것을 추천드립니다.
Ploltly와 Dash 설치
최신 버전의 Plotly 설치는 GitHub 사이트에서 확인할 수 있습니다. Plotly는 PIP로 설치할 수 있으며, 현시점에서는 plotly 5.1.0을 설치합니다. plotly-geo나 chart-studio Lib는 필수는 아니며 사용 시점에서 설치하면 됩니다. Dash도 PIP로 설치하면 1.21 버전이 설치됩니다.
$ sudo pip3 install plotly
$ sudo pip3 install dash
Ploltly로 Scatter chart 만들기
Plotly Gallery에 다양한 Chart 예제와 reference code가 있습니다. Iris 데이터를 plotly.express 객체로 Scatter chart를 그리는 방법입니다.
▣ Python code: plotly.express as px로 선언하고 px.scatter() 함수에 parameter를 설정합니다. Pandas dataframe을 입력하고 px.scatter() 함수를 사용해서 chart를 출력합니다.
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species")
fig.show()
▣ Data set 설명: Iris Data set은 ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'species', 'species_id'] 의 column으로 구성된 데이터입니다. 'sepal_length', 'sepal_width', 'petal_length', 'petal_width' 값은 독립 변수이고, 'species'는 종속 변수입니다. 코드 내용은 df = px.data.iris()으로 dataframe으로 불러옵니다.
▣ px.scatter() 실행 결과: Dataframe에서 x 축에 표시한 column과 y축에 표시할 column을 지정합니다. 각 (x, y)에 해당하는 점의 color값은 'species' column 값으로 지정합니다. 해당 Python code을 실행하면 Web broswer에서 Graph가 표시되고, 개발 메뉴에서 html을 확인해보면 java script (ploly.js)로 구성되어 있습니다.
Ploltly로 만든 chart를 이미지로 저장하기
plotly로 만든 chart를 저장하기 위해서는 fig.write_image() 함수를 사용해야 합니다. plotly는 내부적으로 kaleido 라이브러리를 이용해서 이미지 파일을 저장합니다. kaleido 설치는 pip로 설치 가능합니다. plotly에서는 png, jgp, webp, svg, pdf, eps 포맷을 지원합니다. 앞에서 설명한 Image Writing 엔진은 kaleido, oraca를 사용하고 기본 값은 kaleido입니다. 이미지의 사이즈를 지정하고 싶은 경우 fig.write_image() 함수 호출 시 width 값과 height 값을 지정하면 됩니다.
$ sudo pip3 install kaleido
▣ kaleido 미 설치 에러 메시지:
Traceback (most recent call last):
File "/Users/kibua20/git/DevDocs/keras/11_ploty.py", line 11, in <module>
fig.write_image('11_plotly.png')
File "/usr/local/lib/python3.9/site-packages/plotly/basedatatypes.py", line 3821, in write_image
return pio.write_image(self, *args, **kwargs)
File "/usr/local/lib/python3.9/site-packages/plotly/io/_kaleido.py", line 268, in write_image
img_data = to_image(
File "/usr/local/lib/python3.9/site-packages/plotly/io/_kaleido.py", line 134, in to_image
raise ValueError(
ValueError:
Image export using the "kaleido" engine requires the kaleido package,
▣ 이미지 저장 코드
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import plotly.express as px
df = px.data.iris()
fig = px.scatter(df, x="sepal_width", y="sepal_length", color="species")
fig.write_image('11_plotly.png')
Dash를 활용하여 Web Server 구현
Dash를 활용해서 Web scatter chart를 구현하는 예제입니다. Web Server에서 Dash 객체를 생성하여 callback 함수를 정의하고, Client에서 서버 주소로 접근하면 아래와 같이 Graph를 구성할 수 있습니다.
Web Server의 코드는 11_dash.py 파일에 dash obj를 생성하고, Web 서버 (127.0.0.1)의 8050 포트를 listen 하고 있고, Client에서는 IP주소:포트로 접속하면 아래와 같이 Web broswer에서 scatter chart를 표시합니다.
- Web Server에서 dash 실행: $ python 11_dash.py
- Client에서 서버에 접속: http://127.0.01:8050
서버의 실행 결과를 확인하면 Dash가 Flask으로 구동되고 있음을 확인할 수 있습니다. Flask의 기본적인 내용은 이전 포스팅을 참고해주세요.
서버에 올라가는 Dash App의 소스는 다음과 같습니다. app.layout에 scatter-plot의 객체를 선언하고, callback데이터에서 dataframe의 값을 전달합니다.
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html from dash.dependencies
import Input, Output
import plotly.express as px
#define dataframe
df = px.data.iris()
app = dash.Dash(__name__)
# dash app layout
app.layout = html.Div([
dcc.Graph(id="scatter-plot"),
html.P("Petal Width:"),
dcc.RangeSlider(
id='range-slider',
min=0, max=2.5, step=0.1,
marks={0: '0', 2.5: '2.5'},
value=[0.5, 2]
),
])
# callback - feed data
@app.callback(
Output("scatter-plot", "figure"),
[Input("range-slider", "value")])
def update_bar_chart(slider_range):
low, high = slider_range
mask = (df['petal_width'] > low) & (df['petal_width'] < high)
fig = px.scatter(
df[mask], x="sepal_width", y="sepal_length",
color="species", size='petal_length',
hover_data=['petal_width'])
return fig
if __name__ == '__main__':
app.run_server(debug=True)
Plotly Dash App과 Flask App과 연동
일반적으로 Web page를 Hosting 할 때 Apache와 같은 Web Server를 두고 Gunicorn 등 사용해서 WSGI로 연동시킵니다. 이 경우 기존에 Flask와 연동을 유지하기 위해서는 아래와 같이 수정합니다. Flask App 객체를 만들고, dash.Dash() 객체 생성 시 server를 flask서로 설정합니다. (참고 링크 1, 링크 2)
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import dash
import dash_core_components as dcc
import dash_html_components as html from dash.dependencies
import Input, Output
import plotly.express as px
from flask import Flask
#define dataframe
df = px.data.iris()
#before
#app = dash.Dash(__name__)
#after - flask app
server = Flask(__name__)
app = dash.Dash(
__name__,
server=server,
# url_base_pathname='/yourpath'
# external_stylesheets = 'your css'
)
# end
# dash app layout
app.layout = html.Div([
dcc.Graph(id="scatter-plot"),
html.P("Petal Width:"),
dcc.RangeSlider(
id='range-slider',
min=0, max=2.5, step=0.1,
marks={0: '0', 2.5: '2.5'},
value=[0.5, 2]
),
])
# callback - feed data
@app.callback(
Output("scatter-plot", "figure"),
[Input("range-slider", "value")])
def update_bar_chart(slider_range):
low, high = slider_range
mask = (df['petal_width'] > low) & (df['petal_width'] < high)
fig = px.scatter(
df[mask], x="sepal_width", y="sepal_length",
color="species", size='petal_length',
hover_data=['petal_width'])
return fig
if __name__ == '__main__':
app.run_server(debug=True)
Plotly/Dash와 가격 정책
Ploty 가격 정책과 관련해서 https://plotly.com/python/is-plotly-free/에 정리되어 있습니다. Plot와 Dash 모두 MIT 라이선스의 Open source로 상업적 목적으로 무료 사용 가능합니다. MIT 라이선스는 오픈소스를 활용하여 개발한 소스의 공개 의무가 없으며, 상업적 이용도 가능합니다. 다만 저작권 고지 및 라이선스 사본을 제품에 포함시키면 됩니다. Plotly와 Dash의 가격 정책에 대한 Community Forum 내용은 링크를 참조해주세요.
- plotly는 Open Source이며 MIT 라이선스로 무료로 사용 가능
- 특정 서비스에 계정 등록 필요 없음, 인터넷 연결이 없는 상태에서도 plotly 사용 가능
- Dash도 Open Source이며 MIT 라이선스로 무료로 사용 가능
- Commerical Service는 Dash Enterprise와 Chart Studio Enterprise에서 제공함
Dash Enterprise와 무료 Open source 버전의 차이점은 다음과 같습니다. 주로 Kerbernaties Deploy 관련한 사항과 Dash board engine, reporting engine에서 차이점이 있습니다.
관련 글:
[SW 개발/Data 분석 (RDB, NoSQL, Dataframe)] - Python Dataframe Visualization: matplotlib로 chart 그리기 (sample code)
[SW 개발/Data 분석 (RDB, NoSQL, Dataframe)] - Python Keras를 이용한 로직스틱 회귀 분석(logistics regression) 예제- Wine Quality 분석(Sample code)
[SW 개발/Python] - Python Decorator를 이용한 함수 실행 시간 측정 방법 (Sample code)
[SW 개발/Data 분석 (RDB, NoSQL, Dataframe)] - 우분투 20.04에서 MariaDB 설치 및 기본 동작 확인 명령어
[SW 개발/Data 분석 (RDB, NoSQL, Dataframe)] - Jupyter Notebook의 업그레이드: Jupyter Lab 설치 및 extension 사용법
[SW 개발/Python] - Python: xmltodict를 활용하여 XML를 JSON으로 변환하는 방법
[블로그 관리/티스토리 블로그 관리] - 파이썬 Selenium을 활용한 네이버 서치어드바이저 URL 입력 '자동화'
[Cloud/Oracle Cloud] - 오라클 클라우드 '평생' 무료 VM 만들기 (Google Cloud 무료 조건 비교)
[SW 개발/Python] - Python: OSError: [Errno 98] Address already in use (Flask)
[개발환경/Web Server] - 우분투 20.04에서 lighttpd Web Server 설치 (Embedded용으로 활용 가능)
[개발환경/Web Server] - Python: Web Framework Flask 사용하기
댓글