From 61891e86beb0d2b7fe2d904cb73b4272fd96fa09 Mon Sep 17 00:00:00 2001
From: m-guberina <gubi.guberina@gmail.com>
Date: Mon, 27 Nov 2023 12:58:54 +0100
Subject: [PATCH] more changes

---
 .../manipulator_visual_motion_analyzer.py     | 433 +++++++++---------
 1 file changed, 211 insertions(+), 222 deletions(-)

diff --git a/python/ur_simple_control/visualize/manipulator_visual_motion_analyzer.py b/python/ur_simple_control/visualize/manipulator_visual_motion_analyzer.py
index 11fb982..1442111 100644
--- a/python/ur_simple_control/visualize/manipulator_visual_motion_analyzer.py
+++ b/python/ur_simple_control/visualize/manipulator_visual_motion_analyzer.py
@@ -148,16 +148,16 @@ class ManipulatorVisualMotionAnalyzer:
         #  LAYOUT OF THE GUI                                #
         # putting plots into: frames -> notebooks -> tabs   #
         #####################################################
-        self.notebook_left = Notebook(root, height=int(SCREEN_HEIGHT))
-        self.notebook_right = Notebook(root, height=int(SCREEN_HEIGHT))
-        self.frame_manipulator = Frame(notebook_left)
-        self.frame_manip_graphs = Frame(notebook_right)
-        self.frame_imu = Frame(notebook_right)
-        self.frame_ee = Frame(notebook_left)
-        self.tabs_left = notebook_left.add(frame_manipulator, text='manipulator')
-        self.tabs_left = notebook_left.add(frame_ee, text="end-effector")
-        self.tabs_right = notebook_right.add(frame_manip_graphs, text='manipulator-graphs')
-        self.tabs_right = notebook_right.add(frame_imu, text="ee-graphs")
+        self.notebook_left = Notebook(root, height=int(self.SCREEN_HEIGHT))
+        self.notebook_right = Notebook(root, height=int(self.SCREEN_HEIGHT))
+        self.frame_manipulator = Frame(self.notebook_left)
+        self.frame_manip_graphs = Frame(self.notebook_right)
+        self.frame_imu = Frame(self.notebook_right)
+        self.frame_ee = Frame(self.notebook_left)
+        self.tabs_left = self.notebook_left.add(self.frame_manipulator, text='manipulator')
+        self.tabs_left = self.notebook_left.add(self.frame_ee, text="end-effector")
+        self.tabs_right = self.notebook_right.add(self.frame_manip_graphs, text='manipulator-graphs')
+        self.tabs_right = self.notebook_right.add(self.frame_imu, text="ee-graphs")
         self.notebook_left.grid(row=0, column=0, sticky='ew')
         self.notebook_right.grid(row=0, column=1, sticky='ew')
         
@@ -201,6 +201,11 @@ class ManipulatorVisualMotionAnalyzer:
         self.fig_ee = Figure(figsize=(SCREEN_WIDTH/DPI*SCALING_FACTOR_WIDTH, SCREEN_HEIGHT/DPI*SCALING_FACTOR_HEIGHT), dpi=DPI)
         self.rec3D_ax = self.fig_ee.add_subplot(projection='3d') 
         self.rec3D_ax.set(xticklabels=[], yticklabels=[], zticklabels=[])
+        self.canvas_ee = FigureCanvasTkAgg(self.fig_ee, master=self.frame_ee) 
+        self.canvas_ee_widget = self.canvas_ee.get_tk_widget()     
+        self.canvas_ee_widget.grid(row=0, column=0) 
+        self.canvas_ee._tkcanvas.grid(row=1, column=0)   
+        self.canvas_ee.draw()
 
         #######################################################################
         #                          MANIPULATOR PLOT                           #
@@ -252,6 +257,21 @@ class ManipulatorVisualMotionAnalyzer:
                             color='pink', linewidth=0.1,
                             alpha=0.3, shade=True))
 
