2016-11-16 13 views
1

matplotlibを使用して3Dツリーをグラフ化しようとしています。私は、ユーザが各ノードをドラッグできるようにして、自分が選んだ方法でツリーを見ることができるようにしたい。私の計画は、ノードにデータを追加してツリーを作成するために最終的にサブクラス化することです。matplotlibの三角点を更新する

ノードをドラッグしている間にグラフの更新に問題があります。

self.plot.set_offsets([x,y]) 
self.plot.set_3d_properties([z], 'z') 

しかし、また矢筒の位置とベクトルを更新する方法を見つけるように見えることはできませんが。私は使用して散布ポイントの位置を更新する方法を発見しました。

私は、現在、私はいつも見つけるマウス位置の取得で問題が午前:

ecoor == {'elevation': 30.0, 'azimuth': -60.0} 

EDIT:ImportanceOfBeingErnestのおかげではなく、私はそれを削除し、新しいものを作ったプロットを更新しようとします。ここで

# PlotNode._plot changes 
self.plot.remove() 
self.plot = axes.scatter([x], [y], [z]) 

# PlotInterNode._plot changes (both vector updates) 
arlen=length(xc - x, yc - y, zc - z) 
edge.remove() 
edge = axes.quiver(x, y, z, xc - x, yc - y, zc - z, length=arlen, 
        arrow_length_ratio=.5/arlen, pivot='tail') 
self.edges.update({childname:(childnode, edge)}) 

は元のコードです:

import math 
from matplotlib import pyplot 
from mpl_toolkits.mplot3d import Axes3D 

class PlotNode(object): 
    """ 
    Class for graph node. 
    """ 

    def __init__(self, name, parent): 
     """ 
     Initializes PlotNode. 
     """ 
     self.__name__ = name 
     self.parent = parent 
     self.coordinates = self._make_coordinates() 
     x, y, z = self.coordinates 
     self.plot = axes.scatter([x], [y], [z]) 
     self.pressed = False 
     self.move = False 

    def name(self): 
     return self.__name__ 

    COOR = (0, 0, 0) 
    def _make_coordinates(self): 
     """ 
     Finds coordinates from a file or, if not exist, calculate new coordinates. 
     """ 
     if PlotNode.COOR[1] == PlotNode.COOR[0]: 
      PlotNode.COOR = (PlotNode.COOR[0] + 1, 0, 0) 
     elif PlotNode.COOR[2] == PlotNode.COOR[1]: 
      PlotNode.COOR = (PlotNode.COOR[0], PlotNode.COOR[1] + 1, 0) 
     else: 
      PlotNode.COOR = (PlotNode.COOR[0], PlotNode.COOR[1], PlotNode.COOR[2] + 1) 
     return (PlotNode.COOR[0], PlotNode.COOR[1], PlotNode.COOR[2]) 

    def _plot(self): 
     """ 
     Plots node onto graph. 
     """ 
     x, y, z = self.coordinates 
     #updates the plot coordinates 
     self.plot.set_offsets([x,y]) 
     self.plot.set_3d_properties([z], 'z') 
     #updates the parent 
     if self.parent: 
      self.parent._plot(self.name()) 
     self.plot.figure.canvas.draw() 

    def press(self, event): 
     """ 
     Mouse press event. 
     """ 
     if event.inaxes != self.plot.axes or not self.plot.contains(event)[0]: 
      return False 
     self.pressed = True 
     axes.disable_mouse_rotation() #Make sure node moves instead of plot rotation 
     return True 

    def release(self, event): 
     """ 
     Mouse release event. 
     """ 
     if event.inaxes != self.plot.axes or not self.pressed: 
      return False 
     self.pressed = False 
     if self.move: 
      self.move = False 
      x, y, z = self.coordinates 
      ecoor = to_dict(axes.format_coord(event.xdata, event.ydata)) 
      xe, ye, ze = ecoor.get('x', x), ecoor.get('y', y), ecoor.get('z', z) 
      self.coordinates = (xe, ye, ze) 
      self._plot() 
     else: 
      self.open() 
     axes.mouse_init() #Make plot rotation avaliable again 
     return True 

    def motion(self, event): 
     """ 
     Mouse motion event. 
     """ 
     if event.inaxes != self.plot.axes or not self.plot.contains(event)[0]: 
      return False 
     if not self.pressed: 
      return False 
     self.move = True 
     x, y, z = self.coordinates 
     ecoor = to_dict(axes.format_coord(event.xdata, event.ydata)) 
     xe, ye, ze = ecoor.get('x', x), ecoor.get('y', y), ecoor.get('z', z) 
     self.coordinates = (xe, ye, ze) 
     self._plot() 
     return True 

    def open(self): 
     print('openned!') #to be changed 

