Как настроить Matplotlib Multicursor? - PullRequest
0 голосов
/ 28 ноября 2018

Я пытаюсь реализовать перекрестие matplotlib для двух осей, используя Multicursor.Я хочу новую функцию, которая будет просто рисовать горизонтальную линию курсора для осей, где находится указатель, а не для любых других

Пример кода:

import sys
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt
from matplotlib.widgets import MultiCursor
from PyQt5.QtWidgets import QMainWindow,QVBoxLayout
from PyQt5.QtWidgets import QApplication
from PyQt5 import QtCore, QtGui, QtWidgets
class MainWindow_code_serarch(object):

    def setup_code_serarch(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(870, 680)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.verticalLayoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.verticalLayoutWidget.setGeometry(QtCore.QRect(17, 50, 741, 553))
        self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
        self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
        self.verticalLayout.setContentsMargins(0, 0, 0, 0)
        self.verticalLayout.setObjectName("verticalLayout")


        self.figure = plt.figure(facecolor='black')
        self.canvas = FigureCanvas(self.figure)
        self.verticalLayout.addWidget(self.canvas)
        axes, axes2 = self.figure.subplots(nrows=2, sharex=True)
        axes.plot([1, 2, 3, 4,5,6,7,8])
        axes2.plot([1, 2, 3, 4,7,8,9])
        axes.set_position([0.02, 0.37, 0.88, 0.6])
        axes2.set_position([0.02, 0.15, 0.88, 0.22])
        axes.tick_params(axis='both', color='#ffffff', labelcolor='#ffffff')
        axes.yaxis.tick_right()
        axes2.tick_params(axis='both', color='#ffffff', labelcolor='#ffffff')
        axes2.grid(color='lightgray', linewidth=.5, linestyle=':')
        axes.grid(color='lightgray', linewidth=.5, linestyle=':')
        axes2.yaxis.tick_right()
        axes.autoscale_view()
        axes2.autoscale_view()
        axes.margins(0, .5)
        axes2.margins(0, .5)
        axes.set_facecolor('#041105')
        axes2.set_facecolor('#041105')

        self.multi = MultiCursor(self.canvas, (axes, axes2), color='r', lw=1,horizOn=True, vertOn=True)

        self.canvas.draw()


        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 246, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)
        # self.pushButton.clicked.connect(self.graphShowCode)

        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", "OK"))

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = MainWindow_code_serarch()
    ui.setup_code_serarch(MainWindow)
    MainWindow.show()
    sys.exit(app.exec_())

пример выходных данных приведен ниже: out put of my code

Есть ли другой процесс, которому я могу следовать, пожалуйста, предложите.

Примечание: я использовал здесь python pyqt5, библиотеку matplotlib

Ответы [ 2 ]

0 голосов
/ 30 ноября 2018

Я редактировал некоторый код из-за того, что всякий раз, когда я пытаюсь построить новый след, я показываю предыдущее шоу курсора.Так что я скрываю значение переменной по умолчанию для hline и vline.

from matplotlib.widgets import MultiCursor
from matplotlib.widgets import *
from matplotlib.figure import Figure
class FigureCursor(Widget):
    def __init__(self, fig, horizOn=True, vertOn=True, useblit=True, **lineprops):
        self._cidmotion = None
        self._ciddraw = None
        self.background = None
        self.needclear = False
        self.visible = True
        self.canvas = fig.canvas
        self.fig = fig
        self.horizOn = horizOn
        self.vertOn = vertOn
        self.useblit = useblit
        self.vline, = fig.axes[0].plot([1, 1], [0., 1.], visible=vertOn, transform=self.fig.transFigure,
                                       clip_on = False, **lineprops)
        self.hline, = fig.axes[0].plot([0., 1.], [-1., 0.], visible=horizOn, transform=self.fig.transFigure,
                                       clip_on=False, **lineprops)
        self.connect()

    def connect(self):
        """connect events"""
        self._cidmotion = self.canvas.mpl_connect('motion_notify_event', self.onmove)
        self._ciddraw = self.canvas.mpl_connect('draw_event', self.clear)

    def disconnect(self):
        """disconnect events"""
        self.canvas.mpl_disconnect(self._cidmotion)
        self.canvas.mpl_disconnect(self._ciddraw)

    def clear(self, event):
        """clear the cursor"""
        if self.ignore(event):
            return
        if self.useblit:
            self.background = (
                self.canvas.copy_from_bbox(self.canvas.figure.bbox))
        for line in [self.vline, self.hline]:
            line.set_visible(False)

    def onmove(self, event):
        if self.ignore(event):
            return
        if event.inaxes is None:
            return
        if not self.canvas.widgetlock.available(self):
            return
        self.needclear = True
        if not self.visible:
            return
        trans = event.inaxes.transData + self.fig.transFigure.inverted()
        x_fig, y_fig = trans.transform([event.xdata, event.ydata])
        if self.vertOn:
            self.vline.set_xdata([x_fig, x_fig])
            self.vline.set_visible(self.visible)
        if self.horizOn:
            self.hline.set_ydata([y_fig, y_fig])
            self.hline.set_visible(self.visible)
        self._update()

    def _update(self):
        if self.useblit:
            if self.background is not None:
                self.canvas.restore_region(self.background)
            if self.vertOn:
                self.fig.draw_artist(self.vline)
            if self.horizOn:
                self.fig.draw_artist(self.hline)
            self.canvas.blit(self.canvas.figure.bbox)
        else:
            self.canvas.draw_idle()
