在我的 pyqt5 项目中,我使用一个小部件来显示绘图并将其提升为 mplWidget 类。我正在尝试用标签在悬停时注释一条垂直线(其长度应该到图 2 中所示的图形点)。但是每当我使用SnaptoCursor
类时,都会出现垂直线,但它没有移动或不起作用(图1)。
我正在关注这个示例:将光标添加到 matplotlib
我在这里发布我的完整代码:
主应用程序.py
from PyQt5 import QtCore, QtGui, QtWidgets
from uiWindow import Ui_MainWindow
import pandas as pd
import sys
import datetime as dt
import matplotlib.pyplot as plt
from matplotlib import dates as mdates
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
from PandasModel import PandasModel
from mplWidget import MplWidget
import mplcursors
class MplCanvas(FigureCanvasQTAgg):
def __init__(self, parent=None, width=5, height=4, dpi=100):
fig = Figure(figsize=(width, height), dpi=dpi)
self.axes = fig.add_subplot(111)
super(MplCanvas, self).__init__(fig)
class SnaptoCursor(object):
def __init__(self, ax, x, y):
# self.ax = ax
self.ly = ax.axvline(color='k', alpha=0.2) # the vert line
self.marker, = ax.plot([0],[0], marker="o", color="crimson", zorder=3)
self.x = x
self.y = y
self.txt = ax.text(0.7, 0.9, '')
def mouse_move(self, event):
if not event.inaxes: return
x, y = event.xdata, event.ydata
indx = np.searchsorted(self.x, [x])[0]
x = self.x[indx]
y = self.y[indx]
self.ly.set_xdata(x)
self.marker.set_data([x],[y])
self.txt.set_text('x=%1.2f, y=%1.2f' % (x, y))
self.txt.set_position((x,y))
ax.canvas.draw_idle()
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None,):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.pushButton.clicked.connect(self.displayReturns)
def displayReturns(self):
fileName, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Open File", "", "CSV Files (*.csv)");
df = pd.read_csv(fileName)
model = PandasModel(df)
self.tableView.setModel(model)
t=df['dtTradeDate']
p=df["fPerf"]
# get 3month freq for xticks---
startDate=t.min()
EndDate=t.max()
l =[]
for x in pd.bdate_range(start=startDate, end=EndDate, freq='3M'):
l.append(str(x))
# plot----------
ax=self.widget.canvas.axes
ax.clear()
lines =ax.plot(t,p,color='deepskyblue', linewidth=0.7)[0]
ax.set_xticks(l)
plt.xticks(rotation="vertical")
self.widget.canvas.draw()
# cursor hoverrr
def show_annotation(val):
xi, yi = val.target
xi = int(round(xi))
print(xi)
val.annotation.set_text(f'{t[xi]}\nvalue:{yi:.3f}')
cursor = mplcursors.cursor(lines, hover=True)
cursor.connect('add', show_annotation)
@cursor.connect("add")
def _(sel):
sel.annotation.get_bbox_patch().set(fc="none",boxstyle="square")
sel.annotation.arrow_patch.set( fc="black", alpha=.2)
#vertical line---
cursor2 = SnaptoCursor(ax, t, p)
cid = plt.connect('motion_notify_event', cursor2.mouse_move)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
mplWidget.py
from PyQt5.QtWidgets import*
from matplotlib.backends.backend_qt5agg import FigureCanvas
from matplotlib.figure import Figure
from matplotlib.widgets import Cursor
import mplcursors
import matplotlib.pyplot as plt
class MplWidget(QWidget):
def __init__(self, parent = None):
QWidget.__init__(self, parent)
self.canvas = FigureCanvas(Figure())
vertical_layout = QVBoxLayout()
vertical_layout.addWidget(self.canvas)
self.canvas.axes = self.canvas.figure.add_subplot(111)
self.canvas.axes.set_position([0.03, 0.2,0.95, 0.7])
self.canvas.axes.spines['bottom'].set_color('deepskyblue')
self.canvas.axes.spines['top'].set_color('deepskyblue')
self.canvas.axes.spines['right'].set_color('deepskyblue')
self.canvas.axes.spines['left'].set_color('deepskyblue')
self.canvas.axes.grid(True, lw ='.2', ls = '--', c = '.1')
self.canvas.axes.tick_params(axis='x', which='major', labelsize=7,color='deepskyblue')
self.canvas.axes.tick_params(axis='y', which='major', labelsize=7,color='deepskyblue')
self.setLayout(vertical_layout)
uiWindow.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.frame = QtWidgets.QFrame(self.centralwidget)
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.pushButton = QtWidgets.QPushButton(self.frame)
self.pushButton.setObjectName("pushButton")
self.verticalLayout_2.addWidget(self.pushButton)
self.frame_2 = QtWidgets.QFrame(self.frame)
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_2.setObjectName("frame_2")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.frame_2)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.widget = MplWidget(self.frame_2)
self.widget.setObjectName("widget")
self.verticalLayout_3.addWidget(self.widget)
self.verticalLayout_2.addWidget(self.frame_2)
self.frame_3 = QtWidgets.QFrame(self.frame)
self.frame_3.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_3.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_3.setObjectName("frame_3")
self.verticalLayout_4 = QtWidgets.QVBoxLayout(self.frame_3)
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.tableView = QtWidgets.QTableView(self.frame_3)
self.tableView.setObjectName("tableView")
self.verticalLayout_4.addWidget(self.tableView)
self.verticalLayout_2.addWidget(self.frame_3)
self.verticalLayout_2.setStretch(1, 1)
self.verticalLayout_2.setStretch(2, 1)
self.verticalLayout.addWidget(self.frame)
MainWindow.setCentralWidget(self.centralwidget)
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"))
self.pushButton.setText(_translate("MainWindow", "PushButton"))
from mplWidget import MplWidget
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_())
PandasModel.pyPandasModel(QtCore.QAbstractTableModel)
从
此处输入链接描述
复制类
和我的 csv 数据,如: