Bài 32: Trực quan hóa dữ liệu – PyQtGraph-PlotWidget-PyQt6 – Part 2

Bài học này Tui trình bày chi tiết về đối tượng PlotWidget được đề cập trong PyQtGraph Part 1 mà ta đã dùng để vẽ một Chart đơn giản.

Việc nắm được ý nghĩa và các kỹ thuật sử dụng các phương thức của đối tượng PlotWidget sẽ giúp chúng ta dễ dàng hiệu chỉnh Chart theo nhu cầu:

  1. Thiết lập tiêu đề cho Chart
  2. Thiết lập tiêu đề cho các Trục
  3. Thiết lập màu nền cho Chart
  4. Thiết lập Background Grid
  5. Thiết lập màu, độ rộng và kiểu dáng của đường kẻ
  6. Thiết lập Line Markers
  7. Thiết lập Legends
  8. Thiết lập giới hạn các trục
  9. Thiết lập multiple plot trong một Chart
  10. Xóa và cập nhật Plot

Tui tóm tắt sơ lược ý nghĩa chức năng của một số phương thức của PlotWidget

Phương thứcÝ nghĩa chức năng
setTitle(title)Thiết lập tiêu đề cho Chart
Ví dụ:
self.graphWidget.setTitle(“My Chart Title”)
setTitle(title, color, size)Thiết lập tiêu đề cho Chart cùng với định dạng màu chữ và cỡ chữ.
Ví dụ:
self.graphWidget.setTitle(“My Chart Title”, color=”b”, size=”30pt”)
setLabel(position,text)Thiết lập tiêu đề cho các trục.
position có 4 giá trị: ‘left,’right’,’top’,’bottom’
Ví dụ:
styles = {‘color’:’r’, ‘font-size’:’30pt’}
self.graphWidget.setLabel(‘left’, ‘Temperature (°C)’, **styles)
self.graphWidget.setLabel(‘bottom’, ‘Hour (H)’, **styles)
setBackground(background)Phương thức này dùng để thiết lập màu nền cho Chart.
Ví dụ:
import pyqtgraph as pg
self.graphWidget=pg.PlotWidget()
self.graphWidget.setBackground(“y”)
showGrid(x=True, y=True)Hiển thị lưới cho Chart
plot(X value, Y value,
name=”Plot 1″,
pen=pen, symbol=”+”,
symbolSize=30,
symbolBrush=(“b”),
)
Hàm để vẽ Chart có sử dụng Pen để định dạng đường vẽ như màu đường kẻ, kiểu đường kẻ, độ dày đường kẻ, biểu tượng.
Ví dụ:
pen = pg.mkPen(color=(255, 0, 0))
self.graphWidget.plot(hour, temperature, pen=pen)
addLegend()Hàm hiển thị Legend cho Chart
setXRange(5, 20, padding=0)Thiết lập giới hạn cho trục X
setYRange(30, 40, padding=0)Thiết lập giới hạn cho trục Y
clear()Xóa các plot trên Chart
data_line= graphWidget.plot(x, y)

data_line.setData(new x, new y)
Cập nhật dữ liệu cho Plot

Tui trình bày chi tiết các chức năng dưới này, vừa kết hợp lý thuyết và thực hành, các bạn nhớ thực hiện theo.

Tạo dự án “LearnPyQtGraphPart2” thiết kế giao diện và dữ liệu mẫu giống như bài trước. Bạn có thể copy y chang toàn bộ các file .py, .ui của bài trước vào “LearnPyQtGraphPart2” để sử dụng luôn

  • “MainWindow.ui” là giao diện được thiết kế bằng Qt Designer
  • “MainWindow.py” là generate python code của “MainWindow.ui”
  • “MainWindowEx.py” là file mã lệnh kế thừa từ “MainWindow.py” để xử lý nạp giao diện, gán Chart và các sự kiện, lớp này sẽ không lệ thuộc vào sự thay đổi của giao diện cũng như generate code
  • “MyApp.py” là file mã lệnh thực thi chương trình

