matplotlib (imshow) 中的每个块应该如何被点击?
Posted
技术标签:
【中文标题】matplotlib (imshow) 中的每个块应该如何被点击?【英文标题】:How every block in matplotlib (imshow) should be made clickable? 【发布时间】:2017-06-16 16:28:41 【问题描述】:我有 2 个矩阵,我正在使用 matplotlib 通过imshow
显示它们。我使用 PyQt5 将 matplotlib 嵌入到一个小 GUI 中。每个块分别代表矩阵中的每个值。我希望这些块是可点击的。使其可点击的原因是每当点击每个块时,都会弹出另一个 matplotlib 图。在进入这个阶段之前,我希望这些块是可点击的。我怎样才能做到这一点?我已经尝试了几种来自互联网的方法,但没有运气。
界面图片
import sys
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout, \
QLineEdit, QMessageBox, QInputDialog, QLabel, QHBoxLayout, QGridLayout, QStackedLayout, QFormLayout
from PyQt5 import QtCore, QtGui, QtWidgets
import time
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.lines import Line2D
import numpy as np
import matplotlib.animation as animation
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
j=0
figure = plt.figure()
H = np.array([[100, 2, 39, 190], [402, 55, 369, 1023], [300, 700, 8, 412], [170, 530, 330, 1]])
Z = np.array([[3, 290, 600, 480], [1011, 230, 830, 0], [152, 750, 5, 919], [340, 7, 543, 812]])
class Window(QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
# a figure instance to plot on
self.figure = plt.figure()
# this is the Canvas Widget that displays the `figure`
# it takes the `figure` instance as a parameter to __init__
self.canvas = FigureCanvas(self.figure)
# this is the Navigation widget
# it takes the Canvas widget and a parent
self.toolbar = NavigationToolbar(self.canvas, self)
# Just some button connected to `plot` method
self.button = QPushButton('Plot')
self.button.clicked.connect(self.loop)
self.button.setDefault(False)
self.stop = QPushButton("Stop")
self.stop.clicked.connect(self.loopStop)
self.stop.setDefault(False)
self.exit = QPushButton('Exit')
self.exit.clicked.connect(self.closeIt)
self.exit.setDefault(True)
self.leBtn = QPushButton('Enter Vmin')
self.leBtn.clicked.connect(self.on_pushButtonOK_clicked)
self.leBtn.setDefault(False)
self.lineedit = QLineEdit(self)
validator = QtGui.QIntValidator()
self.lineedit.setValidator(validator)
self.lineedit.returnPressed.connect(self.leBtn.click)
self.leBtn1 = QPushButton('Enter Vmax')
self.leBtn1.clicked.connect(self.on_pushButtonOK_clicked1)
self.leBtn1.setDefault(False)
self.lineedit1 = QLineEdit(self)
validator = QtGui.QIntValidator()
self.lineedit1.setValidator(validator)
self.lineedit1.returnPressed.connect(self.leBtn1.click)
# set the layout
layout = QFormLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.button)
layout.addWidget(self.stop)
layout.addWidget(self.exit)
layout.addWidget(self.lineedit)
layout.addWidget(self.leBtn)
layout.addWidget(self.lineedit1)
layout.addWidget(self.leBtn1)
self.setLayout(layout)
def on_pushButtonOK_clicked(self):
self.vmin = int(self.lineedit.text())
def on_pushButtonOK_clicked1(self):
self.vmax=int(self.lineedit1.text())
def plot(self):
global j
if j == 0:
j += 1
rows, cols = H.shape
im = plt.imshow(H, interpolation='nearest', cmap='bwr', vmin=self.vmin, vmax=self.vmax, extent=[0, cols, 0, rows])
v = np.linspace(0, 1023, 15, endpoint=True)
ax1 = self.figure.add_axes([0.85, 0.093, 0.04, 0.8])
cax = self.figure.add_subplot(1, 1, 1)
self.figure.colorbar(im, cax=ax1, orientation='vertical', ticks=v)
self.canvas.draw()
elif j == 1:
j -= 1
rows, cols = H.shape
im = plt.imshow(Z, interpolation='nearest', cmap='Spectral', vmin=self.vmin, vmax=self.vmax,
extent=[0, cols, 0, rows])
v = np.linspace(0, 1023, 15, endpoint=True)
ax1 = self.figure.add_axes([0.85, 0.093, 0.04, 0.8])
cax = self.figure.add_subplot(1, 1, 1)
self.figure.colorbar(im, cax=ax1, orientation='vertical', ticks=v)
self.canvas.draw()
def loop(self):
self.timer = QtCore.QTimer()
self.timer.setSingleShot(False)
self.timer.timeout.connect(self.plot)
self.timer.start(1000)
def loopStop(self):
self.timer.stop()
def closeIt(self):
self.close()
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
【问题讨论】:
【参考方案1】:如果你想捕捉点击事件,你必须通过画布和mpl_connect('button_press_event', some_callback)
方法:
class Window(QDialog):
def __init__(self, parent=None):
[...]
self.canvas = FigureCanvas(self.figure)
self.canvas.mpl_connect('button_press_event', self.on_button_press_event)
[...]
def on_button_press_event(self, event):
print(event)
示例:
import sys
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout, \
QLineEdit, QMessageBox, QInputDialog, QLabel, QHBoxLayout, QGridLayout, QStackedLayout, QFormLayout
from PyQt5 import QtCore, QtGui, QtWidgets
import time
import matplotlib
matplotlib.use("TkAgg")
from matplotlib.lines import Line2D
import numpy as np
import matplotlib.animation as animation
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
from matplotlib.backends.backend_qt5agg import NavigationToolbar2QT as NavigationToolbar
import matplotlib.pyplot as plt
j=0
figure = plt.figure()
H = np.array([[100, 2, 39, 190], [402, 55, 369, 1023], [300, 700, 8, 412], [170, 530, 330, 1]])
Z = np.array([[3, 290, 600, 480], [1011, 230, 830, 0], [152, 750, 5, 919], [340, 7, 543, 812]])
class Window(QDialog):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
# a figure instance to plot on
self.figure = plt.figure()
# this is the Canvas Widget that displays the `figure`
# it takes the `figure` instance as a parameter to __init_
self.im = None
self.canvas = FigureCanvas(self.figure)
self.canvas.mpl_connect('button_press_event', self.on_button_press_event)
# this is the Navigation widget
# it takes the Canvas widget and a parent
self.toolbar = NavigationToolbar(self.canvas, self)
self.timer = QtCore.QTimer(self)
self.timer.timeout.connect(self.plot)
self.timer.setInterval(5000)
# Just some button connected to `plot` method
self.button = QPushButton('Plot')
self.button.clicked.connect(self.timer.start)
self.button.setDefault(False)
self.stop = QPushButton("Stop")
self.stop.clicked.connect(self.timer.stop)
self.stop.setDefault(False)
self.exit = QPushButton('Exit')
self.exit.clicked.connect(self.close)
self.exit.setDefault(True)
self.leBtn = QPushButton('Enter Vmin')
self.leBtn.clicked.connect(self.on_pushButtonOK_clicked)
self.leBtn.setDefault(False)
self.lineedit = QLineEdit(self)
validator = QtGui.QIntValidator()
self.lineedit.setValidator(validator)
self.lineedit.returnPressed.connect(self.leBtn.click)
self.leBtn1 = QPushButton('Enter Vmax')
self.leBtn1.clicked.connect(self.on_pushButtonOK_clicked1)
self.leBtn1.setDefault(False)
self.lineedit1 = QLineEdit(self)
validator = QtGui.QIntValidator()
self.lineedit1.setValidator(validator)
self.lineedit1.returnPressed.connect(self.leBtn1.click)
# set the layout
layout = QFormLayout()
layout.addWidget(self.toolbar)
layout.addWidget(self.canvas)
layout.addWidget(self.button)
layout.addWidget(self.stop)
layout.addWidget(self.exit)
layout.addWidget(self.lineedit)
layout.addWidget(self.leBtn)
layout.addWidget(self.lineedit1)
layout.addWidget(self.leBtn1)
self.setLayout(layout)
self.lb = QtWidgets.QLabel(self)
self.lb.setWindowFlags(QtCore.Qt.ToolTip)
def on_pushButtonOK_clicked(self):
self.vmin = int(self.lineedit.text())
def on_pushButtonOK_clicked1(self):
self.vmax=int(self.lineedit1.text())
def plot(self):
global j
if j == 0:
j += 1
rows, cols = H.shape
self.im = plt.imshow(H, interpolation='nearest', cmap='bwr', vmin=self.vmin, vmax=self.vmax, extent=[0, cols, 0, rows])
v = np.linspace(0, 1023, 15, endpoint=True)
ax1 = self.figure.add_axes([0.85, 0.093, 0.04, 0.8])
cax = self.figure.add_subplot(1, 1, 1)
self.figure.colorbar(self.im, cax=ax1, orientation='vertical', ticks=v)
self.canvas.draw()
elif j == 1:
j -= 1
rows, cols = H.shape
self.im = plt.imshow(Z, interpolation='nearest', cmap='Spectral', vmin=self.vmin, vmax=self.vmax,
extent=[0, cols, 0, rows])
v = np.linspace(0, 1023, 15, endpoint=True)
ax1 = self.figure.add_axes([0.85, 0.093, 0.04, 0.8])
cax = self.figure.add_subplot(1, 1, 1)
self.figure.colorbar(self.im, cax=ax1, orientation='vertical', ticks=v)
self.canvas.draw()
def on_button_press_event(self, event):
print('button=, x=, y=, xdata=, ydata='
.format(event.button, event.x, event.y, event.xdata, event.ydata))
if self.im:
message = str(self.im.get_cursor_data(event))
delay = 1000
w = self.lb.fontMetrics().width(message)
self.lb.resize(w, self.lb.size().height())
self.lb.setText(message)
self.lb.move(QtGui.QCursor.pos())
self.lb.show()
QtCore.QTimer.singleShot(delay, self.lb.hide)
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Window()
main.show()
sys.exit(app.exec_())
注意:我将 im 变量更改为 self.im 以便能够访问显示在 imshow 中的值
【讨论】:
非常感谢您帮助我。至少我知道这是如何工作的。现在我想要的是,当单击特定块时,应该会弹出一个 matplotlib 窗口,其中包含一些随机数据。我只需要一点想法。再次感谢 如果我的回答能帮助您将我的回答标记为正确,请 我更新了示例,显示了一个包含单元格内容的弹出窗口 我真的很感激。再次感谢。标记为正确。 @HammadUllah 由于您使用正方形,您可以使用 xclick 和 yclick 并确定使用舍入的正方形。像正方形 (1,1) 是roundup(xclick)==1 and roundup(yclick)==1
以上是关于matplotlib (imshow) 中的每个块应该如何被点击?的主要内容,如果未能解决你的问题,请参考以下文章
在 matplotlib imshow 中调整网格线和刻度线