如何在PyQtGraph中重构自动缩放按钮至默认位置并自定义缩放范围
在PyQtGraph子图左下角添加自定义缩放按钮
问题描述
需要在PyQtGraph每个子图的左下角(默认'A'按钮所在位置)添加一个自定义自动缩放按钮,点击后缩放到特定坐标范围(显示比所有数据点更大的区域)。但直接通过QGraphicsProxyWidget添加按钮时,位置受坐标轴刻度影响,无法固定在默认按钮区域,且会处于绘图区域内部。
解决方案
PyQtGraph的PlotItem自带控制按钮布局ctrlLayout,默认的'A'、'Pan'等按钮都放在这个布局里。直接将自定义按钮添加到该布局中,就能和默认按钮保持相同的固定位置,不受坐标轴变化影响。
关键修改点
- 放弃使用
QGraphicsProxyWidget将按钮添加到绘图场景,转而获取PlotItem的ctrlLayout - 创建自定义按钮并绑定点击事件,将其添加到
ctrlLayout的左侧(与'A'按钮同区域)
按钮添加代码示例
在创建子图的循环中,替换原按钮添加逻辑为:
# 创建自定义缩放按钮 auto_button = QtWidgets.QPushButton(f"Auto {i+1}") auto_button.setFixedSize(60, 20) # 按需调整尺寸 # 绑定点击事件,传入当前子图和自定义范围 auto_button.clicked.connect( lambda _, p=plot, i=i: self.set_custom_range( p, xmin=self.xlim[i][0], xmax=self.xlim[i][1], ymin=self.ylim[i][0], ymax=self.ylim[i][1] ) ) # 将按钮加入子图的控制布局 plot.ctrlLayout.addWidget(auto_button, 0, 0) # 0行0列,与默认'A'按钮同位置区域
完整修改后的代码
import sys import random import time import multiprocessing import numpy as np from PyQt5 import QtWidgets, QtCore import pyqtgraph as pg class StockPriceUpdater(multiprocessing.Process): def __init__(self, pipe, stock_name, prices): super().__init__() self.pipe = pipe self.stock_name = stock_name self.prices = prices def run(self): while True: new_price = self.prices[-1] + random.uniform(-0.5, 0.5) self.prices = np.append(self.prices, new_price) self.pipe.send((self.stock_name, self.prices.copy())) time.sleep(10) class StockPriceApp(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.initUI() self.setup_multiprocessing() def initUI(self): self.setWindowTitle('Stock Prices') central_widget = QtWidgets.QWidget() self.setCentralWidget(central_widget) layout = QtWidgets.QVBoxLayout(central_widget) self.graph_layout = pg.GraphicsLayoutWidget() layout.addWidget(self.graph_layout) self.plots = [] self.curves = [] self.xdata = [np.arange(10)] * 4 self.ylim = {} self.xlim = {} self.ini_ydata = {} for i in range(4): plot = self.graph_layout.addPlot(row=i//2, col=i%2, title=f'Stock {i+1}') prices = 10 + np.cumsum(np.random.uniform(-0.5, 0.5, 10)) self.update_axis_limits(plot, i, self.xdata[i], prices) self.ini_ydata[i] = prices curve = plot.plot(self.xdata[i], prices, pen='y') # 添加自定义缩放按钮到控制布局 auto_button = QtWidgets.QPushButton(f"Auto {i+1}") auto_button.setFixedSize(60, 20) auto_button.clicked.connect( lambda _, p=plot, i=i: self.set_custom_range( p, xmin=self.xlim[i][0], xmax=self.xlim[i][1], ymin=self.ylim[i][0], ymax=self.ylim[i][1] ) ) plot.ctrlLayout.addWidget(auto_button, 0, 0) self.plots.append(plot) self.curves.append(curve) self.timer = QtCore.QTimer() self.timer.timeout.connect(self.update_plots) self.timer.start(1000) def setup_multiprocessing(self): self.pipes = {} self.processes = {} for i in range(4): stock_name = f'Stock{i+1}' parent_pipe, child_pipe = multiprocessing.Pipe() self.pipes[stock_name] = parent_pipe process = StockPriceUpdater(child_pipe, stock_name, self.ini_ydata[i]) process.start() self.processes[stock_name] = process def update_plots(self): for i, (stock_name, pipe) in enumerate(self.pipes.items()): if pipe.poll(): _, prices = pipe.recv() self.xdata[i] = np.append(self.xdata[i], self.xdata[i][-1] + 1) self.curves[i].setData(self.xdata[i], prices) self.update_axis_limits(self.plots[i], i, self.xdata[i], prices) def set_custom_range(self, plot, x_min, x_max, y_min, y_max): plot.getViewBox().setRange(xRange=[x_min, x_max], yRange=[y_min, y_max]) def update_axis_limits(self, plot, stock, xvals, yvals): xmin = xvals.min() xmax = xvals.max() offset = (xmax - xmin) / 3 xmax = xmax + offset if isinstance(yvals, list): yvals = np.array(yvals) ymin = yvals.min() ymax = yvals.max() offset = (ymax - ymin) / 10 ymax = ymax + offset ymin = ymin - offset self.ylim[stock] = (ymin, ymax) self.xlim[stock] = (xmin, xmax) plot.getViewBox().setRange(xRange=[xmin, xmax], yRange=[ymin, ymax], padding=0) def closeEvent(self, event): for process in self.processes.values(): process.terminate() event.accept() def main(): app = QtWidgets.QApplication(sys.argv) stock_app = StockPriceApp() stock_app.show() sys.exit(app.exec_()) if __name__ == '__main__': main()
说明
- 自定义按钮会固定在子图左下角的控制按钮区域,与默认'A'按钮处于同一布局,不受坐标轴刻度变化影响
- 点击按钮后会调用
set_custom_range方法,使用预先计算的xlim和ylim范围完成缩放 - 可根据需求调整按钮的尺寸、文本,适配界面风格
内容的提问来源于stack exchange,提问作者Xerium
相关产品推荐
相关产品推荐