0 голосов
/ 28 ноября 2018

РЕДАКТИРОВАТЬ: Основываясь на комментариях ниже, я думаю, что вы ищете курсор на уровне фигуры, который следует за мышью, независимо от осей, над которыми вы зависаете.Я создал новый класс, основанный на коде для MultiCursor, который должен делать то, что вы хотели.

class FigureCursor(Widget):
    def __init__(self, fig, horizOn=True, vertOn=True, useblit=True, **lineprops):
        self._cidmotion = None
        self._ciddraw = None
        self.background = None
        self.needclear = False
        self.visible = True
        self.canvas = fig.canvas
        self.fig = fig
        self.horizOn = horizOn
        self.vertOn = vertOn
        self.useblit = useblit
        self.vline, = fig.axes[0].plot([.5, .5], [0., 1.], visible=vertOn, transform=self.fig.transFigure,
                                       clip_on = False, **lineprops)
        self.hline, = fig.axes[0].plot([0., 1.], [.5, .5], visible=horizOn, transform=self.fig.transFigure,
                                       clip_on=False, **lineprops)
        self.connect()

    def connect(self):
        """connect events"""
        self._cidmotion = self.canvas.mpl_connect('motion_notify_event', self.onmove)
        self._ciddraw = self.canvas.mpl_connect('draw_event', self.clear)

    def disconnect(self):
        """disconnect events"""
        self.canvas.mpl_disconnect(self._cidmotion)
        self.canvas.mpl_disconnect(self._ciddraw)

    def clear(self, event):
        """clear the cursor"""
        if self.ignore(event):
            return
        if self.useblit:
            self.background = (
                self.canvas.copy_from_bbox(self.canvas.figure.bbox))
        for line in [self.vline, self.hline]:
            line.set_visible(False)

    def onmove(self, event):
        if self.ignore(event):
            return
        if event.inaxes is None:
            return
        if not self.canvas.widgetlock.available(self):
            return
        self.needclear = True
        if not self.visible:
            return
        trans = event.inaxes.transData + self.fig.transFigure.inverted()
        x_fig, y_fig = trans.transform([event.xdata, event.ydata])
        if self.vertOn:
            self.vline.set_xdata([x_fig, x_fig])
            self.vline.set_visible(self.visible)
        if self.horizOn:
            self.hline.set_ydata([y_fig, y_fig])
            self.hline.set_visible(self.visible)
        self._update()

    def _update(self):
        if self.useblit:
            if self.background is not None:
                self.canvas.restore_region(self.background)
            if self.vertOn:
                self.fig.draw_artist(self.vline)
            if self.horizOn:
                self.fig.draw_artist(self.hline)
            self.canvas.blit(self.canvas.figure.bbox)
        else:
            self.canvas.draw_idle()

В вашем собственном коде:

(...)
self.multi = FigureCursor(self.figure, horizOn=True, vertOn=True, color='r', lw=1)
(...)

enter image description here

РЕДАКТИРОВАТЬ: часть ниже моя предыдущая попытка ответить на вопрос

Я написал класс, которыйнаследуется от MultiCursor, и вместо True/False для horizOn= и vertOn= берется список осей, на которых можно рисовать горизонтальные или вертикальные линии.

Я обнаружил поведение MutiCursor немного странно, когда мышь перемещается от одного топора к другому, но я не изменил это поведение.Этот код должен помочь вам начать дальнейшее изменение класса.В частности, вы можете переопределить функцию onmove() .

enter image description here

class MyMultiCursor(MultiCursor):
    def __init__(self, canvas, axes, useblit=True, horizOn=[], vertOn=[], **lineprops):
        super(MyMultiCursor, self).__init__(canvas, axes, useblit=useblit, horizOn=False, vertOn=False, **lineprops)

        self.horizAxes = horizOn
        self.vertAxes = vertOn

        if len(horizOn) > 0:
            self.horizOn = True
        if len(vertOn) > 0:
            self.vertOn = True

        xmin, xmax = axes[-1].get_xlim()
        ymin, ymax = axes[-1].get_ylim()
        xmid = 0.5 * (xmin + xmax)
        ymid = 0.5 * (ymin + ymax)

        self.vlines = [ax.axvline(xmid, visible=True, **lineprops) for ax in self.vertAxes]
        self.hlines = [ax.axhline(ymid, visible=True, **lineprops) for ax in self.horizAxes]

и в своем классе создать экземпляр:

    self.multi = MyMultiCursor(self.canvas, (axes, axes2), color='r', lw=1, horizOn=[axes], vertOn=[axes2])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...