在 pyqt5 中包含带有悬停标签的 matplotlib [英] Include matplotlib in pyqt5 with hover labels
问题描述
我有一个来自matplotlib的绘图,当我将鼠标悬停在该绘图上时,我想在标记点上显示标签.
I have a plot from matplotlib for which I would like to display labels on the marker points when hover over with the mouse.
我发现这个关于SO的非常有用的工作示例,我试图将完全相同的绘图集成到pyqt5应用程序中.不幸的是,当应用程序中有绘图时,悬停不再起作用.
I found this very helpful working example on SO and I was trying to integrate the exact same plot into a pyqt5 application. Unfortunately when having the plot in the application the hovering doesn't work anymore.
这是一个基于上述 SO 帖子的完整工作示例:
Here is a full working example based on the mentioned SO post:
import matplotlib.pyplot as plt
import scipy.spatial as spatial
import numpy as np
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
import sys
pi = np.pi
cos = np.cos
def fmt(x, y):
return 'x: {x:0.2f}\ny: {y:0.2f}'.format(x=x, y=y)
class FollowDotCursor(object):
"""Display the x,y location of the nearest data point.
https://stackoverflow.com/a/4674445/190597 (Joe Kington)
https://stackoverflow.com/a/13306887/190597 (unutbu)
https://stackoverflow.com/a/15454427/190597 (unutbu)
"""
def __init__(self, ax, x, y, tolerance=5, formatter=fmt, offsets=(-20, 20)):
try:
x = np.asarray(x, dtype='float')
except (TypeError, ValueError):
x = np.asarray(mdates.date2num(x), dtype='float')
y = np.asarray(y, dtype='float')
mask = ~(np.isnan(x) | np.isnan(y))
x = x[mask]
y = y[mask]
self._points = np.column_stack((x, y))
self.offsets = offsets
y = y[np.abs(y-y.mean()) <= 3*y.std()]
self.scale = x.ptp()
self.scale = y.ptp() / self.scale if self.scale else 1
self.tree = spatial.cKDTree(self.scaled(self._points))
self.formatter = formatter
self.tolerance = tolerance
self.ax = ax
self.fig = ax.figure
self.ax.xaxis.set_label_position('top')
self.dot = ax.scatter(
[x.min()], [y.min()], s=130, color='green', alpha=0.7)
self.annotation = self.setup_annotation()
plt.connect('motion_notify_event', self)
def scaled(self, points):
points = np.asarray(points)
return points * (self.scale, 1)
def __call__(self, event):
ax = self.ax
# event.inaxes is always the current axis. If you use twinx, ax could be
# a different axis.
if event.inaxes == ax:
x, y = event.xdata, event.ydata
elif event.inaxes is None:
return
else:
inv = ax.transData.inverted()
x, y = inv.transform([(event.x, event.y)]).ravel()
annotation = self.annotation
x, y = self.snap(x, y)
annotation.xy = x, y
annotation.set_text(self.formatter(x, y))
self.dot.set_offsets((x, y))
bbox = ax.viewLim
event.canvas.draw()
def setup_annotation(self):
"""Draw and hide the annotation box."""
annotation = self.ax.annotate(
'', xy=(0, 0), ha = 'right',
xytext = self.offsets, textcoords = 'offset points', va = 'bottom',
bbox = dict(
boxstyle='round,pad=0.5', fc='yellow', alpha=0.75),
arrowprops = dict(
arrowstyle='->', connectionstyle='arc3,rad=0'))
return annotation
def snap(self, x, y):
"""Return the value in self.tree closest to x, y."""
dist, idx = self.tree.query(self.scaled((x, y)), k=1, p=1)
try:
return self._points[idx]
except IndexError:
# IndexError: index out of bounds
return self._points[0]
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.width = 1000
self.height = 800
self.setGeometry(0, 0, self.width, self.height)
canvas = self.get_canvas()
w = QWidget()
w.layout = QHBoxLayout()
w.layout.addWidget(canvas)
w.setLayout(w.layout)
self.setCentralWidget(w)
self.show()
def get_canvas(self):
fig, ax = plt.subplots()
x = np.linspace(0.1, 2*pi, 10)
y = cos(x)
markerline, stemlines, baseline = ax.stem(x, y, '-.')
plt.setp(markerline, 'markerfacecolor', 'b')
plt.setp(baseline, 'color','r', 'linewidth', 2)
cursor = FollowDotCursor(ax, x, y, tolerance=20)
canvas = FigureCanvas(fig)
return canvas
app = QApplication(sys.argv)
win = MainWindow()
sys.exit(app.exec_())
将鼠标悬停在pyqt应用程序中时,我该怎么做才能使标签也显示?
What would I have to do to make the labels also show when hovering over in the pyqt application?
推荐答案
第一个问题可能是您没有保留对 FollowDotCursor 的引用.
The first problem may be that you don't keep a reference to the FollowDotCursor.
因此,要确保 FollowDotCursor
保持活动状态,可以将其设置为类变量
So to make sure the FollowDotCursor
stays alive, you can make it a class variable
self.cursor = FollowDotCursor(ax, x, y, tolerance=20)
而不是 cursor = ...
.
接下来确保在给图形画布之后设置 Cursor 类.
Next make sure you instatiate the Cursor class after giving the figure a canvas.
canvas = FigureCanvas(fig)
self.cursor = FollowDotCursor(ax, x, y, tolerance=20)
最后,在 FollowDotCursor 中保留对回调的引用,不要使用 plt.connect
而是画布本身:
Finally, keep a reference to the callback inside the FollowDotCursor and don't use plt.connect
but the canvas itself:
self.cid = self.fig.canvas.mpl_connect('motion_notify_event', self)
这篇关于在 pyqt5 中包含带有悬停标签的 matplotlib的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!