Bài 33: Trực quan hóa dữ liệu – PyQtGraph-BarGraph-PyQt6 – Part 3

Trong chuỗi các bài học về BarGraph để trực quan hóa dữ liệu Tui sẽ trình bày 6 bài về các kỹ thuật liên quan tới BarGraph, để tùy từng tình huống hay nhu cầu sử dụng khác nhau mà các bạn có thể áp dụng.

Đối tượng PlotWidget cũng như các kỹ thuật liên quan chúng ta đã học rất chi tiết và đầy đủ ở phần 2, ở phần này Tui không nói lại PlotWidget mà Tui chỉ sử dụng lại PlotWidget để vẽ các BarGraph biểu độ dạng cột, một trong những loại trực quan quá phổ biến.

Mô tả tập dữ liệu cho bài này:

Công ty Lucy có dữ liệu doanh thu trung bình theo quý của năm 2023 như sau:

QuýTrung bình doanh thu
1100
2200
3250
4190

Hãy trực quan hóa dữ liệu bằng biểu đồ cột. Hình dưới đây minh họa kỹ thuật đầu tiên trong chuỗi 6 bài về BarGraphItem này:

Chúng ta lưu ý là toàn bộ các bài liên quan tới trực quan hóa dữ liệu, Chúng ta sẽ sử dụng PlotWidget, các hàm phổ biến liên quan đã được học ở các bài trước đều được tái sử dụng. Còn loại Chart hiển thị như thế nào thì tùy từng trường hợp mà ta sẽ gọi các hàm hiển thị khác nhau.

Ta từng bước thực hiện bài này như sau:

Bước 1: Tạo dự án “LearnPyQtBarGraphPart3” có cấu trúc như hình dưới đây:

  • “MainWindow.ui” là giao diện thiết kế tương tác người dùng bằng Qt Designer
  • “MainWindow.py” là Generate Python code cho giao diện “MainWindow.ui”
  • “MainWindowEx.py” là file mã lệnh kế thừa từ Generate Python Code để xử lý: Nạp giao diện, hiển thị chart, gán sự kiện và không bị lệ thuộc vào giao diện bị thay đổi sau này khi Generate lại code
  • “MyApp.py” là file mã lệnh thực thi chương trình.

Bước 2: Thiết kế giao diện “MainWindow.ui” và đặt tên cho Widget/layout như hình dưới đây:

Bước 3: Generate Python Code cho “MainWindow.ui”, lúc này mã lệnh “MainWindow.py” tự động được tạo ra:

# Form implementation generated from reading ui file 'MainWindow.ui'
#
# Created by: PyQt6 UI code generator 6.5.2
#
# WARNING: Any manual changes made to this file will be lost when pyuic6 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt6 import QtCore, QtGui, QtWidgets


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(434, 352)
        self.centralwidget = QtWidgets.QWidget(parent=MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout_2.setObjectName("verticalLayout_2")
        self.myLayout = QtWidgets.QVBoxLayout()
        self.myLayout.setObjectName("myLayout")
        self.verticalLayout_2.addLayout(self.myLayout)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(parent=MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 434, 22))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(parent=MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "Trần Duy Thanh - BarGraphItem"))

Bước 4: Viết mã lệnh cho “MainWindowEx.py”

Lớp MainWindowEx kế thừa lớp Ui_MainWindow (lớp được Generate Python code ở bước trước)

Tui định nghĩa 1 constructor __init__() gọi lại constructor ở lớp cha, tạm thời trong bài tập này chưa xử lý gì khác.

from MainWindow import Ui_MainWindow
import pyqtgraph as pg

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        self.setupBarGraph()

Hàm setupUi() được override để nạp giao diện, lưu lại biến MainWindow để sử dụng cho quá trình xử lý trong tương lai. Đồng thời nó cũng gọi hàm setupBarGraph() để hiển thị Chart, Hàm này ta viết như sau:

def setupBarGraph(self):
    self.graphWidget = pg.PlotWidget()
    self.graphWidget.setTitle("Lucy Company",
                              color="r",
                              size="15pt",
                              bold=True,
                              italic=True)
    self.graphWidget.setBackground('w')

    labelStyle = {"color": "green", "font-size": "18px"}
    labelBrandStyle = {"color": "pink", "font-size": "18px"}
    self.graphWidget.setLabel("left", "Revenue (VNĐ)", **labelStyle)
    self.graphWidget.setLabel("bottom", "Quarter (time)", **labelStyle)
    self.graphWidget.setLabel("top", "Revenue Report", **labelStyle)
    self.graphWidget.setLabel("right", "tranduythanh.com", **labelBrandStyle)
    self.graphWidget.showGrid(x=True, y=True)

    width = 0.3

    quarter = [1, 2, 3, 4]
    revenue = [100, 200, 250, 190]

    self.bargraphItem = pg.BarGraphItem(x=quarter, height=revenue, width=width, brush='b', name="ABC Revenue")

    self.legend = self.graphWidget.addLegend()

    self.graphWidget.addItem(self.bargraphItem)
    self.myLayout.addWidget(self.graphWidget)