Giao diện “MainWindow.ui” và dữ liệu mẫu trong “MainWidowEx.py” là y chang như bài trước nên Tui không chụp hình lại, các bạn tự chuyển qua. Còn dưới đây Tui sẽ lần lượt hướng dẫn từng chức năng cụ thể, các bạn bổ sung vào “MainWindowEx.py“:

1. Thiết lập tiêu đề cho Chart

Ta thiết lập tiêu đề cho Chart bằng hàm setTitle(title)

self.graphWidget.setTitle("Chart Title Here")

Ngoài ra ta có thể định dạng style cho title như màu tiêu đề, cỡ chữ tiêu đề, in đậm, in nghiêng.

StyleCách dùng
color‘CCFF00’ , ‘b’
size’10pt’
boldTrue/False
italicTrue/False
self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt",bold=True,italic=True)

Dưới đây là chi tiết mã lệnh của MainWindowEx.py cho phần tiêu đề:

#Step 1: import pyqtgraph
import pyqtgraph as pg
from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #self.graphWidget.setTitle("Temperature per hour")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt")
        self.graphWidget.setTitle("Temperature per hour", color="b", size="20pt",bold=True,italic=True)
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        # Step 4: call plot method
        self.graphWidget.plot(hour, temperature)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Chạy “MyApp.py” ta có kết quả:

Ngoài ra ta cũng có thể thiết lập title bằng cấu trúc HTML như dưới đây:

self.graphWidget.setTitle("<span style=\"color:blue;font-size:20pt\">Temperature per hour</span>")


2. Thiết lập tiêu đề cho các Trục

Chúng ta dùng hàm setLabel(position,text,style) để thiết lập tiêu đề cho các trục. position có ‘left,’right’,’top’,’bottom’. Ví dụ:

styles = {"color": "#f00", "font-size": "20px"}
self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
self.graphWidget.setLabel("bottom", "Hour (H)", **styles)

Coding đầy đủ của MainWindowEx.py cho phần thiết lập tiêu đề cho các Trục:

#Step 1: import pyqtgraph
import pyqtgraph as pg
from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #self.graphWidget.setTitle("Temperature per hour")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="20pt",bold=True,italic=True)
        self.graphWidget.setTitle("<span style=\"color:blue;font-size:20pt\">Temperature per hour</span>")
        styles = {"color": "#f00", "font-size": "20px"}
        self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
        self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
        styles_top_right = {"color": "green", "font-size": "15px"}
        self.graphWidget.setLabel("top", "Learn PyQtGraph",**styles_top_right)
        self.graphWidget.setLabel("right", "tranduythanh.com",**styles_top_right)
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        # Step 4: call plot method
        self.graphWidget.plot(hour, temperature)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Chạy “MyApp.py” ta có kết quả như dưới đây:

Ở Chart bên trên ta thấy, cả 4 trục đều có tiêu đề.


3. Thiết lập màu nền cho Chart

Bây giờ ta làm quen với phương thức setBackground(). Phương thức đổi thiết lập màu nền có thể nhận các dạng màu sau:

  • Dùng Letter code
ColorLetter Code
blueb
greeng
redr
cyanc
magentam
yellowy
blackk
whitew

Ví dụ lệnh dưới đây thiết lập nền trắng cho Chart:

self.graphWidget.setBackground("w")
  • Dùng hex color

Danh sách Hex Color bạn có thể lấy nhiều nơi, có thể lấy ở đây:

https://www.color-hex.com/

Ví dụ ta thiết lập màu nền Hex Color #ff0000 màu đỏ:

self.graphWidget.setBackground('#ff0000')
  • Sử dụng RGB (Red – Green-Blue) RGBA (Red Green Blue Alpha Opacity)

Khi dùng RGB thì ta dùng bộ 3:

self.graphWidget.setBackground((100,50,255)) # RGB each 0-255

Khi dùng RGBA thì ta dùng bộ 4:

self.graphWidget.setBackground((100,50,255,25)) # RGBA (A = alpha opacity)
  • Ngoài ra ta có thể dùng đối tượng QColor để thiết lập màu
