การสร้าง Data Visualization ด้วย Dash ตอนที่ 3 : Callback function basic

callback หรือ call-after คือเทคนิคการใช้ decorator [1] ในภาษา Python มักใช้ร่วมกับ Input และ Output และ Dash Core Compoments เพื่อสร้างระบบที่มีปฏิสัมพันธ์กับผู้ใช้ เช่น

import dash
import dash_core_components as dcc
import dash_html_components as html


ext_css = ['https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.1.2/tailwind.min.css']
app = dash.Dash(__name__, external_stylesheets=ext_css)

app.layout = html.Div(className="md:container md:mx-auto rounded-md shadow p-6 rounded-lg bg-gray-500 px-10",
			children=[
				html.H1(children='เลือกจังหวัดที่ต้องการ :'),
				html.Br(),
				dcc.Dropdown(id="province_list",
					options=[{'label':clr,'value':clr} for clr in ['---','กรุงเทพฯ','เชียงใหม่','ขอนแก่น','ประจวบคิรีขันธ์']]),
				html.Hr(),             
				html.Div(id='result'),

    
			])

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

รูปที่ 1


ผลที่ได้ตามรูปที่ 1 คือหน้าจอมี interactive component คือ dropdown ปรากฏให้เห็น แต่ยังไม่มีการทำงานด้านข้อมูล

กำหนด Input และ Output

ทั้งสองเป็น class ใน dash.dependencies package นำเข้าสู่ระบบด้วยคำสั่ง

    from dash.dependencies import Input,Output
    

argument ที่ต้องส่งให้กับ Input และ Ouput มีสองอย่างคือ
  • id ของ HTML component ที่จะเป็นผู้ส่งข้อมูลและผู้รับข้อมูล
  • property ของ HTML component ที่เป็นที่แหล่งเก็บข้อมูลในกรณีของ Input หรือที่ต้องการปรับแต่งในกรณีของ Output
จากตัวอย่างข้างต้น component id และ property ของ component ที่จะส่งให้ Input คือ ("province_list","value") สำหรับ Ouput คือ ("result","children")

    Input(component_id="province_list",component_property="value")
    Output(component_id="result",component_property="children")
    

ตามที่กล่าวมาก่อนหน้าว่า callback อาศัยการทำ decoration ทั้ง Input และ Output ที่ประกาศแล้วจะถูกนำไปเป็น arguments สำหรับ decorator function ชื่อ "callback" ซึ่งเป็น function หนึ่งใน class app (หากยังไม่เข้าใจเรื่อง decoration กรุณาทบทวนเรื่องนี้ใน decorator)

@app.callback(Output(component_id="result",
                component_property="children"),
              Input(component_id="province_list",
               component_property="value")
         )    
    

ขั้นตอนต่อไปคือการสร้าง stand alone function เพื่อกำหนดขั้นตอนการประมวลผลข้อมูลที่ได้ ผลลัพธ์ที่ส่งออกไปจาก stand alone function จะถูกส่งต่อให้ component ที่ถูกกำหนดให้เป็น output รับค่าไปแสดง

def display_provice(province):
	msg=""
    if province=="---" or province is None :
    	return "You chose nothing."
    else:
    	return ""You chose {}".format(province)
    


นำ code ทั้งหมดมารวมกัน

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


ext_css = ['https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.1.2/tailwind.min.css']
app = dash.Dash(__name__, external_stylesheets=ext_css)

app.layout = html.Div(className="md:container md:mx-auto rounded-md \
                                 shadow p-6 rounded-lg bg-gray-500 px-10",
			children=[
				html.H1(children='เลือกจังหวัดที่ต้องการ :'),
				html.Br(),
				dcc.Dropdown(id="province_list",
					options=[{'label':clr,'value':clr} for clr in ['---','กรุงเทพฯ','เชียงใหม่','ขอนแก่น','ประจวบคิรีขันธ์']]),
				html.Br(),             
				html.Div(id='result'),

    
			])
@app.callback(Output(component_id="result",component_property="children"),
              Input(component_id="province_list",component_property="value")
			  )
			  
def display_provice(province):
	msg=""
	if province=="---" or province is None :
		return "You chose nothing."
	else:
		return "You chose {}".format(province)
			  
if __name__ == '__main__':    
    

รูปที่ 2

รูปที่ 3


ตัวอย่างที่สองเป็นการทำ callback เพื่อทำการ update การแสดงผลในรูปของกราฟ (ดูเรื่อง bargraph ของ plotly express ประกอบ)

import numpy as np
import pandas as pd
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Output,Input
import plotly.express as px


# -- dataframe
df = pd.read_csv('./data/demo2.csv')

ext_css = ['https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.1.2/tailwind.min.css']
app = dash.Dash(__name__, external_stylesheets=ext_css)

app.layout = html.Div(className="md:container md:mx-auto rounded-md \
                                 shadow p-6 rounded-lg bg-gray-500 px-10",
			children=[
				html.H1(children='เลือกทวีปที่ต้องการ :'),
				html.Br(),
				dcc.Dropdown(id="continent_list",
					options=[{'label':clr,'value':clr} for clr in ['Asia','Africa','Europe','North America','Oceania','South America']]),
				html.Br(),             
				dcc.Graph(id='bar-graph')
			])
@app.callback(Output(component_id="bar-graph",component_property="figure"),
              Input(component_id="continent_list",component_property="value")
			  )
			  
def update_graph(continent):
	filtered = df.loc[df['continent']==continent,
					  ['total_cases','total_deaths',
					  'population','aged_65_older',
					  'female_smokers','male_smokers']].melt()
	filtered['value']  = np.log10(filtered['value'] )
	figure = px.bar(filtered,x='variable',y='value',color="value",text="value")
	figure.update_layout(transition_duration=500)
	return figure
			  
if __name__ == '__main__':
    app.run_server('0.0.0.0',debug=True)



สรุปขั้นตอนการทำงาน สำหรับตอนนี้
  1. สร้าง Output, Input instance และกำหนด component id, component property เพื่อให้ระบบทราบว่าจะไปเอาข้อมูลจากที่ไหน ไปแสดงที่ไหน
  2. ส่ง Output และ Input เป็น argument ให้กับ callback function
  3. สร้าง stand alone function ขึ้นมาเพื่อกำหนดขั้นตอนการประมวลผลข้อมูล


Previous
Next Post »