+        # tkinterize the figure/canvas
+        self.canvas_manipulator = FigureCanvasTkAgg(self.fig_manipulator, master=self.frame_manipulator) 
+        # need to hit it with the first draw before saving background
+        self.canvas_manipulator.draw()
+        # save background - in manual blitting you reload and update yourself
+        self.background_manipulator = self.canvas_manipulator.copy_from_bbox(self.fig_manipulator.bbox)
+        # take and put the matplotlib toolbar below the plot.
+        # these are quite nifty (zooming, adjusting axes etc)
+        self.canvas_manipulator_widget = self.canvas_manipulator.get_tk_widget()     
+        self.canvas_manipulator_widget.grid(row=0, column=0) 
+        self.canvas_manipulator._tkcanvas.grid(row=1, column=0)   
+        # i probably don't need this draw, but who cares
+        self.canvas_manipulator.draw()
+
+
         #######################################################################
         #                        manipulability plots                         #
         #######################################################################
@@ -298,6 +318,13 @@ class ManipulatorVisualMotionAnalyzer:
             dist_to_goal_lines.append(dist_to_goal_line)
         # TODO: blit this line
         self.point_in_time_dist_to_goal_line = ax.axvline(x=0, color='red')
+        # tkinterize canvas
+        self.canvas_manip_graphs = FigureCanvasTkAgg(self.fig_manip_graphs, master=self.frame_manip_graphs) 
+        # put matplotlib toolbar below the plot
+        self.canvas_manip_graphs_widget = self.canvas_manip_graphs.get_tk_widget()     
+        self.canvas_manip_graphs_widget.grid(row=0, column=0) 
+        self.canvas_manip_graphs._tkcanvas.grid(row=1, column=0)   
+        self.canvas_manip_graphs.draw()
 
 
         #######################################################################
@@ -357,220 +384,28 @@ class ManipulatorVisualMotionAnalyzer:
         self.point_in_time_ax_omega_y_line = ax_omega_y.axvline(x=0, color='red')
         self.point_in_time_ax_omega_z_line = ax_omega_z.axvline(x=0, color='red')
 