self.graphWidget.setBackground(QColor(50, 168, 82,255)) # R, G, B, A

Mã lệnh đầy đủ của MainWindowEx.py để đổi màu nền của Chart qua màu trắng:

#Step 1: import pyqtgraph
import pyqtgraph as pg
from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #self.graphWidget.setTitle("Temperature per hour")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="20pt",bold=True,italic=True)
        self.graphWidget.setTitle("<span style=\"color:blue;font-size:20pt\">Temperature per hour</span>")
        styles = {"color": "#f00", "font-size": "20px"}
        self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
        self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
        styles_top_right = {"color": "green", "font-size": "15px"}
        self.graphWidget.setLabel("top", "Learn PyQtGraph",**styles_top_right)
        self.graphWidget.setLabel("right", "tranduythanh.com",**styles_top_right)
        self.graphWidget.setBackground("w")
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        # Step 4: call plot method
        self.graphWidget.plot(hour, temperature)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Chạy “MyApp.py” ta có kết quả:


4. Thiết lập Background Grid

Để hiển thị lưới cho Chart ta dùng hàm .showGrid()

self.graphWidget.showGrid(x=True, y=True)

Ta có thể tùy chỉnh trục nào sẽ xuất hiện lưới, mã lệnh ở trên là hiển thị cả trục tung và trục hoành, dưới đây là mã lệnh đầy đủ của MainWindowEx.py:

#Step 1: import pyqtgraph
import pyqtgraph as pg
from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #self.graphWidget.setTitle("Temperature per hour")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="20pt",bold=True,italic=True)
        self.graphWidget.setTitle("<span style=\"color:blue;font-size:20pt\">Temperature per hour</span>")
        styles = {"color": "#f00", "font-size": "20px"}
        self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
        self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
        styles_top_right = {"color": "green", "font-size": "15px"}
        self.graphWidget.setLabel("top", "Learn PyQtGraph",**styles_top_right)
        self.graphWidget.setLabel("right", "tranduythanh.com",**styles_top_right)
        self.graphWidget.setBackground("w")
        self.graphWidget.showGrid(x=True, y=True)
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        # Step 4: call plot method
        self.graphWidget.plot(hour, temperature)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Chạy “MyApp.py” ta có kết quả:


5. Thiết lập màu, độ rộng và kiểu dáng của đường kẻ

  • Bây giờ chúng ta làm quen với đối tượng QPen hiệu chỉnh màu đường kẻ, kiểu đường kẻ, độ dày đường kẻ:
pen = pg.mkPen(color=(255, 0, 0), width=15, style=Qt.PenStyle.DashLine)
self.graphWidget.plot(hour, temperature,pen=pen)

Kiểu của đường kẻ ta dùng như dưới đây:

Enum StyleÝ nghĩa chức năng
Qt.PenStyle.SolidLineVẽ đường liên tục
Qt.PenStyle.DashLineVẽ đường các gạch ngang
Qt.PenStyle.DotLineVẽ đường các chấm
Qt.PenStyle.DashDotLineVẽ đường: Gạch ngang – chấm – gạch ngang
Qt.PenStyle.DashDotDotLineVẽ đường: Gạch ngang – chấm- chấm – gạch ngang

Coding đầy đủ của MainWindowEx.py:

#Step 1: import pyqtgraph
import pyqtgraph as pg
from PyQt6.QtCore import Qt

from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #self.graphWidget.setTitle("Temperature per hour")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="20pt",bold=True,italic=True)
        self.graphWidget.setTitle("<span style=\"color:blue;font-size:20pt\">Temperature per hour</span>")
        styles = {"color": "#f00", "font-size": "20px"}
        self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
        self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
        styles_top_right = {"color": "green", "font-size": "15px"}
        self.graphWidget.setLabel("top", "Learn PyQtGraph",**styles_top_right)
        self.graphWidget.setLabel("right", "tranduythanh.com",**styles_top_right)
        self.graphWidget.setBackground("w")
        self.graphWidget.showGrid(x=True, y=True)
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        # Step 4: call plot method
        pen = pg.mkPen(color=(255, 0, 0), width=15, style=Qt.PenStyle.DashDotLine)
        self.graphWidget.plot(hour, temperature,pen=pen)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Chạy MyApp.py ta có kết quả:


6. Thiết lập Line Markers

Để thiết lập Markers cho các Line plot, ta dùng các thuộc tính sau cho hàm plot() của đối tương PlotWidget:

self.graphWidget.plot(hour, temperature, pen=pen, symbol='+', symbolSize=30, symbolBrush=('b'))
  • symbol: Thiết lập biểu tượng của Marker
SymbolÝ nghĩa
oCircular
sSquare
tTriangular
dDiamond
+Cross
  • symbolSize: Thiết lập độ lớn của Marker
  • symbolBrush: Thiết lập màu của Marker
  • symbolPen: Thiết lập màu đường viên của Marker

Dưới đây là coding minh họa phần Marker trong MainWindowEx.py:

#Step 1: import pyqtgraph
import pyqtgraph as pg
from PyQt6.QtCore import Qt

from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #self.graphWidget.setTitle("Temperature per hour")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="20pt",bold=True,italic=True)
        self.graphWidget.setTitle("<span style=\"color:blue;font-size:20pt\">Temperature per hour</span>")
        styles = {"color": "#f00", "font-size": "20px"}
        self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
        self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
        styles_top_right = {"color": "green", "font-size": "15px"}
        self.graphWidget.setLabel("top", "Learn PyQtGraph",**styles_top_right)
        self.graphWidget.setLabel("right", "tranduythanh.com",**styles_top_right)
        self.graphWidget.setBackground("w")
        self.graphWidget.showGrid(x=True, y=True)
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        # Step 4: call plot method
        pen = pg.mkPen(color=(255, 0, 0), width=15, style=Qt.PenStyle.DotLine)
        symbolPen = pg.mkPen(color=(196, 196, 196), width=2)
        self.graphWidget.plot(hour, temperature, pen=pen,
                              symbol='+',
                              symbolSize=15,
                              symbolBrush=('b'),
                              symbolPen=symbolPen)
        #self.graphWidget.plot(hour, temperature,pen=pen)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Chạy MyApp.py ta có kết quả:

Ta thấy Marker có màu xanh (symbolBrush) và màu viền là xám (symbolPen), biểu tượng + (symbol), kích thước của marker (symbolSize). Ta thử thay thế các symbol khác nhau rồi quan sát so sánh kết quả.


7. Thiết lập Legends

Để thiết lập Legends cho Chart, trước tiên các Line/plot cần được đặt tên khi gọi phương thức plot() của PlotWidget.

Sau đó ta gọi phương thức addLegend() của PlotWidget.

self.graphWidget.addLegend()
self.graphWidget.plot(hour, temperature,name="Sensor X",
                      pen=pen,
                      symbol='+',
                      symbolSize=15,
                      symbolBrush=('b'),
                      symbolPen=symbolPen)

Dưới đây là mã lệnh đầy đủ của MainWindowEx.py để hiển thị Legend:

#Step 1: import pyqtgraph
import pyqtgraph as pg
from PyQt6.QtCore import Qt

from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #self.graphWidget.setTitle("Temperature per hour")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="20pt",bold=True,italic=True)
        self.graphWidget.setTitle("<span style=\"color:blue;font-size:20pt\">Temperature per hour</span>")
        styles = {"color": "#f00", "font-size": "20px"}
        self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
        self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
        styles_top_right = {"color": "green", "font-size": "15px"}
        self.graphWidget.setLabel("top", "Learn PyQtGraph",**styles_top_right)
        self.graphWidget.setLabel("right", "tranduythanh.com",**styles_top_right)
        self.graphWidget.setBackground("w")
        self.graphWidget.showGrid(x=True, y=True)
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        # Step 4: call plot method
        pen = pg.mkPen(color=(255, 0, 0), width=15, style=Qt.PenStyle.DotLine)
        symbolPen = pg.mkPen(color=(196, 196, 196), width=2)
        self.graphWidget.addLegend()
        self.graphWidget.plot(hour, temperature,name="Sensor X",
                              pen=pen,
                              symbol='+',
                              symbolSize=15,
                              symbolBrush=('b'),
                              symbolPen=symbolPen)
        #self.graphWidget.plot(hour, temperature,pen=pen)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Chạy “MyApp.py” ta có kết quả:

