2016-10-26 15 views
2

データセット内のポイントのセットを手動で調整するには、ドラッグ可能なデータマーカーが必要です。 This答えて、他の人がこの問題をPatch.Circleを使って解決します。しかし、私はプロットをズームするときに同じサイズを維持するためにマーカーが必要です。サークルではサークルもズームします。私はマーカーを動かすより簡単な方法があるように見えるので、新しいズームごとにサークルのサイズを動的に変更する方法を見つけようとしていません。誰もこれを行う方法を知っていますか?Matplotlibのドラッグ可能なデータマーカー

+0

座標が、パッチのサイズは、Axesの座標であることを? – cphlewis

答えて

2

以下、matplotlibとPyQt4のオブジェクト指向APIを使用する方法の1つを示すMWEを示します。データマーカーは、マウスの中央ボタンを使用してドラッグ可能です。ストラテジは、データをLine2Dアーティストにプロットし、続いてアーティストのデータを操作してプロットを更新することによってマーカーをドラッグすることです。 - 中央のマウスボタンをクリックすると、ピクセル単位でのマウスカーソルの座標がLine2Dの両方のアーティストの画素で変換XYデータと比較される

ステップ1:これは大まかに3つのステップに要約することができます。カーソルと最も近いマーカ間の線形距離が所定の値(マーカのサイズとして定義される)よりも小さい場合、そのデータマーカのインデックスはクラス属性draggableに保存されます。それ以外の場合、draggableNoneに設定されます。

ステップ2 - マウスが移動されると、draggable is not None場合、そのインデックスクラス属性draggableに記憶されたマウスカーソルのものに設定されているデータのマーカの座標。

ステップ3 - マウスの中央ボタンを放すと、draggableがNoneに戻されます。

注:必要に応じて、オブジェクト指向APIではなく、図を生成するためにpyplotインターフェイスを使用することもできます。あなたがパッチの場所は、データになりたい

import sys 
from PyQt4 import QtGui 
from matplotlib.figure import Figure 
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg 
from matplotlib.backends.backend_qt4agg import FigureManagerQT 
import numpy as np 


class MyFigureCanvas(FigureCanvasQTAgg): 
    def __init__(self): 
     super(MyFigureCanvas, self).__init__(Figure()) 
     # init class attributes: 
     self.background = None 
     self.draggable = None 
     self.msize = 6 
     # plot some data: 
     x = np.random.rand(25) 
     self.ax = self.figure.add_subplot(111) 
     self.markers, = self.ax.plot(x, marker='o', ms=self.msize) 
     # define event connections: 
     self.mpl_connect('motion_notify_event', self.on_motion) 
     self.mpl_connect('button_press_event', self.on_click) 
     self.mpl_connect('button_release_event', self.on_release) 

    def on_click(self, event): 
     if event.button == 2: # 2 is for middle mouse button 
      # get mouse cursor coordinates in pixels: 
      x = event.x 
      y = event.y 
      # get markers xy coordinate in pixels: 
      xydata = self.ax.transData.transform(self.markers.get_xydata()) 
      xdata, ydata = xydata.T 
      # compute the linear distance between the markers and the cursor: 
      r = ((xdata - x)**2 + (ydata - y)**2)**0.5 
      if np.min(r) < self.msize: 
       # save figure background: 
       self.markers.set_visible(False) 
       self.draw() 
       self.background = self.copy_from_bbox(self.ax.bbox) 
       self.markers.set_visible(True) 
       self.ax.draw_artist(self.markers) 
       self.update() 
       # store index of draggable marker: 
       self.draggable = np.argmin(r) 
      else: 
       self.draggable = None 

    def on_motion(self, event): 
     if self.draggable is not None: 
      if event.xdata and event.ydata: 
       # get markers coordinate in data units: 
       xdata, ydata = self.markers.get_data() 
       # change the coordinate of the marker that is 
       # being dragged to the ones of the mouse cursor: 
       xdata[self.draggable] = event.xdata 
       ydata[self.draggable] = event.ydata 
       # update the data of the artist: 
       self.markers.set_xdata(xdata) 
       self.markers.set_ydata(ydata) 
       # update the plot: 
       self.restore_region(self.background) 
       self.ax.draw_artist(self.markers) 
       self.update() 

    def on_release(self, event): 
     self.draggable = None 

if __name__ == '__main__': 

    app = QtGui.QApplication(sys.argv) 

    canvas = MyFigureCanvas() 
    manager = FigureManagerQT(canvas, 1) 
    manager.show() 

    sys.exit(app.exec_()) 

enter image description here

+0

これは素晴らしい作品です!ありがとう! – martinako

+0

on_click()は、(on_motion()のように)データ座標で計算することに関して、ピクセル座標で計算することに利点があるのだろうかと思います。 on_click()のデータ座標を操作することは、データ座標をピクセル座標に変換する必要はありません。いずれにしても、教育目的のために、両方の用途を見るのが得意です:-) – martinako

+1

@martinakoピクセル座標は、x軸とy軸のスケールとは無関係の直線距離を計算できます。そうでなければ、xyデータを変換する必要があります。なぜなら、両方の軸が同じ縮尺ではなく、ズームアウト時にも考慮に入れるということです。 –

関連する問題