Ta thấy rằng tất cả các phương thức thường sử dụng của PlotWidget trình bày ở bài học trước đều được dùng lại ở đây, nên Tui không có trình bày lại các kiến thức cũ.

Mà các bạn hãy để ý các dòng lệnh mới liên quan tới BarGraphItem thôi:

  • Khai bao và khởi tạo giá trị cho biến width, biến này là độ rộng của cột Bar :
width = 0.3
  • Khai báo mảng lưu 4 quý vào biến quarter:
quarter = [1, 2, 3, 4]
  • Khai báo mảng doanh thu tương ứng với mảng quarter:
revenue = [100, 200, 250, 190]
  • Cuối cùng là hàm vẽ biểu đồ BarGraph bằng cách khai báo đối tượng BarGraphItem:
self.bargraphItem = pg.BarGraphItem(x=quarter, height=revenue, width=width, brush='b', name="ABC Revenue")

Ý nghĩa của BarGraphItem là vẽ các biểu đồ cột, dưới đây là một số thuộc tính/parameter thường dùng của BarGraphItem:

Thuộc tínhÝ nghĩa, Chức năng
xlà đối số lưu mảng các vị trí mà mỗi Cột biểu đồ sẽ được vẽ
heightlà đối số lưu mảng các giá trị (độ cao) của mỗi cột biểu đồ ở vị trí tương ứng trong mảng x
widthLà độ rộng của cột biểu đồ, mà ở trên ta khai báo mặc định là 0.3, ta có thể lựa chọn giá trị tùy thích
brushlà màu của các cột trong biểu đồ
nameLà tên của biểu đồ, nó có ý nghĩa cho xử lý tương tác biểu đồ, legend trên biểu đồ….
optsMảng lưu đầy đủ các thông số cấu hình của Chart, dựa vào đây ta có thể hiệu chỉnh trực tiếp biểu đồ.

Dưới đây là mã lệnh đầy đủ của “MainWindowEx.py“:

from MainWindow import Ui_MainWindow
import pyqtgraph as pg

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        self.setupBarGraph()
    def setupBarGraph(self):
        self.graphWidget = pg.PlotWidget()
        self.graphWidget.setTitle("Lucy Company",
                                  color="r",
                                  size="15pt",
                                  bold=True,
                                  italic=True)
        self.graphWidget.setBackground('w')

        labelStyle = {"color": "green", "font-size": "18px"}
        labelBrandStyle = {"color": "pink", "font-size": "18px"}
        self.graphWidget.setLabel("left", "Revenue (VNĐ)", **labelStyle)
        self.graphWidget.setLabel("bottom", "Quarter (time)", **labelStyle)
        self.graphWidget.setLabel("top", "Revenue Report", **labelStyle)
        self.graphWidget.setLabel("right", "tranduythanh.com", **labelBrandStyle)
        self.graphWidget.showGrid(x=True, y=True)

        width = 0.3

        quarter = [1, 2, 3, 4]
        revenue = [100, 200, 250, 190]

        self.bargraphItem = pg.BarGraphItem(x=quarter, height=revenue, width=width, brush='b', name="ABC Revenue")

        self.legend = self.graphWidget.addLegend()

        self.graphWidget.addItem(self.bargraphItem)
        self.myLayout.addWidget(self.graphWidget)

    def show(self):
        self.MainWindow.show()

Bước 5: Viết mã lệnh “MyApp.py” để thực thi chương trình:

from PyQt6.QtWidgets import QApplication, QMainWindow

from MainWindowEx import MainWindowEx

app=QApplication([])
myWindow=MainWindowEx()
myWindow.setupUi(QMainWindow())
myWindow.show()
app.exec()

Chạy “MyApp.py” ta có kết quả như mong muốn, các biểu đồ cột, các nhãn của các cột, tiêu đề chart… được hiển thị:

Như vậy tới đây Tui đã trình bày xong cách lập trình xử lý trực quan hóa dữ liệu với BarGraph. Các bạn đã biết cách khai báo các mảng tương ứng với các trục, biết cách gọi các hàm liên quan tới BarGraphItem để hiển thị Chart. Cũng như ôn tập lại được toàn bộ kiến thức liên quan tới PlotWidget, một trong các đối tượng quan trọng và thường sử dụng trong trực quan hóa dữ liệu.

Soure code của bài này các bạn tải ở đây:

https://www.mediafire.com/file/tpic3u6bkckjilt/LearnPyQtBarGraphPart3.rar/file

Bài học sau Tui sẽ nâng cấp bài học này bằng cách bổ sung thêm các Widget cho người dùng tương tác, chẳng hạn như:

  • Cung cấp chức năng ẩn hiện Background Grid
  • Cung cấp chức năng ẩn hiện Legend
  • Cung cấp chức năng đổi màu nền của Chart
  • Cung cấp chức năng đổi màu nền của Bar

Các bạn chú ý theo dõi

Chúc các bạn thành công

One thought on “Bài 33: Trực quan hóa dữ liệu – PyQtGraph-BarGraph-PyQt6 – Part 3”

Leave a Reply