Quan sát Chart ta thấy Legen “Sensor X” được hiển thị mặc định ở góc trái bên trên của Chart, ta có thể dùng chuột để di chuyển.


8. Thiết lập giới hạn các trục

Đôi khi trong quá trình trực quan hóa dữ liệu, chúng ta cần thiết phải giới hạn hiển thị dữ liệu ở các trục.

Ta dùng hàm setXRange(min, max,padding) và setYRange(min,max,padding) để giới hạn

Ví dụ:

self.graphWidget.setXRange(1, 8, padding=0)
self.graphWidget.setYRange(10, 80, padding=0)

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

#Step 1: import pyqtgraph
import pyqtgraph as pg
from PyQt6.QtCore import Qt

from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #self.graphWidget.setTitle("Temperature per hour")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="20pt",bold=True,italic=True)
        self.graphWidget.setTitle("<span style=\"color:blue;font-size:20pt\">Temperature per hour</span>")
        styles = {"color": "#f00", "font-size": "20px"}
        self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
        self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
        styles_top_right = {"color": "green", "font-size": "15px"}
        self.graphWidget.setLabel("top", "Learn PyQtGraph",**styles_top_right)
        self.graphWidget.setLabel("right", "tranduythanh.com",**styles_top_right)
        self.graphWidget.setBackground("w")
        self.graphWidget.showGrid(x=True, y=True)
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        # Step 4: call plot method
        pen = pg.mkPen(color=(255, 0, 0), width=15, style=Qt.PenStyle.DotLine)
        symbolPen = pg.mkPen(color=(196, 196, 196), width=2)
        self.graphWidget.addLegend()
        self.graphWidget.setXRange(1, 8, padding=0)
        self.graphWidget.setYRange(10, 80, padding=0)
        self.graphWidget.plot(hour, temperature,name="Sensor X",
                              pen=pen,
                              symbol='+',
                              symbolSize=15,
                              symbolBrush=('b'),
                              symbolPen=symbolPen)
        #self.graphWidget.plot(hour, temperature,pen=pen)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Chạy MyApp.py ta có kết quả:


9. Thiết lập multiple plot trong một Chart

Thông thường khi vẽ chart ta hay kết hợp nhiều plot để hiển thị, so sánh…. PyQtGraph cũng hỗ trợ đặc tính này:

hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
temperature2 = [25, 18, 30,10, 47, 29, 26, 32, 35, 45, 40, 42]

pen = pg.mkPen(color=(255, 0, 0), width=15, style=Qt.PenStyle.DotLine)
pen2 = pg.mkPen(color=(0, 0, 255), width=8, style=Qt.PenStyle.SolidLine)

symbolPen = pg.mkPen(color=(196, 196, 196), width=2)
symbolPen2 = pg.mkPen(color=(255, 255, 0), width=2)


self.graphWidget.plot(hour, temperature,name="Sensor X",
                      pen=pen,
                      symbol='+',
                      symbolSize=15,
                      symbolBrush=('b'),
                      symbolPen=symbolPen)

self.graphWidget.plot(hour, temperature2, name="Sensor Y",
                      pen=pen2,
                      symbol='d',
                      symbolSize=8,
                      symbolBrush=('r'),
                      symbolPen=symbolPen2)

Mã lệnh ở trên các bạn quan sát Tui bổ sung thêm các biến:

  • temperature2: lưu trữ mảng nhiệt độ mới cho Sensor Y
  • pen2: thiết lập đường kẻ thứ 2
  • symbolPen2: thiết lập biểu tượng cho đường kẻ thứ 2

