การสร้าง Data Visualization ด้วย Dash ตอนที่ 4 : Live updating

Live updating คือการที่ระบบสามารถปรับปรุงข้อมูลได้เองตามช่วงเวลาที่กำหนด โดยผู้ใช้ไม่ต้องไปทำการ refresh หน้าจอด้วยตัวเอง ตัวอย่างรูปที่ 1 ผลของการ live updating ทำให้ตัวเลขเปลี่ยนค่าได้เองทุก 1 วินาทีเพื่อใช้แสดงเวลา
รูปที่ 1

Interval เป็น component ใน Dash Core Component package ทำหน้าที่เหมือนกับนาฬิกาปลุก ตั้งเวลาปลุกผ่าน property ชื่อ interval ในหน่วย miliseconds กิจกรรมที่จะเกิดขึ้นเมื่อถึงเวลาที่กำหนดไว้จะทำโดยการเรียกใช้ callback เนื่องจากต้องมีการใช้ callback ตัว Interval component เองต้องมี unique id ของตัวเอง ยังมีตัวแปรสำคัญอีกตัวคือ n_intervals ซึ่งจะมีค่าเพิ่มขึ้นอัตโนมัติทุกครั้งเมื่อมีการเรียกใช้ callback

การประกาศตัวแปร Interval component ในโปรแกรม จะทำเหมือนกับการประกาศ web component อื่น ในตัวอย่างเป็นการประกาศโดยให้อยู่ภายใต้ Div component กำหนดให้มี Interval component ที่มี id เป็น 'clock-interval' มีรอบในการทำงานทุก 1 วินาที (1000 milliseconds) และกำหนดค่าเริ่มต้นให้ n_interval เป็น 0

import dash_core_components as dcc
import dash_html_components as html
    
app.layout = html.Div(id='main-div',
			children=[
				dcc.Interval(
						id='clock-interval',
						interval=1*1000, # fires every second
						n_intervals=0 # initial value, could be any integer
					)
                 ]
             )
    

สร้าง callback function
  
@app.callback(Output(...), Input('clock-interval', 'n_intervals'))
def what_to_do(n):
	# do something
Interval component จะเป็น Input ของ callback โดยอ้างอิงจาก id และจะมีการส่งค่า n_intervals ด้วย แต่ก็ขึ้นกับการออกแบบว่าจะใช้งานหรือไม่


มาดูตัวอย่างการสร้างนาฬิกาบอกเวลาแบบง่าย ขั้นตอนการทำงานคือ Interval component จะเรียกใชงาน callback function ทุก 1 วินาที การทำงานของ callback function คือ รับค่าเวลาปัจจุบันจาก system แล้วนำไปแสดงที่ส่วนของ user interface
รูปที่ 2

สร้าง layout ในที่นี้ใช้ bootstrap framework
  
import dash_html_components as html
import dash_core_components as dcc

app.layout = html.Div(className="card",
					style={'width': '18rem'},
					children=[
						html.Div(className="card-body",
							children=[
								html.H2(className="card-title",children="Clock"),
								html.P(id='date-part',className="card-text",children="21-06-2021"),
								html.P(id='time-part',className="card-text",children="15:00:00"),
                                dcc.Interval(id='clock-interval',
											interval=1*1000, # in  1000 milliseconds
											n_intervals=0
								)
							]),
						
					]
			)	
  

จะเห็นว่ามีการเติม Interval component (id='clock-interval') เข้าไปใน layout การเติม component นี้จะไม่ส่งผลต่อการแสดงผลบนหน้าจอ

เติมการทำงานในส่วน callback
      
@app.callback([Output('date-part', 'children'),Output('time-part', 'children')],
               Input('clock-interval', 'n_intervals'))
def update_ui(n):
	_now = datetime.datetime.now()
	_date = "{:02d}-{:02d}-{}".format(_now.day,_now.month,_now.year)   
	_time = "{:02d}:{:02d}:{:02d}".format(_now.hour,_now.minute,_now.second)   
	return [_date,_time]

มีข้อสังเกตุคือ argument ที่เป็น Output ของ callback มี 2 component คือ "date-part" และ "time-part" ทั้งสองถูกจัดอยู่ใน array ซึ่งจะสอดคล้องกับ output จาก stand alone function ชื่อ update_ui จะ return ออกมาเป็น array เช่นกัน

นำมาสร้างเป็น application
        
import datetime
import dash
import dash_core_components as dcc
import dash_html_components as html
from dash.dependencies import Input, Output

ext_css = ["https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" ]
app = dash.Dash(__name__, external_stylesheets=ext_css)

app.layout = html.Div(className="card",
					style={'width': '18rem'},
					children=[
						html.Div(className="card-body",
							children=[
								html.H2(className="card-title",children="Clock"),
								html.P(id='date-part',className="card-text",children="21-06-2021"),
								html.P(id='time-part',className="card-text",children="15:00:00"),
								dcc.Interval(id='clock-interval',
									interval=1*1000, # in  1000 milliseconds
									n_intervals=0
								)
							]),
						
					]
			)			
			
@app.callback([Output('date-part', 'children'),Output('time-part', 'children')],
              Input('clock-interval', 'n_intervals'))
def update_ui(n):
	_now = datetime.datetime.now()
	_date = "{:02d}-{:02d}-{}".format(_now.day,_now.month,_now.year)   
	_time = "{:02d}:{:02d}:{:02d}".format(_now.hour,_now.minute,_now.second)   
	return [_date,_time]

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

เมื่อเสร็จแล้วผลที่ได้บนเว็บบราวเซอร์จะเป็นดังรูปที่ 2
รูปที่ 2


เป้าหมายของตอนนี้คือการแนะนำการทำ live updating โดยใช้ประโยชน์จาก Interval component และ callback function อย่างง่าย มีตัวอย่างโครงงานส่วนตัวของผู้เขียนเอง ทำขึ้นเพื่อการศึกษาและทดลองเพิ่มข้อมูลพยากรณ์อากาศรายชั่วโมงเข้าไปด้วย ดังที่เห็นในรูปที่ 1 ท่านที่สนใจสามารถนำ code ไปศึกษาได้จาก https://github.com/somchaisomph/weatherclock เนื่องจากผู้เขียนได้ใช้ข้อมูลพยากรณ์อากาศจากกรมอุตุนิยมวิทยา ดังนั้นหากท่านต้องการ สามารถไปดำเนินการขอรับ token ได้โดยไม่มีค่าใช้จ่ายจาก https://data.tmd.go.th/nwpapi/doc/


Latest
Previous
Next Post »