2016-05-29 1 views
2

私はLine2dオブジェクトに沿って個々のマーカーをドラッグ可能にしようとしています。私はこれがbar()を使ってどのように行われたかを見てきましたMatplotlib's draggable rectangle example.ここでの基本的な違いは、ax.bar(...)はアーティストセットを生成し、ax.plot(...)はLine2Dオブジェクトを1つ返します。その行にある単一のマーカー要素のプロパティーを編集する方法を知らず、文書を精査して何も見つけることができません。 Circle()オブジェクトを「マーカー」として使用し、その行をmotion_notify_eventとして連続して再描画する必要がありますか?私はここに私のコードを貼り付けることができますが、それは根本的に間違っています(笑)。matplotlibを使って特定のマーカーを選択し編集する

+0

次の質問を確認してください:http://stackoverflow.com/questions/28001655/draggable-line-with-draggable-points – armatita

+0

この質問は非常に便利ですが、Ellipse()もマーカーとして使用しています。 「ネイティブ」Line2Dマーカーでこれを行う方法はありますか? –

+0

マーカーは透明にすることも、透明にすることもできます(線の頂点をドラッグしているような錯覚を与えます)。私はそれを答えに入れました。それがあなたに合っているかどうか見てください。 – armatita

答えて

1

これを行う方法はいくつかあります。私はライン自体をドラッグするための簡単な方法があるとは思わない。ラインマーカーをドラッグするには(ただし、何も見ずに)それらが存在することを確認して透明にします。 matplotlibのドキュメントの例を使用します:The Path Editor。ここで

が変更されたコードです:

import numpy as np 
import matplotlib.path as mpath 
import matplotlib.patches as mpatches 
import matplotlib.pyplot as plt 

Path = mpath.Path 

fig, ax = plt.subplots() 

pathdata = [ 
    (Path.MOVETO, (1.58, -2.57)), 
    (Path.MOVETO, (0.35, -1.1)), 
    (Path.MOVETO, (-1.75, 2.0)), 
    (Path.MOVETO, (0.375, 2.0)), 
    (Path.MOVETO, (0.85, 1.15)), 
    (Path.MOVETO, (2.2, 3.2)), 
    (Path.MOVETO, (3, 0.05)), 
    (Path.MOVETO, (2.0, -0.5)), 
    #(Path.CLOSEPOLY, (1.58, -2.57)), 
    ] 

codes, verts = zip(*pathdata) 
path = mpath.Path(verts, codes) 
patch = mpatches.PathPatch(path, facecolor='green', edgecolor='yellow', alpha=0.5) 
ax.add_patch(patch) 


class PathInteractor(object): 
    """ 
    An path editor. 

    Key-bindings 

     't' toggle vertex markers on and off. When vertex markers are on, 
      you can move them, delete them 


    """ 

    showverts = True 
    epsilon = 5 # max pixel distance to count as a vertex hit 

    def __init__(self, pathpatch): 

     self.ax = pathpatch.axes 
     canvas = self.ax.figure.canvas 
     self.pathpatch = pathpatch 
     self.pathpatch.set_animated(True) 

     x, y = zip(*self.pathpatch.get_path().vertices) 

     self.line, = ax.plot(x, y, marker='o', markerfacecolor='r', animated=True) 
     self.line.set_markerfacecolor((1, 1, 0, 0)) 

     self._ind = None # the active vert 

     canvas.mpl_connect('draw_event', self.draw_callback) 
     canvas.mpl_connect('button_press_event', self.button_press_callback) 
     canvas.mpl_connect('key_press_event', self.key_press_callback) 
     canvas.mpl_connect('button_release_event', self.button_release_callback) 
     canvas.mpl_connect('motion_notify_event', self.motion_notify_callback) 
     self.canvas = canvas 

    def draw_callback(self, event): 
     self.background = self.canvas.copy_from_bbox(self.ax.bbox) 
     self.ax.draw_artist(self.pathpatch) 
     self.ax.draw_artist(self.line) 
     self.canvas.blit(self.ax.bbox) 

    def pathpatch_changed(self, pathpatch): 
     'this method is called whenever the pathpatchgon object is called' 
     # only copy the artist props to the line (except visibility) 
     vis = self.line.get_visible() 
     plt.Artist.update_from(self.line, pathpatch) 
     self.line.set_visible(vis) # don't use the pathpatch visibility state 

    def get_ind_under_point(self, event): 
     'get the index of the vertex under point if within epsilon tolerance' 

     # display coords 
     xy = np.asarray(self.pathpatch.get_path().vertices) 
     xyt = self.pathpatch.get_transform().transform(xy) 
     xt, yt = xyt[:, 0], xyt[:, 1] 
     d = np.sqrt((xt - event.x)**2 + (yt - event.y)**2) 
     ind = d.argmin() 

     if d[ind] >= self.epsilon: 
      ind = None 

     return ind 

    def button_press_callback(self, event): 
     'whenever a mouse button is pressed' 
     if not self.showverts: 
      return 
     if event.inaxes is None: 
      return 
     if event.button != 1: 
      return 
     self._ind = self.get_ind_under_point(event) 

    def button_release_callback(self, event): 
     'whenever a mouse button is released' 
     if not self.showverts: 
      return 
     if event.button != 1: 
      return 
     self._ind = None 

    def key_press_callback(self, event): 
     'whenever a key is pressed' 
     if not event.inaxes: 
      return 
     if event.key == 't': 
      self.showverts = not self.showverts 
      self.line.set_visible(self.showverts) 
      if not self.showverts: 
       self._ind = None 

     self.canvas.draw() 

    def motion_notify_callback(self, event): 
     'on mouse movement' 
     if not self.showverts: 
      return 
     if self._ind is None: 
      return 
     if event.inaxes is None: 
      return 
     if event.button != 1: 
      return 
     x, y = event.xdata, event.ydata 

     vertices = self.pathpatch.get_path().vertices 

     vertices[self._ind] = x, y 
     self.line.set_data(zip(*vertices)) 

     self.canvas.restore_region(self.background) 
     self.ax.draw_artist(self.pathpatch) 
     self.ax.draw_artist(self.line) 
     self.canvas.blit(self.ax.bbox) 


interactor = PathInteractor(patch) 
ax.set_title('drag vertices to update path') 
ax.set_xlim(-3, 4) 
ax.set_ylim(-3, 4) 

plt.show() 

あなたが考慮に特別に取る必要がある行はこれです:

self.line.set_markerfacecolor((1, 1, 0, 0)) 

それは右plotの定義の後__init__機能にあります。最後の数字はアルファチャンネルです。私はゼロにしました。プロット自体は次のようになります。あなたが種類の彼らがどこにあるかを推測する必要がありますが、

Dragging line using transparent markers in matplotlib

Anはあなたがラインマーカーをドラッグすることができます(私はあなたがこのために飛行機を持っていると仮定します)。

いずれの場合でも、この例を使用する場合は、ラインデータをパスに変換してください。

EDIT:(同様にそれ完全な例になるかもしれない)私はちょうどあなたにこのパス構築を行う方法の一例を挙げてみましょう:

import numpy as np 

def buildpath(x,y): 
    path = [] 
    for i in range(len(x)): 
     path.append((Path.MOVETO, (x[i], y[i]))) 
    return path 

x = np.linspace(-2,2,5) 
y = x*1 
pathdata = buildpath(x,y) 

あなたpathdata(ビルドするためにこれを使用する場合残りのコードは同じです)numpy配列を使用してパーソナライズされたパスを取得する必要があります(通常はmatplotlibのplotコマンドを使用します)。

関連する問題