Và Ta gọi 2 lần hàm plot() của đối tượng PlotWidget (biến graphWidget)

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

#Step 1: import pyqtgraph
import pyqtgraph as pg
from PyQt6.QtCore import Qt

from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #self.graphWidget.setTitle("Temperature per hour")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="20pt",bold=True,italic=True)
        self.graphWidget.setTitle("<span style=\"color:blue;font-size:20pt\">Temperature per hour</span>")
        styles = {"color": "#f00", "font-size": "20px"}
        self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
        self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
        styles_top_right = {"color": "green", "font-size": "15px"}
        self.graphWidget.setLabel("top", "Learn PyQtGraph",**styles_top_right)
        self.graphWidget.setLabel("right", "tranduythanh.com",**styles_top_right)
        self.graphWidget.setBackground("w")
        self.graphWidget.showGrid(x=True, y=True)
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        temperature2 = [25, 18, 30,10, 47, 29, 26, 32, 35, 45, 40, 42]
        # Step 4: call plot method
        pen = pg.mkPen(color=(255, 0, 0), width=15, style=Qt.PenStyle.DotLine)
        pen2 = pg.mkPen(color=(0, 0, 255), width=8, style=Qt.PenStyle.SolidLine)
        symbolPen = pg.mkPen(color=(196, 196, 196), width=2)
        symbolPen2 = pg.mkPen(color=(255, 255, 0), width=2)
        self.graphWidget.addLegend()
        #self.graphWidget.setXRange(1, 8, padding=0)
        #self.graphWidget.setYRange(10, 80, padding=0)
        self.graphWidget.plot(hour, temperature,name="Sensor X",
                              pen=pen,
                              symbol='+',
                              symbolSize=15,
                              symbolBrush=('b'),
                              symbolPen=symbolPen)
        self.graphWidget.plot(hour, temperature2, name="Sensor Y",
                              pen=pen2,
                              symbol='d',
                              symbolSize=8,
                              symbolBrush=('r'),
                              symbolPen=symbolPen2)
        #self.graphWidget.plot(hour, temperature,pen=pen)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Chạy “MyApp.py” ta có kết quả:

Ta có thể ẩn/hiển thị các Plot bằng cách nhấn vào Legend, ví dụ như muốn ẩn Sensor Y:

Ta có thể áp dụng kỹ thuật của Multiple Line để tự động nạp nhiều Plot cho 1 Chart. Ví dụ như hãy vẽ biểu đồ doanh thu từng tháng của 10 chi nhánh trong năm 2023.


10. Xóa và cập nhật Plot

Để xóa Plot trên Chart ta gọi lệnh:

self.graphWidget.clear()

Trong quá trình hiển thị Chart, đặc biệt là liên quan tới Realtime data thì rõ ràng ta muốn Chart được cập nhật tự động.

Bước 1: Khai báo đối tượng lưu trữ lại Plot, ví dụ ta khai báo plot 2 cho Sensor Y

plot2=self.graphWidget.plot(hour, temperature2, name="Sensor Y",
                              pen=pen2,
                              symbol='d',
                              symbolSize=8,
                              symbolBrush=('r'),
                              symbolPen=symbolPen2)

Bước 2: Thay đổi giá trị trong mảng temperature2, ví dụ:

temperature2[3]=100

Ở bước 2 này tức là nếu trong quá trình vận hành trực quan hóa, mà bất cứ khi nào đó mảng dữ liệu bị thay đổi. Ở đây là Tui minh họa 1 trường hợp phần tử thứ 3 bị đổi dữ liệu

Bước 3: Gọi hàm setData() của plot2 để cập nhật Plot

plot2.setData(hour, temperature2)

Code đầy đủ của MainWindowEx.py cho phần cập nhật Plot:

#Step 1: import pyqtgraph
import pyqtgraph as pg
from PyQt6.QtCore import Qt

from MainWindow import Ui_MainWindow

