2017-06-23 4 views
0

マウスでマウスを移動するとマーカーポイントにラベルを表示したいmatplotlibのプロットがあります。pyqt5にmatplotlibをホバーラベル付きで表示する

私はthis very helpful working exampleをSO上に見つけました。まったく同じプロットをpyqt5アプリケーションに統合しようとしていました。 残念なことに、アプリケーションにプロットしているときは、ホバリングはもう機能しません。ここで

は完全な作業例が挙げSOポストに基づいています。

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はアプリケーションで上にマウスを移動する際にラベルにも表示させるためにしなければならないでしょうか?

答えて

1

最初の問題は、FollowDotCursorへの参照を保持していないことが原因です。ですから、

self.cursor = FollowDotCursor(ax, x, y, tolerance=20) 

代わりのcursor = ...それクラスは、可変にすることができ、生きているFollowDotCursor滞在を確実にする

次に、の後にCursorクラスを入れて、図形をキャンバスにしてください。

canvas = FigureCanvas(fig) 
self.cursor = FollowDotCursor(ax, x, y, tolerance=20) 

最後に、FollowDotCursor内部のコールバックへの参照を保持し、plt.connectが、キャンバス自体を使用していない:私はそれを試してみました

self.cid = self.fig.canvas.mpl_connect('motion_notify_event', self) 
+0

が、それはまだ動作しません – wasp256

+0

[OK]を、I答えを更新しました。 – ImportanceOfBeingErnest

+0

はい、うまくいきました!助けてくれてありがとう – wasp256

関連する問題