Как вы увеличиваете pickradius художника Matplotlib Line2D? - PullRequest
2 голосов
/ 24 января 2020

Я хотел бы создать сюжет, где каждая точка - это отдельный художник, которого можно выбрать. Это мое текущее решение:

import sys
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.backends.backend_qt5agg import \
    FigureCanvasQTAgg as FigureCanvas
import matplotlib.patheffects as PathEffects

from PyQt5.QtWidgets import QDialog, QApplication, QVBoxLayout


class MainWindow(QDialog):
    def __init__(self):
        super().__init__()
        self.fig, self.ax = plt.subplots()
        self.canvas = FigureCanvas(self.fig)

        a = [np.random.randint(100) for _ in range(100)]
        b = [np.random.randint(100) for _ in range(100)]
        self.artists = []
        self.last_artist = None
        for x, y in zip(a, b):
            artist = self.ax.plot(
                x, y, 'o', picker=True, pickradius=6, color='#ff4500'
            )
            self.artists += artist

        self.canvas.draw()

        self.cid_motion = self.fig.canvas.mpl_connect(
            'motion_notify_event', self.hover
        )

        layout = QVBoxLayout()
        layout.addWidget(self.canvas)
        self.setLayout(layout)

    def hover(self, event):
        if event.inaxes == self.ax:
            ind = 0
            cont = None
            while (
                ind in range(len(self.artists))
                and not cont
            ):
                artist = self.artists[ind]
                cont, _ = artist.contains(event)
                if cont:
                    if artist is not self.last_artist:
                        if self.last_artist is not None:
                            self.last_artist.set_path_effects(
                                [PathEffects.Normal()]
                            )
                            self.last_artist.set_zorder(2)
                        artist.set_path_effects(
                            [PathEffects.withStroke(
                                linewidth=7, foreground="c", alpha=0.4
                            )]
                        )
                        artist.set_zorder(3)
                        self.last_artist = artist
                ind += 1

            if not cont and self.last_artist is not None:
                self.last_artist.set_path_effects([PathEffects.Normal()])
                self.last_artist.set_zorder(2)
                self.last_artist = None
            self.canvas.draw()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    GUI = MainWindow()
    GUI.show()
    sys.exit(app.exec_())

Однако выделение only работает, если вы наведите точно на центр точки данных, это не имеет значения если вы увеличите pickradius. Поэтому я подумал, что, возможно, смогу изменить метод contains, но я не знаю как. Я обнаружил, что matplotlib Artists поставляется с set_contains методом , который вы можете использовать для создания собственного contains метода. Но я не знаю, как это сделать. Я надеялся, что смогу узнать, как реализован метод contains по умолчанию, и взглянул на исходный код , но, к сожалению, это ничего не объясняет.

1 Ответ

1 голос
/ 24 января 2020

pickradius в сочетании с picker как bool должен достичь того, что вы намереваетесь. Однако это не так. С другой стороны, picker, если определено с плавающей точкой, используется в качестве радиуса выбора в точках. Следовательно, задание допуска прямо к picker заставляет вещь работать. Измените следующую строку:

        artist = self.ax.plot(
            x, y, 'o', picker=True, pickradius=6, color='#ff4500'
        )

на

        artist = self.ax.plot(
            x, y, 'o', picker=6, color='#ff4500'
        )
...