class MainWindowEx(Ui_MainWindow):
    def __init__(self):
        super().__init__()
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #self.graphWidget.setTitle("Temperature per hour")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="30pt")
        #self.graphWidget.setTitle("Temperature per hour", color="b", size="20pt",bold=True,italic=True)
        self.graphWidget.setTitle("<span style=\"color:blue;font-size:20pt\">Temperature per hour</span>")
        styles = {"color": "#f00", "font-size": "20px"}
        self.graphWidget.setLabel("left", "Temperature (°C)", **styles)
        self.graphWidget.setLabel("bottom", "Hour (H)", **styles)
        styles_top_right = {"color": "green", "font-size": "15px"}
        self.graphWidget.setLabel("top", "Learn PyQtGraph",**styles_top_right)
        self.graphWidget.setLabel("right", "tranduythanh.com",**styles_top_right)
        self.graphWidget.setBackground("w")
        self.graphWidget.showGrid(x=True, y=True)
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        temperature2 = [25, 18, 30,10, 47, 29, 26, 32, 35, 45, 40, 42]
        # Step 4: call plot method
        pen = pg.mkPen(color=(255, 0, 0), width=15, style=Qt.PenStyle.DotLine)
        pen2 = pg.mkPen(color=(0, 0, 255), width=8, style=Qt.PenStyle.SolidLine)
        symbolPen = pg.mkPen(color=(196, 196, 196), width=2)
        symbolPen2 = pg.mkPen(color=(255, 255, 0), width=2)
        self.graphWidget.addLegend()
        #self.graphWidget.setXRange(1, 8, padding=0)
        #self.graphWidget.setYRange(10, 80, padding=0)
        self.graphWidget.plot(hour, temperature,name="Sensor X",
                              pen=pen,
                              symbol='+',
                              symbolSize=15,
                              symbolBrush=('b'),
                              symbolPen=symbolPen)
        plot2=self.graphWidget.plot(hour, temperature2, name="Sensor Y",
                              pen=pen2,
                              symbol='d',
                              symbolSize=8,
                              symbolBrush=('r'),
                              symbolPen=symbolPen2)
        temperature2[3]=100
        plot2.setData(hour, temperature2)
        #self.graphWidget.plot(hour, temperature,pen=pen)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Chạy MyApp.py ta thấy temperature2[3]=100 được update.

Dựa vào tính năng nay ta có thể viết code tự động update dữ liệu theo thời gian.

Như vậy tới Tui đã hướng dẫn đầy đủ và chi tiết các chức năng quan trọng và thường dùng của PlotWidget trong trực quan hóa dữ liệu. Các bạn chú ý làm lại nhiều lần và hiểu thật rõ, áp dụng thật tốt từng kỹ thuật để giúp cho trực quan hóa được tốt nhất.

Các bạn tải mã lệnh đầy đủ của dự án ở đây:

https://www.mediafire.com/file/7s7lkzsmsoyufy0/LearnPyQtGraphPart2.rar/file

Bài học sau Tui sẽ minh họa cách sử dụng PyQtGraph và OpenGL để hiển thị 3D Graph, các bạn chú ý theo dõi

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

Bài 31: Trực quan hóa dữ liệu – PyQtGraph-PlotWidget-PyQt6 – Part 1

PyQt6 cung cấp gói thư viện PyQtGraph, QGraphicScene để trực quan hóa dữ liệu dưới dạng biểu đồ một cách hiệu quả. Đặc biệt đối với Live Data, cũng như cung cấp khả năng tương tác và khả năng dễ dàng tùy chỉnh các loại biểu đồ bằng các tiện ích đồ họa trong Qt.

Bài học này Chúng ta sẽ tìm hiểu cách tải thư viện và vẽ một chart đơn giản bằng PyQtGraph. Bài học sau Tui sẽ trình bày chi tiết các thành phần bên trong PyQtGraph, và hướng dẫn cách customize màu đường kẻ, loại đường kẻ, các tiêu đề của các trục, màu nền, cũng như cách vẽ nhiều biểu đồ trong cùng một màn hình.

Ta tiến hành từng bước như hướng dẫn dưới đây.

