0

在此处输入图像描述

在我的 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 数据,如:

在此处输入图像描述

4

0 回答 0