使用pyat和pyqtgraph实现根据鼠标选择内容进行实时图像绘制
1.效果
根据鼠标选择内容,图像动态变化。本文选的是条形图。
2.程序组成
此示例程序涉及到3个界面。
一是图像展示界面,使用的是pyqtgraph库实现。
二是数据界面,用QTableWidget展示数据区域。
三是主界面,组织数据展示界面和图像暂时界面,并且起一个数据传输的作用。
3.程序解析
先来理一下逻辑,要实现根据鼠标选择范围动态绘制图像。首先要捕捉鼠标选择的数据范围,其次传输数据到绘图界面,最后更新图像。我在实现这个效果的时候,网上没有找到直接的示范,东拼西凑找了一些代码,幸运的是,最后顺利完成。
3.1鼠标选择范围捕捉
itemSelectionChanged信号
使用itemSelectionChanged信号触发,并绑定到槽函数handleCellChanged。简单来说,把clicked换成itemSelectionChanged。
selectedIndexes()方法
槽函数handleCellChanged中,要使用到一个很重要的方法selectedIndexes(),这个方法会返回一个选择区域。对这个选择区域进行遍历,可以通过遍历项的row()和column()方法获取遍历项的行索引和列索引。这样我们就可以获得所有选择单元格的索引,有了索引就能获取到数据。
数据整理
获取数据之后,接着就有一个问题,我们现在获取的是一个区域中的数据,比如说这个区域是2列乘6行的一个区域。这里画的是条形图,条形图的数据一组一组的的,这里我把一列做为一组。那就需要对这个数据进行整理,根据索引分成两列数据,我用了一个二维列表来存,一个子列表表示一组数据。
3.2数据传递
数据整理好了,需要传给条形图进行绘制。这里用的pyqt自定义信号机制,网上资料很多,不再介绍。
3.3图像更新
数据传过来了,一切当然是水到渠成!!pyqtgraph的绘图方法和与pyqt结合不在此介绍,事实上,你换成matplotlib库也可以。
完整代码
import numpy as np
import pyqtgraph as pg
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QTableWidget, QTableWidgetItem, QHBoxLayout, QWidget
from PyQt5.QtCore import pyqtSignal
class CtxPlotBar(QMainWindow):
def __init__(self):
super().__init__()
self.plot_bar()
def plot_bar(self, plot_data=None):
if plot_data is None:
plot_data = [[1, 2, 3, 4, 5, 6, 7, 8, 9]]
self.setWindowTitle('条形图')
view = pg.GraphicsLayoutWidget()
self.w1 = view.addPlot()
# 单组数据即可,x为横坐标
x = np.arange(len(plot_data[0]))
bar_count = 0
for item in plot_data:
y = []
for value in item:
y.append(value)
bg = pg.BarGraphItem(x=x + bar_count, height=y, width=0.3, brush='r')
self.w1.addItem(bg)
bar_count += 0.33
self.setCentralWidget(view)
class TableUi(QMainWindow):
# 自定义信号
plot_signal = pyqtSignal(list)
def __init__(self):
super().__init__()
self.resize(400, 400)
self.initUI()
def initUI(self):
self.tableWidget = QTableWidget(self)
self.tableWidget.itemSelectionChanged.connect(self.handleCellChanged)
self.setCentralWidget(self.tableWidget)
self.tableWidget.setRowCount(30)
self.tableWidget.setColumnCount(6)
self.data = [[1, 2, 3, 1, 2, 3], [4, 5, 6, 1, 2, 3], [7, 8, 9, 1, 2, 3], [1, 2, 3, 1, 2, 3], [4, 5, 6, 1, 2, 3],
[7, 8, 9, 1, 2, 3], [1, 2, 3, 1, 2, 3], [4, 5, 6, 1, 2, 3], [7, 8, 9, 1, 2, 3]]
# 读取数据并显示在表格中
for i in range(len(self.data)):
for j in range(len(self.data[0])):
item = QTableWidgetItem(str(self.data[i][j]))
self.tableWidget.setItem(i, j, item)
def handleCellChanged(self):
row_list = []
column_list = []
plot_data = []
select_area = self.tableWidget.selectedIndexes()
# select_area是一个鼠标选择区域,可以通过row()和column()方法获取每项的行坐标和列坐标
for item in select_area:
if item.row() not in row_list:
row_list.append(item.row())
if item.column() not in column_list:
column_list.append(item.column())
# 获取选中数据的索引
# 数据组合,传递数据,colum_list决定几组数量
for col in column_list:
line = []
for row in row_list:
line.append(self.data[row][col])
plot_data.append(line)
self.plot_signal.emit(plot_data) # 信号的触发
class MainUi(QWidget):
def __init__(self):
super().__init__()
self.resize(400, 400)
self.initUI()
def initUI(self):
hbox = QHBoxLayout()
# 横向布局
self.table = TableUi()
# 连接信号
self.table.plot_signal.connect(self.plot_data_deal)
self.bar = CtxPlotBar()
hbox.addWidget(self.table)
hbox.addWidget(self.bar)
self.setLayout(hbox)
def plot_data_deal(self, plot_data):
self.bar.plot_bar(plot_data)
if __name__ == '__main__':
app = QApplication(sys.argv)
demo = MainUi()
demo.show()
sys.exit(app.exec_())
运行效果