如何使用 Matplotblib 和 PyQt5 将数据游标添加到条形图中?
Posted
技术标签:
【中文标题】如何使用 Matplotblib 和 PyQt5 将数据游标添加到条形图中?【英文标题】:How to add the datacursor to a bar chart with Matplotblib and PyQt5? 【发布时间】:2018-07-21 20:12:19 【问题描述】:我尝试使用以下代码将数据游标功能添加到我的条形图中:
datacursor(hover=True, formatter=self.formatter)
当我将鼠标指针悬停在条上时,不会发生错误,但工具提示不显示。
我尝试将以下代码(这个代码完美)放入QWidget
:
import numpy as np
import matplotlib.pyplot as plt
from mpldatacursor import datacursor
label = ['a', 'b', 'c', 'd']
x = [1, 2, 3, 4]
y = [10, 20, 30, 40]
fig, ax = plt.subplots()
ax.bar(x, y, align='center', color='lightblue')
ax.margins(0.05)
ax.set_ylim(bottom=0)
def formatter(**kwargs):
dist = abs(np.array(x) - kwargs['x'])
i = dist.argmin()
return '\n'.join(label[i])
datacursor(hover=True, formatter=formatter)
plt.show()
这是我当前的代码。
后端:
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QWidget
from front_end import Ui_MainWindow
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt
from mpldatacursor import datacursor
class Ui_MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(Ui_MainWindow, self).__init__(parent)
self.setupUi(self)
self.graph = MyCanvas()
self.gridLayout.addWidget(self.graph, 0, 0, 1, 1)
self.populate()
def populate(self):
self.graph.figure.clf()
self.axes= self.graph.figure.add_subplot(111)
label = ['a', 'b', 'c', 'd']
x = [1, 2, 3, 4]
y = [10, 20, 30, 40]
datacursor(hover=True, formatter=self.formatter)
self.axes.bar(x, y, align='center', bottom=0, color='b')
def formatter(**kwargs):
x = [1, 2, 3, 4]
dist = abs(np.array(x) - kwargs['x'])
i = dist.argmin()
return '\n'.join(label[i])
class MyCanvas(FigureCanvas):
def __init__(self, *args, **kwargs):
self.figure = plt.figure()
FigureCanvas.__init__(self, self.figure)
self.figure.patch.set_facecolor("None")
self.figure.subplots_adjust(left=0.08, bottom=0.10, right=0.99, top=0.97)
if __name__ == '__main__':
app = QApplication(sys.argv)
prog = Ui_MainWindow()
prog.show()
sys.exit(app.exec_())
前端:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(625, 460)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.widget = QtWidgets.QWidget(self.centralwidget)
self.widget.setObjectName("widget")
self.gridLayout.addWidget(self.widget, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 625, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
【问题讨论】:
询问不良行为时,请始终提供minimal reproducible example。我试图让你的代码可以运行,但需要中途放弃......只要确保有人可以从问题中复制它而无需猜测丢失的东西。 所以更准确地说:formatter
方法中的x
是什么?它没有定义。
感谢您的评论。我添加了前端的代码。希望它会有所帮助。谢谢。
是的,但是如果没有定义x
,代码将无法运行。
@ImportanceOfBeingErnest 一个问题,即使使用了FigureCanvasQTAgg,还会继续处理原生的matplotlib事件吗?
【参考方案1】:
有几个问题。
需要定义在formatter
方法内部使用的 x
和 label
。一个好的解决方案是使它们成为类变量。
formatter
方法应该是类的方法。因此,最好使用 self
参数将其定义为 1。
将使用的类命名为与导入的类相同可能会导致混淆,最好使用不同的名称。
datacursor
需要知道要处理哪些对象,因此需要先定义条形图,然后以这些条形作为参数调用 datacursor
函数。
格式化器的返回不需要加入任何东西,只需要返回标签显示即可。
这应该看起来像
class MyWindow(QMainWindow, Ui_MainWindow):
# ....
def populate(self):
self.graph.figure.clf()
self.axes= self.graph.figure.add_subplot(111)
self.label = ['a', 'b', 'c', 'd']
self.x = [1, 2, 3, 4]
self.y = [10, 20, 30, 40]
bars = self.axes.bar(self.x, self.y, align='center', bottom=0, color='b')
datacursor(bars, hover=True, formatter=self.formatter)
def formatter(self, **kwargs):
dist = abs(np.array(self.x) - kwargs['x'])
i = dist.argmin()
return self.label[i]
【讨论】:
以上是关于如何使用 Matplotblib 和 PyQt5 将数据游标添加到条形图中?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Python、PyQt5 和 Pyinstaller 修复未正确显示的按钮
如何使用 QML 和 PyQt5 创建一个没有标题栏的小通知窗口
PyQt5:如何在 QThread 和某些子类之间“通信”?
如何使用 PyQt5 实现自定义标题栏和窗口框架? [复制]