+        self.canvas_imu = FigureCanvasTkAgg(self.fig_imu, master=self.frame_imu) 
+        self.canvas_imu_widget = self.canvas_manip_graphs.get_tk_widget()     
+        self.canvas_imu_widget.grid(row=0, column=0) 
+        self.canvas_imu._tkcanvas.grid(row=1, column=0)   
+        self.canvas_imu.draw()
+
+        # i don't even remember what these toolbars are lol
+        # pack_toolbar=False will make it easier to use a layout manager later on.
+        toolbar_manipulator = NavigationToolbar2Tk(canvas_manipulator, frame_manipulator, pack_toolbar=False)
+        toolbar_manipulator.update()
+        toolbar_manipulator.grid(column=0, row=2)
+        toolbar_manip_graphs = NavigationToolbar2Tk(canvas_manip_graphs, frame_manip_graphs, pack_toolbar=False)
+        toolbar_manip_graphs.update()
+        toolbar_manip_graphs.grid(column=0, row=2)
+        toolbar_ee = NavigationToolbar2Tk(canvas_ee, frame_ee, pack_toolbar=False)
+        toolbar_ee.update()
+        toolbar_ee.grid(column=0, row=2)
+        toolbar_imu = NavigationToolbar2Tk(canvas_imu, frame_imu, pack_toolbar=False)
+        toolbar_imu.update()
+        toolbar_imu.grid(column=0, row=2)
 
 
-# tkinterize these plots
-canvas_manipulator = FigureCanvasTkAgg(fig_manipulator, master=frame_manipulator) 
-canvas_manipulator.draw()
-# NEW
-# TODO maybe you want another background idk
-# worked elsewhere with figure.bbox
-background_manipulator = canvas_manipulator.copy_from_bbox(fig_manipulator.bbox)
-#background_manipulator = canvas_manipulator.copy_from_bbox(canvas_manipulator.bbox)
-
-canvas_manipulator_widget = canvas_manipulator.get_tk_widget()     
-canvas_manipulator_widget.grid(row=0, column=0) 
-canvas_manipulator._tkcanvas.grid(row=1, column=0)   
-canvas_manipulator.draw()
-
-canvas_ee = FigureCanvasTkAgg(fig_ee, master=frame_ee) 
-canvas_ee_widget = canvas_ee.get_tk_widget()     
-canvas_ee_widget.grid(row=0, column=0) 
-canvas_ee._tkcanvas.grid(row=1, column=0)   
-canvas_ee.draw()
-
-canvas_manip_graphs = FigureCanvasTkAgg(fig_manip_graphs, master=frame_manip_graphs) 
-canvas_manip_graphs_widget = canvas_manip_graphs.get_tk_widget()     
-canvas_manip_graphs_widget.grid(row=0, column=0) 
-canvas_manip_graphs._tkcanvas.grid(row=1, column=0)   
-canvas_manip_graphs.draw()
-
-canvas_imu = FigureCanvasTkAgg(self.fig_imu, master=frame_imu) 
-canvas_imu_widget = canvas_manip_graphs.get_tk_widget()     
-canvas_imu_widget.grid(row=0, column=0) 
-canvas_imu._tkcanvas.grid(row=1, column=0)   
-canvas_imu.draw()
-
-# pack_toolbar=False will make it easier to use a layout manager later on.
-toolbar_manipulator = NavigationToolbar2Tk(canvas_manipulator, frame_manipulator, pack_toolbar=False)
-toolbar_manipulator.update()
-toolbar_manipulator.grid(column=0, row=2)
-toolbar_manip_graphs = NavigationToolbar2Tk(canvas_manip_graphs, frame_manip_graphs, pack_toolbar=False)
-toolbar_manip_graphs.update()
-toolbar_manip_graphs.grid(column=0, row=2)
-toolbar_ee = NavigationToolbar2Tk(canvas_ee, frame_ee, pack_toolbar=False)
-toolbar_ee.update()
-toolbar_ee.grid(column=0, row=2)
-toolbar_imu = NavigationToolbar2Tk(canvas_imu, frame_imu, pack_toolbar=False)
-toolbar_imu.update()
-toolbar_imu.grid(column=0, row=2)
-
-#######################################################################
-#                 functions for widgets to control the plots          #
-#######################################################################
-
-# keyboard inputs
-# whatever, doesn't hurt, could be used
-#canvas.mpl_connect(
-#    "key_press_event", lambda event: print(f"you pressed {event.key}"))
-#canvas.mpl_connect("key_press_event", key_press_handler)
-
-# new_val is what the widget gives you
-# you define what needs to happen to plots in Figure below,
-# and call canvas.draw
-def update_points(new_val):
-# ee plot
-###########################################################################
-    start = ttime.time()
-    #fig_manipulator.canvas.restore_region(background_manipulator)
-    canvas_manipulator.restore_region(background_manipulator)
-    index = int(np.floor(float(new_val)))
-    
-    # Update 3D reconstruction plot
-    # plot3D_camera(recP[index], scale=scale)
-#    C, Q = camera_data_for_plot3D(recP[cam_indices[index]])
-#    camera_center.set_data_3d(*C)
-#    C = C.flatten()
-#    for ii in range(len(camera_coordinate_system)):
-#        camera_coordinate_system[ii].set_data([C[0], C[0] + scale * Q[0,ii]],
-#                                              [C[1], C[1] + scale * Q[1,ii]])
-#        camera_coordinate_system[ii].set_3d_properties([C[2], C[2] + scale * Q[2,ii]])
-#    recX_ = recX[:,X_indices[:num_pts_subset*(index+1)]]
-#    rec_points3D.set_data_3d(recX_[0,:], recX_[1,:], recX_[2,:])
-###########################################################################
-
-    ik_env.ax.set_title(str(index) + 'th iteration toward goal')
-    # animate 3d manipulator
-    for robot_index, robot in enumerate(ik_env.robots):
-        ik_env.robots[robot_index].setJoints(ik_env.data[robot_index]["qs"][index])
-        ik_env.robots[robot_index].drawStateAnim()
-
-    # NEW AND BROKEN
-        for link in robot.lines:
-            for line in link:
-                ik_env.ax.draw_artist(line)
-        # all these are in lists as that's what the line plot wants, 
-        # despite the fact that we have single points
-        point_in_time_eigen1_line.set_xdata([time[index]])
-        point_in_time_manip_index_line.set_xdata([time[index]])
-        point_in_time_dist_to_goal_line.set_xdata([time[index]])
-        point_in_time_ax_v_x_line.set_xdata([time[index]])
-        point_in_time_ax_v_y_line.set_xdata([time[index]])
-        point_in_time_ax_v_z_line.set_xdata([time[index]])
-        point_in_time_ax_omega_x_line.set_xdata([time[index]])
-        point_in_time_ax_omega_y_line.set_xdata([time[index]])
-        point_in_time_ax_omega_z_line.set_xdata([time[index]])
-
-        # ellipsoid update
-        radii = 1.0/ik_env.data[robot_index]["manip_ell_eigenvals"][index] * 0.1
-        u = np.linspace(0.0, 2.0 * np.pi, 60)     
-        v = np.linspace(0.0, np.pi, 60)     
-        x = radii[0] * np.outer(np.cos(u), np.sin(v))     
-        y = radii[1] * np.outer(np.sin(u), np.sin(v))     
-        z = radii[2] * np.outer(np.ones_like(u), np.cos(v))
-        for i in range(len(x)):         
-            for j in range(len(x)):
-                [x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], ik_env.data[robot_index]["manip_elip_svd_rots"][index]) + ik_env.data[robot_index]['p_es'][index]
-
-        if ellipse_on_off_var.get():
-            try:
-                ik_env.ellipsoid_surf_plots[robot_index].remove()
-            except ValueError:
-                pass
-            ik_env.ellipsoid_surf_plots[robot_index] = ik_env.ax.plot_surface(x, y, z,  rstride=3, cstride=3,
-                            color='pink', linewidth=0.1,
-                            alpha=0.3, shade=True) 
-
-        ik_env.p_e_point_plots[robot_index].set_data([ik_env.data[robot_index]['p_es'][index][0]], [ik_env.data[robot_index]['p_es'][index][1]])
-        ik_env.p_e_point_plots[robot_index].set_3d_properties([ik_env.data[robot_index]['p_es'][index][2]])
-    canvas_ee.draw()
-    # NEW AND BROKEN
-#    fig_manipulator.canvas.blit(fig_manipulator.bbox)
-#    fig_manipulator.canvas.flush_events()
-    canvas_manipulator.blit(fig_manipulator.bbox)
-    canvas_manipulator.flush_events()
-    #canvas_manipulator.draw()
-    # might need to manually update all artists here from ax_something
-    #canvas_manipulator.blit(fig_manipulator.bbox)
-    canvas_manip_graphs.draw()
-    canvas_imu.draw()
-    # TODO update may not be needed as we're going by slider here
-    root.update()
-    end = ttime.time()
-    print("time per update:", end - start)
-    print("fps", 1 / (end - start))
-
-
-def update_goal_x(new_val):
-    goal_x = float(new_val)
-    ik_env.goal[0] = goal_x
-    ik_env.goal_point_plot.set_data([ik_env.goal[0]], [ik_env.goal[1]])
-    ik_env.goal_point_plot.set_3d_properties([ik_env.goal[2]])
-    canvas_ee.draw()
-    canvas_manipulator.draw()
-    canvas_manip_graphs.draw()
-    # TODO update may not be needed as we're going by slider here
-    root.update()
-
-def update_goal_y(new_val):
-    goal_y = float(new_val)
-    ik_env.goal[1] = goal_y
-    ik_env.goal_point_plot.set_data([ik_env.goal[0]], [ik_env.goal[1]])
-    ik_env.goal_point_plot.set_3d_properties([ik_env.goal[2]])
-    canvas_ee.draw()
-    canvas_manipulator.draw()
-    canvas_manip_graphs.draw()
-    # TODO update may not be needed as we're going by slider here
-    root.update()
-
-def update_goal_z(new_val):
-    goal_z = float(new_val)
-    ik_env.goal[2] = goal_z
-    ik_env.goal_point_plot.set_data([ik_env.goal[0]], [ik_env.goal[1]])
-    ik_env.goal_point_plot.set_3d_properties([ik_env.goal[2]])
-    canvas_ee.draw()
-    canvas_manipulator.draw()
-    canvas_manip_graphs.draw()
-    # TODO update may not be needed as we're going by slider here
-    root.update()
-
-
-
-def reset():
-    ik_env.reset()
-#    ik_env.goal_point_plot.remove()
-#    ik_env.goal_point_plot = drawPoint(ik_env.ax, ik_env.goal, 'red', 'o')
-#    print(controller_string1.get())
-#    print(controller_string2.get())
-    controller1 = getController(controller_string1.get())
-    controller2 = getController(controller_string2.get())
-    controllers = [controller1, controller2]
-    for robot_index, robot in enumerate(ik_env.robots):
-        ik_env.data.append(makeRun(controllers[robot_index], ik_env, n_iters, robot_index))
-        trajectory_plots[robot_index].set_data(ik_env.data[robot_index]['p_es'][:,0], ik_env.data[robot_index]['p_es'][:,1])
-        trajectory_plots[robot_index].set_3d_properties(ik_env.data[robot_index]['p_es'][:,2])
-        eigen1_lines[robot_index].set_ydata(ik_env.data[robot_index]["manip_ell_eigenvals"][:,0])
-        eigen2_lines[robot_index].set_ydata(ik_env.data[robot_index]["manip_ell_eigenvals"][:,1])
-        eigen3_lines[robot_index].set_ydata(ik_env.data[robot_index]["manip_ell_eigenvals"][:,2])
-        manip_index_lines[robot_index].set_ydata(ik_env.data[robot_index]['manip_indeces'])
-        dist_to_goal_lines[robot_index].set_ydata(ik_env.data[robot_index]['dists_to_goal'])
-    update_points(0)
-    canvas_ee.draw()
-    canvas_manipulator.draw()
-    canvas_manip_graphs.draw()
-    root.update()
-
-def play():
-    pass
-
-# ellipse on/off
-def add_remove_ellipse():
-    try:
-        for robot_index, robot in enumerate(ik_env.robots):
-            ik_env.ellipsoid_surf_plots[robot_index].remove()
-    except ValueError:
-        pass
-
 
 # NOTE: this thing is not used
 same_starting_position_on_off_var = IntVar()   
