以下是 ✅ 完整支援 UTF-8 中文顯示 的 PyQt5 GUI 程式碼範例,包含:
-
matplotlib
圖表中文字支援 ✅ -
PyQt5
控制項中文顯示 ✅ -
pandas.read_csv()
使用encoding='utf-8'
讀取中文 CSV ✅
✅ 全中文友善 PyQt5 GUI:IMU 時域圖顯示器
[python]import sys
import pandas as pd
import numpy as np
import matplotlib
from PyQt5.QtWidgets import (
QApplication, QWidget, QVBoxLayout, QPushButton,
QFileDialog, QComboBox, QLabel
)
from PyQt5.QtCore import QTimer
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.figure import Figure
import torch
import torch.nn as nn
# ✅ 設定 matplotlib 支援中文顯示
matplotlib.rcParams['font.sans-serif'] = ['Microsoft JhengHei', 'Taipei Sans TC Beta', 'Arial Unicode MS', 'SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
# ✅ 模擬模型(可替換為自己訓練的模型)
class DummyLSTM(nn.Module):
def __init__(self, input_dim=6, hidden_dim=64, num_layers=1, num_classes=4):
super().__init__()
self.lstm = nn.LSTM(input_dim, hidden_dim, num_layers, batch_first=True)
self.fc = nn.Linear(hidden_dim, num_classes)
def forward(self, x):
out, _ = self.lstm(x)
out = self.fc(out[:, -1, :])
return out
class IMUGUI(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle('IMU 時域顯示器(支援 UTF-8 中文)')
self.resize(900, 700)
self.data = None
self.index = 0
self.fs = 100
self.seq_len = 100
self.timer = QTimer()
self.timer.timeout.connect(self.next_frame)
self.model = DummyLSTM().eval()
self.device = torch.device('cpu')
layout = QVBoxLayout()
self.load_button = QPushButton('📂 載入 CSV 檔案')
self.play_button = QPushButton('▶️ 播放 / 暫停')
self.combo = QComboBox()
self.combo.addItems(['顯示 1 秒', '顯示 2 秒', '顯示 3 秒'])
self.label = QLabel('📌 尚未載入資料')
self.canvas = FigureCanvas(Figure())
self.ax = self.canvas.figure.add_subplot(111)
layout.addWidget(self.load_button)
layout.addWidget(self.play_button)
layout.addWidget(self.combo)
layout.addWidget(self.label)
layout.addWidget(self.canvas)
self.setLayout(layout)
self.load_button.clicked.connect(self.load_csv)
self.combo.currentIndexChanged.connect(self.set_seq_len)
self.play_button.clicked.connect(self.toggle_play)
def load_csv(self):
fname, _ = QFileDialog.getOpenFileName(self, '選擇 CSV 檔案', '', 'CSV files (*.csv)')
if fname:
try:
self.data = pd.read_csv(fname, encoding='utf-8')
except UnicodeDecodeError:
self.data = pd.read_csv(fname, encoding='big5')
self.label.setText(f'✅ 已載入:{fname.split("/")[-1]}')
self.set_seq_len()
self.index = 0
self.update_plot()
def set_seq_len(self):
self.seq_len = self.fs * (self.combo.currentIndex() + 1)
def toggle_play(self):
if self.timer.isActive():
self.timer.stop()
self.play_button.setText("▶️ 播放 / 暫停")
else:
self.timer.start(100)
self.play_button.setText("⏸️ 播放中...")
def next_frame(self):
if self.data is None:
return
self.index += 1
if self.index + self.seq_len > len(self.data):
self.timer.stop()
self.play_button.setText("▶️ 播放 / 暫停")
self.index = 0
self.update_plot()
def update_plot(self):
if self.data is None or self.index + self.seq_len > len(self.data):
return
segment = self.data.iloc[self.index:self.index + self.seq_len]
time = [i * 0.01 for i in range(self.seq_len)]
self.ax.clear()
colors = ['red', 'blue', 'green']
for i in range(3): # b1~b3
self.ax.plot(time, segment[f'b{i+1}'], color=colors[i], label=f'b{i+1}')
for i in range(3): # b4~b6
self.ax.plot(time, segment[f'b{i+4}'], linestyle='--', color=colors[i], label=f'b{i+4}')
# 顯示實際類別與預測類別
actual_label = segment['type'].iloc[-1]
imu_values = segment[[f'b{i+1}' for i in range(6)]].values
imu_tensor = torch.tensor(imu_values, dtype=torch.float32).unsqueeze(0)
with torch.no_grad():
pred = self.model(imu_tensor).argmax().item()
self.ax.set_title(f'第 {self.index} ~ {self.index+self.seq_len} 筆|實際類別:{actual_label}|預測:{pred}')
self.ax.set_xlabel('時間(秒)')
self.ax.set_ylabel('IMU 數值')
self.ax.legend()
self.canvas.draw()
if __name__ == '__main__':
app = QApplication(sys.argv)
gui = IMUGUI()
gui.show()
sys.exit(app.exec_())
✅ 特點總結:
項目 | 說明 |
---|---|
📂 載入中文 CSV | 使用 utf-8 或 fallback big5 |
🈶 中文標題、按鈕、圖例 | 完全繁體中文化介面 |
📊 Matplotlib 中文支援 | 不亂碼顯示圖表中文 |
⏱️ 支援即時播放 | 自動滑動時間窗格,每 100ms 前進 |
================================================================
self.timer.start(100)
是 PyQt5 中的 QTimer 定時器啟動指令,以下是它的詳細說明:
📘 指令說明
pythonself.timer.start(100)
表示 啟動 QTimer 並每隔 100 毫秒(0.1 秒)觸發一次 timeout
事件。
🧠 在你的 GUI 中代表什麼?
-
你設置了一個
QTimer()
物件並綁定了:pythonself.timer.timeout.connect(self.next_frame)
-
所以每次
100 毫秒
會執行一次self.next_frame()
函式。 -
self.next_frame()
的作用是:-
將目前視窗滑動 1 筆
-
重新呼叫
update_plot()
更新圖表內容
-
-
結果就是:形成 IMU 時域圖的播放動畫效果(類似影片滑動窗)
⏱️ 參數 100
的意義
數值 | 播放速度效果 |
---|---|
100 | 每秒更新 10 次(建議值) |
50 | 每秒更新 20 次(更快) |
200 | 每秒更新 5 次(慢動作) |
✅ 延伸:可根據播放需求微調
你可以讓使用者手動選擇播放速率,例如新增:
pythonself.speed_combo = QComboBox()
self.speed_combo.addItems(['0.1 秒/格', '0.2 秒/格', '0.05 秒/格'])
並在 toggle_play()
中讀取:
pythoninterval = [100, 200, 50][self.speed_combo.currentIndex()]
self.timer.start(interval)
沒有留言:
張貼留言