ในบทความนี้เราจะมาทำการประยุกต์ใช้งาน Chart.js ร่วมกันกับ Flask ซึ่งเรียกได้ว่าเป็น stack ที่รวมกันแล้วค่อนข้างที่จะเซ็กซี่นิดหนึ่ง ที่พูดแบบนี้ก็เพราะว่าทั้งคู่เป็นเฟรมเวิร์คและไลบรารี่ที่สามารถสร้างงานของตัวเองได้อย่างรวดเร็ว Flask นั้นก็สามารถที่จะสร้างเว็บได้อย่างรวดเร็ว ส่วน Chart.js ก็สามารถที่จะสร้าง Chart เพื่อทำการแสดงผลข้อมูลได้อย่างรวดเร็วมาก ๆ พร้อมทั้งง่ายและสะดวกเช่นกัน ดังนั้นจึงเป็นการจับคู่ที่ค่อนข้างจะลงตัวเสียจริง ๆ
ปล. สามารถชมคลิป Flask with Chart.js ประกอบการเรียนเพิ่มเติมได้ที่ในช่องยูทูปของเราได้ เพิ่มเติมเลยครับ และบทความนี้สามารถประยุกต์ Chart.js เพื่อใช้งานกับ Django ได้เช่นกัน คอนเซ็ปต์เหมือนกัน
ทำการสร้างไฟล์ app.py ขึ้นมาเพื่อเขียนโค้ดไพธอน
app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def chart():
return render_template('chart.html')
if __name__ =="__main__":
app.run(debug=True)
ตอนนี้คือการ render หน้า HTML ออกไปแสดงผล โดยตั้งชื่อไฟล์ว่า chart.html โดยตอนนี้ยังไม่ได้ทำการสร้างไฟล์นี้ขึ้นมา โดยไม่รอช้าสร้างไฟล์นี้ขึ้นมาได้เลย
ก่อนที่จะสร้างไฟล์ ต้องทำการสร้างโฟลเดอร์ templates เพื่อใช้เก็บไฟล์ HTML ต่าง ๆ ซึ่งนี่ก็เป็นโครงสร้างของ Flask ที่ได้วางไว้แบบนี้ ซึ่งถ้าท่านใดที่เคยเขียน Django ก็จะพบว่ามันเหมือนกันเป๊ะเลยในโครงสร้างส่วนนี้
chart.html
<!DOCTYPE html>
<html>
<head>
<title>Chart.js with Flask</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
</head>
<body>
<div class="container">
<h1>Flask with Chart.js Tutorial</h1>
</div>
</body>
</html>
จะเห็นว่าผมได้มีการเรียกใช้งาน Chart.js CDN เข้ามาใช้นั่นก็คือ
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
</head>
Bootstrap CDN
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
ตอนนี้เรายังไม่ได้ทำการแสดงผล Chart ยังเป็นเพียงแค่ข้อความ "Flask with Chart.js Tutorial"
เมื่อทำการรันเซิร์ฟเวอร์ จะได้ดังภาพด้านล่าง
จากนั้นไปที่ Chart.js Document และทำการก็อปปี้โค้ด Tutorial เบื้องต้นมาใช้ และวางไว้ภายในแท็ก <body> ของไฟล์ chart.html
<canvas id="myChart" width="400" height="400"></canvas>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>
var ctx = document.getElementById('myChart').getContext('2d');
กำหนดตัวแปรที่มีชื่อว่า ctx และกำหนดไอดีชื่อว่า "myChart"
type: 'bar'
type เราสามารถที่จะกำหนดประเภทของ Chart ให้เป็นประเภทต่าง ๆ ได้ตามต้องการ เช่น บาร์, ไลน์, โดนัท, เส้น ฯลฯ เป็นต้น ซึ่งจะเห็นว่ามันค่อนข้างที่จะสะดวกสุด ๆ ไปเลยครับ ในการเปลี่ยนประเภทของ chart
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange']
labels คือส่วนของชื่อของข้อมูลในแต่ละชาร์จ
data: [12, 19, 3, 5, 2, 3]
data คือส่วนของข้อมูลของแต่ละชาร์จเป็นแบบ Array โดยเราสามารถทดสอบเปลี่ยนแปลงข้อมูลได้ตามต้องการเพื่อทดสอบ
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
backgroundColor คือสีของชาร์จแต่ละชาร์จที่กำหนดเป็นแบบ RGB เลือกใช้ได้ตามต้องการ
โดยสามารถศึกษาหรือดูโค้ดสีแต่ละสีตามต้องการได้ในเว็บนี้ คลิ๊ก
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
โดยเรานำโค้ดด้านบนมาวางไว้ในส่วนของแท็ก body ของ HTML ได้เลย
app.py
from flask import Flask, render_template
app = Flask(__name__)
data = [5, 9, 10, 7, 15, 11]
@app.route('/')
def chart():
chart_data = data
return render_template('chart.html', chart_data=chart_data)
if __name__ =="__main__":
app.run(debug=True)
จากนั้นทำการรันเซิร์ฟเวอร์
$ python app.py
จะได้หน้า Chart
จะเห็นว่าได้ Bar Chart มาเรียบร้อยแล้ว แต่ขนาดยังไม่ได้สัดส่วนยังใหญ่เกินไป แก้ปัญหาโดยปรับขนาดโดยใช้ col-md-5 ของ Bootstrap เข้าไปในแท็ก <div>
<div class="col-md-5">
<canvas id="myChart" width="400" height="400"></canvas>
</div>
จะได้ Bar Chart ที่ดูขนาดสมส่วน อย่างที่ได้กล่าวไปด้านบนว่า เราสามารถที่จะเปลี่ยนสีของ Chart ได้ตามต้องการไม่ว่าจะเป็นสีพื้นหลัง backgroundnColor หรือเส้นขอบ boderColor ตามรหัสสี RGB ของแต่ละตัวได้เลย
ถึงขั้นตอนนี้แล้วหลายท่านอาจเกิดความสงสัย แล้วถ้าเราต้องการที่จะเปลี่ยนแปลงข้อมูลของ Chart เราต้องตามแก้โค้ดในไฟล์ HTML นี้ตลอดเลยหรือไม่ คำตอบคือไม่ครับ มันไม่ค่อย make sense เอาเสียเลยที่จะทำแบบนั้น ดังนั้นวิธีการที่ดีคือข้อมูลควรจะมาจาก Database, จาก API Services, etc. และเป็นแบบอัปเดตโดยอัตโนมัติ
สมมติว่าเราทำการดึงข้อมูลมาจาก Database ที่อยู่ฝั่งหลังบ้าน แต่ในบทความนี้ยังไม่ได้ทำการสร้าง Database แต่ก็ไม่มีปัญหาครับ ทดสอบสร้างข้อมูลแบบ Fake Data ขึ้นมาเพื่อทดสอบเล่น ๆ ก่อนได้
สร้างข้อมูลขึ้นมาเพื่อทดสอบเก็บเป็นแบบ List เพื่อให้เข้ากันกับข้อมูลของ Chart ที่เป็นแบบ Array ในโค้ด JavaScript ของ Chart.js โดยกำหนดตัวแปรชื่อ data = [...] เก็บข้อมูลจำนวน 6 members และทดสอบใส่เป็นข้อมูลปลอม ๆ ขึ้นมาเพื่อทดสอบกำหนดเป็น 10 ทุกตัว
data = [10, 10, 10, 10, 10, 10]
app.py
# Fake data
data = [10, 10, 10, 10, 10, 10]
@app.route('/')
def chart():
chart_data = data
return render_template('chart.html', chart_data=chart_data)
ตอนนี้ข้อมูลที่อยู่ในตัวแปร data ซึ่งก็คือ 10 ที่อยู่ใน members ทั้ง 6 ตัวของ List หลายท่านอาจจะสงสัยว่าทำไมต้องใช้ 10 เหมือนกันทุกตัว คำตอบก็คือผมอยากให้ตัว Chart นั้นดูง่ายครับว่ามันเป็นข้อมูลเดิมที่มากับ Chart หรือเป็นข้อมูลของเราที่สร้างขึ้นมาใหม่จากฝั่ง Backend คือ Flask แล้วส่งไปแสดงผล ดังนั้นการใช้ข้อมูลเหมือนกันจะทำให้ดูง่ายถ้าตัว Chart อยู่ในระนาบเดียวกันแสดงว่าข้อมูลของเราแสดงผลใน Chart ได้สำเร็จครับ
คำถามต่อมาคือเราจะแสดงผลข้อมูลใน Chart ได้ยังไง คำตอบก็คือ ใช้การวนลูปข้อมูลเหมือนที่เคยทำใน Flask โปรเจคท์ที่ผ่าน ๆ ได้เลยเพราะว่าข้อมูลเป็นแบบ List ก็ต้องใช้ for loop นั่นเองครับ
chart.html
data: [12, 19, 3, 5, 2, 3]
จากโค้ดด้านบนคือข้อมูลเดิมที่มากับ Chart.js แต่ข้อมูลตรงนี้เราจะไม่ใช้อีกต่อไป จะเป็นการลูปข้อมูลที่ส่งมาจากฝั่ง Backend แทนครับ ทำได้โดยการวนลูปออกมาได้เลย โดยใช้ Jinja2 Template ของ Flask ตามปกติ ซึ่งหลายท่านอาจจะสงสัยว่า ตรงส่วนนี้มันเป็นโค้ดของ JavaScript เราจะใช้ Jinja2 Template ได้หรือไม่เพราะว่าเคยใช้ในส่วนของ HTML เท่านั้น คำตอบก็คือทำได้สบาย ๆ เหมือนกันเลยครับ โดยขอเสริม Jinja Template แบบคร่าว ๆ สักหน่อยเพื่อเป็นการทบทวนสำหรับใคร ๆ หลายคนครับ
{% %} --> คือ Tag เอาไว้ใช้เขียนคำสั่งหรือลอจิกต่าง ๆ
{{ }} --> คือ Variable เอาไว้ใช้แสดงผลข้อมูล
ทำการลูปข้อมูลออกมาแสดงผล
data: [{% for dt in chart_data %} {{dt}} {% endfor %}],
โดย chart_data คือข้อมูลที่ส่งมาจากฝั่ง Backend ในฟังก์ชัน render_template นั่นเอง
จากนั้่นทำการรีเฟรชหน้าเว็บ
จะเห็นว่าตอนนี้ Chart ก็ยังไม่แสดงผล แสดงว่าต้องมีบางอย่างผิดพลาด ตรวจสอบได้โดยการคลิ๊กขวา Inspect หรือ ตรวจสอบ ที่หน้าเพจนี้
เมื่อทำการ Inspect ดู จะพบว่าข้อมูลนั้นถูกส่งมาไม่มีปัญหา เมื่อเปรียบเทียบกับข้อมูลที่ได้ทำการคอมเมนต์ไว้ด้านบน แต่เพียงแค่ไม่ถูกฟอร์แมตเท่านั้นครับคือ ข้อมูลคือ 10 ที่อยู่ใน Array นั้นไม่มีคอมม่ามาคั่น ทำการแก้ไขใหม่โดยเพิ่มคอมม่าเข้าไปหลัง Variable Tag คือ {{ dt }}
เพิ่ม , คอมม่าเข้ามา
data: [{% for dt in chart_data %} {{dt}}, {% endfor %}],
จากนั้นทำการรีเฟรชหน้าเว็บอีกครั้ง
app.py
from flask import Flask, render_template
app = Flask(__name__)
# Fake data
data = [10, 10, 10, 10, 10, 10]
@app.route('/')
def chart():
# Assign data created above into a new variable
# called "chart_data" then send it to frontend(HTML)
# to display on Bar Chart
chart_data = data
return render_template('chart.html', chart_data=chart_data)
if __name__ =="__main__":
app.run(debug=True)
<!DOCTYPE html>
<html>
<head>
<title>Chart.js with Flask</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" integrity="sha384-TX8t27EcRE3e/ihU7zmQxVncDAy5uIKz4rEkgIXeMed4M0jlfIDPvg6uqKI2xXr2" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.min.js"></script>
</head>
<body>
<div class="container">
<h1>Flask with Chart.js Tutorial</h1>
<div class="col-md-5">
<canvas id="myChart" width="400" height="400"></canvas>
</div>
</div>
<script>
var ctx = document.getElementById('myChart').getContext('2d');
var myChart = new Chart(ctx, {
type: 'bar',
data: {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [{
label: '# of Votes',
// data: [12, 19, 3, 5, 2, 3],
data: [{% for dt in chart_data %} {{dt}}, {% endfor %}],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)'
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)'
],
borderWidth: 1
}]
},
options: {
scales: {
yAxes: [{
ticks: {
beginAtZero: true
}
}]
}
}
});
</script>
</body>
</html>
สำหรับบทความ การประยุกต์ใช้งาน Flask with Chart.js Tutorial ก็ขอจบลงเพียงเท่านี้ ผมหวังเป็นอย่างยิ่งว่าเพื่อน ๆ ที่อ่านบทความนี้จบแล้ว จะเข้าใจคอนเซ็ปต์และนำไปต่อยอดเพิ่มเติมได้เป็นอย่างดีนะครับ เช่นการสร้าง Dashboard ต่าง ๆ การทำ Data Visualization เป็นต้น
ถ้าถูกใจบทความนี้ก็อย่าลืมคอมเมนต์เข้ามาที่ด้านล่างของบทความนี้เพื่อซัพพอร์ตและให้กำลังใจผลงานการเขียนของผมกันได้เลยนะครับ จะขอบคุณมาก ๆ ครับ
Follow us on
Medium: STACKPYTHON
Youtube: STACKPYTHON
Facebook: STACKPYTHON
หรือเข้าชมคอร์ส Flask Full Course ของ STACKPYTHON
กิจกรรมที่กำลังจะมาถึง
ไม่พลาดกิจกรรมเด็ด ๆ ที่น่าสนใจ
Event นี้จะเริ่มขึ้นใน April 25, 2023
รายละเอียดเพิ่มเติม/สมัครเข้าร่วมคอร์สเรียนไพธอนออนไลน์ที่เราได้รวบรวมและได้ย่อยจากประสบการณ์จริงและเพื่อย่นระยะเวลาในการเรียนรู้ ลองผิด ลองถูกด้วยตัวเองมาให้แล้ว เพราะเวลามีค่าเป็นอย่างยิ่ง พร้อมด้วยการซัพพอร์ตอย่างดี