@@ -586,6 +421,7 @@ same_starting_position_checkbutton= Checkbutton(root, text = "same starting posi
 #######################################################################
 #                     PLACING ELEMENTS IN THE GUI                     #
 #######################################################################
+ # TODO put this into init
 
 # LEFT PANE BELOW MANIP/EE PLOTS
 frame_below_manipulator_plot = Frame(frame_manipulator)
@@ -697,6 +533,159 @@ slider_goal_x.set(ik_env.goal[0])
 slider_goal_y.set(ik_env.goal[1])
 slider_goal_z.set(ik_env.goal[2])
 
+
+
+#######################################################################
+#                 functions for widgets to control the plots          #
+#######################################################################
+
+# keyboard inputs
+# whatever, doesn't hurt, could be used
+#canvas.mpl_connect(
+#    "key_press_event", lambda event: print(f"you pressed {event.key}"))
+#canvas.mpl_connect("key_press_event", key_press_handler)
+
+# new_val is what the widget gives you
+# you define what needs to happen to plots in Figure below,
+# and call canvas.draw
+    def update_points(self, new_val):
+        start = ttime.time()
+        #fig_manipulator.canvas.restore_region(background_manipulator)
+        self.canvas_manipulator.restore_region(self.background_manipulator)
+        index = int(np.floor(float(new_val)))
+        # ee plot here, but NOTE: UNUSED
+
+        self.ik_env.ax.set_title(str(index) + 'th iteration toward goal')
+        # animate 3d manipulator
+        for robot_index, robot in enumerate(self.ik_env.robots):
+            self.ik_env.robots[robot_index].setJoints(self.ik_env.data[robot_index]["qs"][index])
+            self.ik_env.robots[robot_index].drawStateAnim()
+
+        # NEW AND BROKEN
+            for link in robot.lines:
+                for line in link:
+                    self.ik_env.ax.draw_artist(line)
+            # all these are in lists as that's what the line plot wants, 
+            # despite the fact that we have single points
+            self.point_in_time_eigen1_line.set_xdata([time[index]])
+            self.point_in_time_manip_index_line.set_xdata([time[index]])
+            self.point_in_time_dist_to_goal_line.set_xdata([time[index]])
+            self.point_in_time_ax_v_x_line.set_xdata([time[index]])
+            self.point_in_time_ax_v_y_line.set_xdata([time[index]])
+            self.point_in_time_ax_v_z_line.set_xdata([time[index]])
+            self.point_in_time_ax_omega_x_line.set_xdata([time[index]])
+            self.point_in_time_ax_omega_y_line.set_xdata([time[index]])
+            self.point_in_time_ax_omega_z_line.set_xdata([time[index]])
+
+            # ellipsoid update
+            radii = 1.0/self.ik_env.data[robot_index]["manip_ell_eigenvals"][index] * 0.1
+            u = np.linspace(0.0, 2.0 * np.pi, 60)     
+            v = np.linspace(0.0, np.pi, 60)     
+            x = radii[0] * np.outer(np.cos(u), np.sin(v))     
+            y = radii[1] * np.outer(np.sin(u), np.sin(v))     
+            z = radii[2] * np.outer(np.ones_like(u), np.cos(v))
+            for i in range(len(x)):         
+                for j in range(len(x)):
+                    [x[i,j],y[i,j],z[i,j]] = np.dot([x[i,j],y[i,j],z[i,j]], self.ik_env.data[robot_index]["manip_elip_svd_rots"][index]) + self.ik_env.data[robot_index]['p_es'][index]
+
+            if self.ellipse_on_off_var.get():
+                try:
+                    self.ik_env.ellipsoid_surf_plots[robot_index].remove()
+                except ValueError:
+                    pass
+                self.ik_env.ellipsoid_surf_plots[robot_index] = self.ik_env.ax.plot_surface(x, y, z,  rstride=3, cstride=3,
+                                color='pink', linewidth=0.1,
+                                alpha=0.3, shade=True) 
+
+            self.ik_env.p_e_point_plots[robot_index].set_data([ik_env.data[robot_index]['p_es'][index][0]], [ik_env.data[robot_index]['p_es'][index][1]])
+            self.ik_env.p_e_point_plots[robot_index].set_3d_properties([ik_env.data[robot_index]['p_es'][index][2]])
+        # TODO: blit the rest
+        canvas_manipulator.blit(fig_manipulator.bbox)
+        canvas_manipulator.flush_events()
+        canvas_manip_graphs.draw()
+        # non blitted (bad)
+        canvas_imu.draw()
+        self.canvas_ee.draw()
+        # TODO update may not be needed as we're going by slider here
+        root.update()
+        end = ttime.time()
+        print("time per update:", end - start)
+        print("fps", 1 / (end - start))
+
+
+    def update_goal_x(self, new_val):
+        goal_x = float(new_val)
+        self.ik_env.goal[0] = goal_x
+        self.ik_env.goal_point_plot.set_data([self.ik_env.goal[0]], [self.ik_env.goal[1]])
+        self.ik_env.goal_point_plot.set_3d_properties([self.ik_env.goal[2]])
+        self.canvas_ee.draw()
+        self.canvas_manipulator.draw()
+        self.canvas_manip_graphs.draw()
+        # TODO update may not be needed as we're going by slider here
+        self.root.update()
+
+    def update_goal_y(self, new_val):
+        goal_y = float(new_val)
+        self.ik_env.goal[1] = goal_y
+        self.ik_env.goal_point_plot.set_data([self.ik_env.goal[0]], [self.ik_env.goal[1]])
+        self.ik_env.goal_point_plot.set_3d_properties([self.ik_env.goal[2]])
+        self.canvas_ee.draw()
+        self.canvas_manipulator.draw()
+        self.canvas_manip_graphs.draw()
+        # TODO update may not be needed as we're going by slider here
+        self.root.update()
+
+    def update_goal_z(self, new_val):
+        goal_z = float(new_val)
+        self.ik_env.goal[2] = goal_z
+        self.ik_env.goal_point_plot.set_data([self.ik_env.goal[0]], [self.ik_env.goal[1]])
+        self.ik_env.goal_point_plot.set_3d_properties([self.ik_env.goal[2]])
+        self.canvas_ee.draw()
+        self.canvas_manipulator.draw()
+        self.canvas_manip_graphs.draw()
+        # TODO update may not be needed as we're going by slider here
+        self.root.update()
+
+
+
+# TODO fix
+    def reset():
+        ik_env.reset()
+    #    ik_env.goal_point_plot.remove()
+    #    ik_env.goal_point_plot = drawPoint(ik_env.ax, ik_env.goal, 'red', 'o')
+    #    print(controller_string1.get())
+    #    print(controller_string2.get())
+        controller1 = getController(controller_string1.get())
+        controller2 = getController(controller_string2.get())
+        controllers = [controller1, controller2]
+        for robot_index, robot in enumerate(ik_env.robots):
+            ik_env.data.append(makeRun(controllers[robot_index], ik_env, n_iters, robot_index))
+            trajectory_plots[robot_index].set_data(ik_env.data[robot_index]['p_es'][:,0], ik_env.data[robot_index]['p_es'][:,1])
+            trajectory_plots[robot_index].set_3d_properties(ik_env.data[robot_index]['p_es'][:,2])
+            eigen1_lines[robot_index].set_ydata(ik_env.data[robot_index]["manip_ell_eigenvals"][:,0])
+            eigen2_lines[robot_index].set_ydata(ik_env.data[robot_index]["manip_ell_eigenvals"][:,1])
+            eigen3_lines[robot_index].set_ydata(ik_env.data[robot_index]["manip_ell_eigenvals"][:,2])
+            manip_index_lines[robot_index].set_ydata(ik_env.data[robot_index]['manip_indeces'])
+            dist_to_goal_lines[robot_index].set_ydata(ik_env.data[robot_index]['dists_to_goal'])
+        update_points(0)
+        canvas_ee.draw()
+        canvas_manipulator.draw()
+        canvas_manip_graphs.draw()
+        root.update()
+
+    def play():
+        pass
+
+    # ellipse on/off
+    def add_remove_ellipse():
+        try:
+            for robot_index, robot in enumerate(ik_env.robots):
+                ik_env.ellipsoid_surf_plots[robot_index].remove()
+        except ValueError:
+            pass
+
+
+
 if name == "__main__":
     queue = Queue()
     root = Tk()
-- 
GitLab