PyQt5主界面嵌入Matplotlib图表及树莓派串口数据绘图求助
Got it, let's tackle your two main needs: embedding Matplotlib charts directly into your PyQt5 main window (instead of popping up separate windows) and setting up real-time plotting from serial data on your Raspberry Pi. Here's a step-by-step fix with updated code:
1. Fixing Matplotlib Embedding in PyQt5
Your current code uses global plt functions that spawn standalone windows. To embed the chart into your main UI, we'll use Matplotlib's Qt-compatible canvas component.
First, add these required imports:
import matplotlib.pyplot as plt from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas from matplotlib.figure import Figure
Then update your ApplicationWindow class. Note: You'll need to add a QWidget (or QFrame) to your Qt Designer UI (name it widget_graph) to act as the chart container.
class ApplicationWindow(QtWidgets.QMainWindow): def __init__(self): super(ApplicationWindow, self).__init__() self.ui = Ui_Form() self.ui.setupUi(self) # Initialize Matplotlib figure and canvas self.figure = Figure(figsize=(5, 4), dpi=100) self.canvas = FigureCanvas(self.figure) # Attach canvas to your UI's widget container layout = QtWidgets.QVBoxLayout(self.ui.widget_graph) layout.addWidget(self.canvas) # Connect button to data load function self.ui.pushButtonGraph.clicked.connect(self.load_Data) def load_Data(self): # Clear previous plot for clean updates self.figure.clear() # Create an axes object from the figure ax = self.figure.add_subplot(111) # Your sample data x = [2, 4, 6, 8, 10] y = [6, 7, 8, 2, 10] # Plot on the embedded axes ax.bar(x, y, label='Bar 1') ax.set_xlabel('x') ax.set_ylabel('y') ax.set_title('Graph test') ax.legend() # Refresh the canvas to show the new plot self.canvas.draw()
This replaces the standalone plt.show() with a canvas that's directly integrated into your main interface.
2. Adding Serial Data Plotting for Raspberry Pi
To read serial data without freezing your PyQt5 UI, we'll use a QThread (separate thread for serial reading) to avoid blocking the main UI thread.
First, install pyserial if you haven't:
pip install pyserial
Add these additional imports:
import serial from PyQt5.QtCore import QThread, pyqtSignal
Then add a serial thread class and update your main window for real-time plotting:
class SerialThread(QThread): # Signal to send parsed data back to the main thread data_received = pyqtSignal(float) def __init__(self, port='/dev/ttyUSB0', baud_rate=9600): super().__init__() self.port = port self.baud_rate = baud_rate self.running = True def run(self): # Open serial port (adjust port for your Raspberry Pi setup) try: ser = serial.Serial(self.port, self.baud_rate, timeout=1) while self.running: # Read and parse serial data (adjust parsing logic as needed) line = ser.readline().decode('utf-8').strip() if line: try: data = float(line) self.data_received.emit(data) except ValueError: print(f"Invalid data received: {line}") ser.close() except serial.SerialException as e: print(f"Serial connection error: {e}") def stop(self): self.running = False # Updated ApplicationWindow with serial plotting support class ApplicationWindow(QtWidgets.QMainWindow): def __init__(self): super(ApplicationWindow, self).__init__() self.ui = Ui_Form() self.ui.setupUi(self) # Initialize Matplotlib components for real-time plotting self.figure = Figure(figsize=(5, 4), dpi=100) self.canvas = FigureCanvas(self.figure) self.ax = self.figure.add_subplot(111) self.ax.set_xlabel('Time') self.ax.set_ylabel('Serial Data') self.ax.set_title('Real-Time Serial Plot') # Attach canvas to UI container layout = QtWidgets.QVBoxLayout(self.ui.widget_graph) layout.addWidget(self.canvas) # Initialize serial thread and data storage self.serial_thread = SerialThread(port='/dev/ttyUSB0') # Adjust port here! self.serial_thread.data_received.connect(self.update_plot) self.x_data = [] self.y_data = [] self.time_counter = 0 # Connect start/stop buttons (add these buttons to your UI first) self.ui.pushButtonStartSerial.clicked.connect(self.start_serial) self.ui.pushButtonStopSerial.clicked.connect(self.stop_serial) def start_serial(self): self.serial_thread.start() print("Serial plotting started") def stop_serial(self): self.serial_thread.stop() self.serial_thread.wait() print("Serial plotting stopped") def update_plot(self, new_data): # Update data lists self.time_counter += 1 self.x_data.append(self.time_counter) self.y_data.append(new_data) # Keep plot clean by limiting data points (optional) if len(self.x_data) > 50: self.x_data.pop(0) self.y_data.pop(0) # Redraw the plot with new data self.ax.clear() self.ax.plot(self.x_data, self.y_data, 'b-', label='Serial Data') self.ax.set_xlabel('Time') self.ax.set_ylabel('Serial Data') self.ax.set_title('Real-Time Serial Plot') self.ax.legend() self.canvas.draw()
Raspberry Pi Specific Notes:
- Adjust the serial port (
/dev/ttyUSB0or/dev/ttyAMA0depending on your hardware setup) - Grant serial port permissions to your user:
sudo usermod -a -G dialout $USER(log out and back in after this) - Modify the data parsing logic if your serial output isn't a single float (e.g., handle comma-separated values)
内容的提问来源于stack exchange,提问作者Chanuka Gayantha