class PlotInterNode(PlotNode): 
    """ 
    Class for graph folder node. 
    """ 
    def __init__(self, name, parent=None): 
     """ 
     Initializes PlotDir. 
     """ 
     self.edges = {} 
     PlotNode.__init__(self, name, parent) 

    def _plot(self, childname=None): 
     """ 
     Plots node onto graph. 
     """ 
     if childname: 
      x, y, z = self.coordinates 
      childnode, edge = self.edges.get(childname) 
      xc, yc, zc = childnode.coordinates 
      ##update the vector 
      arlen=length(xc - x, yc - y, zc - z) 
      ##update the arrow length 
     else: 
      x, y, z = self.coordinates 
      for childname in self.edges: 
       _, edge = self.edges.get(childname) 
       ##update the position of each edge 
      super()._plot() 
     self.plot.figure.canvas.draw() 

    def traverse(self): 
     """ 
     Generator that traverses the tree rooted at this node. 
     """ 
     yield self 
     for child in self.edges: 
      try: 
       for node in self.edges.get(child)[0].traverse(): 
        yield node 
      except AttributeError: 
       yield self.edges.get(child)[0] 


def select_node(root, event): 
    """ 
    Single event function to handle all node movement. 
    """ 
    if event.name == 'button_press_event': 
     event_fn = lambda self: PlotNode.press(self, event) 
    elif event.name == 'button_release_event': 
     event_fn = lambda self: PlotNode.release(self, event) 
    elif event.name == 'motion_notify_event': 
     event_fn = lambda self: PlotNode.motion(self, event) 
    for node in root.traverse(): 
     if event_fn(node): 
      return #if act on node then end 

select_ids = [] 
def connect_select(root): 
    """ 
    Connects select_node to events. 
    """ 
    select_ids.append(figure.canvas.mpl_connect('button_press_event', lambda event: select_node(root, event))) 
    select_ids.append(figure.canvas.mpl_connect('button_release_event', lambda event: select_node(root, event))) 
    select_ids.append(figure.canvas.mpl_connect('motion_notify_event', lambda event: select_node(root, event))) 

def to_dict(string): 
    """ 
    Converts a string to a dictionary. 
    """ 
    dictionary = {} 
    for st in string.split(','): 
     st = st.strip().split('=') 
     if st[0] not in dictionary: 
      try: 
       dictionary.update({st[0]:float(st[1])}) 
      except ValueError: 
       st[1] = st[1].split(' ')[0] 
       dictionary.update({st[0]:float(st[1])}) 
    return dictionary 

def length(x, y, z): 
    """ 
    Returns hypotenuse. 
    """ 
    ret = math.sqrt(math.pow(x, 2) + math.pow(y, 2) + math.pow(z, 2)) 
    if not ret: 
     ret = 1 
    return ret 

figure = pyplot.figure() 
axes = figure.add_subplot(111, projection='3d') 
root = PlotInterNode('root') 
def make_children(node, child_type, number): 
    x, y, z = node.coordinates 
    for i in range(number): 
     child = child_type(str(i), node) 
     xc, yc, zc = child.coordinates 
     arlen = length(xc - x, yc - y, zc - z) 
     edge = axes.quiver(x, y, z, xc - x, yc - y, zc - z, length=arlen, arrow_length_ratio=.5/arlen, pivot='tail') 
     node.edges.update({child.name():(child, edge)}) 
def node_depth(node, depth): 
    if not depth: 
     make_children(node, PlotNode, 3) 
    else: 
     make_children(node, PlotInterNode, 3) 
     for child in node.edges: 
      node_depth(node.edges.get(child)[0], depth-1) 
node_depth(root, 3) 
connect_select(root) 
pyplot.show() 

編集:私は

axes.format_coord(event.xdata, event.ydata) 
+0

矢筒にだけコメントを呼ばれる前に、私は3Dでマウスの位置を取得するために必要なすべてが

axes.button_pressed = None 

を追加しました更新することはできません。私は唯一の解決策は毎回それらを再描画することだと思います。 – ImportanceOfBeingErnest

+0

ああ、それはその後dissapointingです:( ありがとう!ありがとう! – carrvo

答えて

0
と呼ばれる前に、私は3Dでマウスの位置を取得するために必要なすべてが

axes.button_pressed = None 

を追加しました

ImportanceOfBeingErnestのおかげで私はそれを削除し、新しいものを作ったプロットを更新しようとしています。第二部のために

# PlotNode._plot changes 
self.plot.remove() 
self.plot = axes.scatter([x], [y], [z]) 

# PlotInterNode._plot changes (both vector updates) 
arlen=length(xc - x, yc - y, zc - z) 
edge.remove() 
edge = axes.quiver(x, y, z, xc - x, yc - y, zc - z, length=arlen, 
       arrow_length_ratio=.5/arlen, pivot='tail') 
self.edges.update({childname:(childnode, edge)}) 

:一般的には:
私は

axes.format_coord(event.xdata, event.ydata) 
関連する問題