Bước 1: Cài đặt PyQtGraph bằng lệnh dưới đây:

pip install git+https://github.com/pyqtgraph/pyqtgraph@master

Mở command line để thực hiện câu lệnh trên:

Bước 2: Tạo một dự án tên “LearnPyQtGraphPart1” trong Pycharm. Thiết kế giao diện và tạo các lớp cho dự án có cấu trúc như dưới đây:

  • “MainWindow.ui” là giao diện được thiết kế bằng Qt Designer
  • “MainWindow.py” là generate python code của “MainWindow.ui”
  • “MainWindowEx.py” là file mã lệnh kế thừa từ “MainWindow.py” để xử lý nạp giao diện, gán Chart và các sự kiện, lớp này sẽ không lệ thuộc vào sự thay đổi của giao diện cũng như generate code
  • “MyApp.py” là file mã lệnh thực thi chương trình

Bước 3: Thiết kế Giao diện “MainWindow.ui” như dưới đây

Trong giao diện ta chỉ cần kéo một QVBoxLayout vào MainWindow và đặt tên là “myLayout

Bước 4: Generate Python code “MainWindow.py” cho “MainWindow.ui”

# Form implementation generated from reading ui file 'MainWindow.ui'
#
# Created by: PyQt6 UI code generator 6.4.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(441, 322)
        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, 441, 26))
        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 - PyQtGraph"))

Bước 5: Viết lớp python kế thừa trong “MainWindowEx.py

from MainWindow import Ui_MainWindow
#Step 1: import pyqtgraph
import pyqtgraph as pg

class MainWindowEx(Ui_MainWindow):
    def setupUi(self, MainWindow):
        super().setupUi(MainWindow)
        self.MainWindow=MainWindow
        #Step 2: call pg.PlotWidget()
        self.graphWidget = pg.PlotWidget()
        #Step 3: Create plot data
        hour = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,12]
        temperature = [20, 21, 20, 32, 33, 31, 29,31, 32, 35,37, 45]
        #Step 4: call plot method
        self.graphWidget.plot(hour, temperature)
        #Step 5: add graphWidget into Layout:
        self.myLayout.addWidget(self.graphWidget)
    def show(self):
        self.MainWindow.show()

Trong bước 5 ta có một số bước nhỏ để tạo Chart bằng PyQtGraph. Chúng ta làm theo các ghi chú mà Tui để ở trong code.

  • Bước 5.1: Khai báo thư viện PyQtGraph và đặt lại tên thư viện pg (ta có thể đặt tên khác hoặc không đặt)
  • Bước 5.2: Tạo đối tượng PlotWidget bằng cách gọi pg.PlotWidget() và lưu đối tượng này vào biến graphWidget
  • Bước 5.3: Khai báo 2 mảng dữ liệu cho hour temperature, 2 mảng này phải cùng số lượng phần tử
  • Bước 5.4: Gọi phương thức plot(hour,temperature) của đối tượng graphWidget
  • Bước 5.5: Đưa đối tượng graphWidget vào layout

Bước 6: Viết “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 chương trình MyApp.py ta có Chart như dưới đây:

Ta thấy trục Temperature hiển thị: 20, 25, 30, 35, 40, 45

Trục Hour, hiển thị: 2, 4, 6, 8, 10, 12

Bạn thực hành lại bài này để hiểu được cách sử dụng thư viện PyQtGraph một cách đơn giản nhất nhé. Khoan hãy đi vào chi tiết, chỉ cần biết cách gọi và sử dụng thư viện này để hiển thị Chart là thành công.

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

https://www.mediafire.com/file/ckrg97s6xul5jrr/LearnPyQtGraphPart1.rar/file

Bài học sau Tui sẽ trình bày chi tiết các thành phần bên trong PyQtGraph, và hướng dẫn cách customize màu đường kẻ, loại đường kẻ, các tiêu đề của các trục, màu nền, cũng như cách vẽ nhiều biểu đồ trong cùng một màn hình. Các bạn chú ý theo dõi.

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