diff --git a/python/examples/clik.py b/python/examples/clik.py
index b6cde26961a23ff9e30bd27a9267b9f48b69803b..933b9bf209c293cd9066bc5a5e469afce2f1109a 100644
--- a/python/examples/clik.py
+++ b/python/examples/clik.py
@@ -1,8 +1,12 @@
+import numpy as np
 import argparse
 from functools import partial
 from ur_simple_control.managers import ControlLoopManager, RobotManager
 # TODO merge the 2 clik files
 from ur_simple_control.clik.clik_point_to_point import getClikController, controlLoopClik 
+# TODO write this in managers and automate name generation
+import pickle
+
 """
 Every imaginable magic number, flag and setting is put in here.
 This way the rest of the code is clean.
@@ -65,9 +69,25 @@ if __name__ == "__main__":
     clik_controller = getClikController(args)
     controlLoop = partial(controlLoopClik, robot, clik_controller)
     log_dict = {
-            'qs' : np.zeros((args.max_iterations, 6)),
-            'dqs' : np.zeros((args.max_iterations, 6)),
+            'qs' : np.zeros((args.max_iterations, robot.model.nq)),
+            'dqs' : np.zeros((args.max_iterations, robot.model.nq)),
         }
     # we're not using any past data or logging, hence the empty arguments
     loop_manager = ControlLoopManager(robot, controlLoop, args, {}, log_dict)
-    loop_manager.run()
+    # TODO create a logging function in util.
+    # something that generates a file name from something in args.
+    # also save args there
+    log_dict = loop_manager.run()
+    # save the logged data
+    file_path = "./data/clik_run_001.pickle"
+    # pretty sure you need to open it binary for pickling
+    log_file = open(file_path, 'wb')
+    pickle.dump(log_dict, log_file)
+    log_file.close()
+    # but also save the arguments
+    file_path = "./data/clik_run_001_args.pickle"
+    # pretty sure you need to open it binary for pickling
+    log_file = open(file_path, 'wb')
+    pickle.dump(args, log_file)
+    log_file.close()
+
diff --git a/python/examples/data/clik_run_001.pickle b/python/examples/data/clik_run_001.pickle
new file mode 100644
index 0000000000000000000000000000000000000000..22dba69ab354c9446dc0c1977f138a6fbb4aa299
Binary files /dev/null and b/python/examples/data/clik_run_001.pickle differ
diff --git a/python/examples/data/clik_run_001_args.pickle b/python/examples/data/clik_run_001_args.pickle
new file mode 100644
index 0000000000000000000000000000000000000000..9d20c5ca9feb7d5adf4978d8de0677386d30d4ab
Binary files /dev/null and b/python/examples/data/clik_run_001_args.pickle differ
diff --git a/python/ur_simple_control/__pycache__/managers.cpython-310.pyc b/python/ur_simple_control/__pycache__/managers.cpython-310.pyc
index 24de3cbd1f605849db1670e76ac3f2d16f4d86a4..f140aa92fbed2b3fe15daff025b45847443394bb 100644
Binary files a/python/ur_simple_control/__pycache__/managers.cpython-310.pyc and b/python/ur_simple_control/__pycache__/managers.cpython-310.pyc differ
diff --git a/python/ur_simple_control/clik/__pycache__/clik_point_to_point.cpython-310.pyc b/python/ur_simple_control/clik/__pycache__/clik_point_to_point.cpython-310.pyc
index dd38d4802f19ea27099acff0a3f394579a099c10..f770d71cc54659c570bd13f21e6d8b0bca454d94 100644
Binary files a/python/ur_simple_control/clik/__pycache__/clik_point_to_point.cpython-310.pyc and b/python/ur_simple_control/clik/__pycache__/clik_point_to_point.cpython-310.pyc differ
diff --git a/python/ur_simple_control/clik/clik_point_to_point.py b/python/ur_simple_control/clik/clik_point_to_point.py
index a0f5ed28336f2c03bc6863e0beb5386839296e1b..971d4d96290bf73f002e52de4f6ed955312aba73 100644
--- a/python/ur_simple_control/clik/clik_point_to_point.py
+++ b/python/ur_simple_control/clik/clik_point_to_point.py
@@ -158,11 +158,11 @@ def controlLoopClik(robot, clik_controller, i, past_data):
 #        print("angular error = ", pin.log6(SEerror).angular)
 #        print(" error = ", err_vector.transpose())
 
-    log_item['qs'] = q[:6].reshape((6,))
+    log_item['qs'] = q.reshape((robot.model.nq,))
     # get actual velocity, not the commanded one.
     # although that would be fun to compare i guess
     # TODO: have both, but call the compute control signal like it should be
-    log_item['dqs'] = robot.getQd()[:6].reshape((6,))
+    log_item['dqs'] = robot.getQd().reshape((robot.model.nq,))
     # we're not saving here, but need to respect the API, 
     # hence the empty dict
     return breakFlag, {}, log_item
diff --git a/python/ur_simple_control/managers.py b/python/ur_simple_control/managers.py
index 05f3ec926c5913e839ab0446529ceef5763a607d..0a0eeb23d98e35556280a14f289d2f494db40586 100644
--- a/python/ur_simple_control/managers.py
+++ b/python/ur_simple_control/managers.py
@@ -170,6 +170,8 @@ class ControlLoopManager:
 #        if not self.args.pinocchio_only:
 #            self.robot_manager.stopHandler(None, None)
 
+        return self.log_dict
+
 """
 robotmanager:
 ---------------
diff --git a/python/ur_simple_control/visualize/__pycache__/make_run.cpython-310.pyc b/python/ur_simple_control/visualize/__pycache__/make_run.cpython-310.pyc
index cc59155c44e721a1377bb4db4c29fbecfe833313..607c0fa9684ec739810129676b0ad85f254d1d75 100644
Binary files a/python/ur_simple_control/visualize/__pycache__/make_run.cpython-310.pyc and b/python/ur_simple_control/visualize/__pycache__/make_run.cpython-310.pyc differ
diff --git a/python/ur_simple_control/visualize/make_run.py b/python/ur_simple_control/visualize/make_run.py
index 378d700020cca2187953753d745ed7e414ca0183..04ebe058e8f5c0b5cc9264d4f7acd7ade0a9fb3f 100644
--- a/python/ur_simple_control/visualize/make_run.py
+++ b/python/ur_simple_control/visualize/make_run.py
@@ -3,6 +3,7 @@ from robot_stuff.drawing import *
 from robot_stuff.inv_kinm import *
 from robot_stuff.utils import *
 from ur_simple_control.managers import RobotManager
+import pinocchio as pin
 
 import numpy as np
 
@@ -60,7 +61,7 @@ def loadRun(args, robot, log_data):
     # anything extra can be copied here and then plotted in an extra tab or something
     assert "qs" in log_data.keys()
     n_iters = log_data["qs"].shape[0]
-    recompute_checher = {
+    recompute_checker = {
         "qs" : False,
         "dqs" : False,
         "manip_ell_eigenvals" : False,
@@ -72,16 +73,16 @@ def loadRun(args, robot, log_data):
         }
     # we construct what's not in log_dict for a nice default window
     if "dqs" not in log_data.keys():
-        log_data["dqs"] = np.zeros((n_iters, robot.n_joints)),
+        log_data["dqs"] = np.zeros((n_iters, robot.n_joints))
         recompute_checker["dqs"] = True
     if "manip_ell_eigenvals" not in log_data.keys():
         log_data["manip_ell_eigenvals"] = np.zeros((n_iters, 3))
         recompute_checker["manip_ell_eigenvals"] = True
     if "manip_elip_svd_rots" not in log_data.keys():
-        log_data["manip_elip_svd_rots"] = np.zeros((n_iters, 3, 3)),
+        log_data["manip_elip_svd_rots"] = np.zeros((n_iters, 3, 3))
         recompute_checker["manip_elip_svd_rots"] = True
     if "p_es" not in log_data.keys():
-        log_data["p_es"] = np.zeros((n_iters, 3)),
+        log_data["p_es"] = np.zeros((n_iters, 3))
         recompute_checker["p_es"] = True
     if "vs" not in log_data.keys():
         log_data["vs"] = np.zeros((n_iters, 6)) # all links linear velocities # NOT USED
@@ -101,25 +102,29 @@ def loadRun(args, robot, log_data):
         # cut of angular velocities 'cos i don't need them for the manip ellipsoid
         # but TODO: check that it's the top ones and not the bottom ones
         J_lin = J[:3, :6]
-        if recompute_checher['vs']:
-            data['vs'][i] = J[:6] @ log_data['dqs'][i]
+        if recompute_checker['vs']:
+            log_data['vs'][i] = J[:6] @ log_data['dqs'][i]
         # TODO fix if you want it, whatever atm man
-        if recompute_checher['p_es']:
-            #data['p_es'][i] = robot.getMtool.translation
+        # TODO you're doubling fkine, dont
+        if recompute_checker['p_es']:
+            log_data['p_es'][i] = robot.getMtool().translation
 
         M = J_lin @ J_lin.T
         manip_index = np.sqrt(np.linalg.det(M))
         _, diag_svd, rot = np.linalg.svd(M)
-        if recompute_checher['manip_indeces']:
-            data['manip_indeces'][i] = manip_index
+        if recompute_checker['manip_indeces']:
+            log_data['manip_indeces'][i] = manip_index
         # TODO check this: idk if this or the square roots are eigenvalues 
-        if recompute_checher['manip_ell_eigenvals']:
-            data["manip_ell_eigenvals"][i] = np.sqrt(diag_svd)
-        if recompute_checher['manip_elip_svd_rots']:
-            data["manip_elip_svd_rots"][i] = rot
+        if recompute_checker['manip_ell_eigenvals']:
+            log_data["manip_ell_eigenvals"][i] = np.sqrt(diag_svd)
+        if recompute_checker['manip_elip_svd_rots']:
+            log_data["manip_elip_svd_rots"][i] = rot
         # maybe plot just this idk, here it is
         smallest_eigenval = diag_svd[diag_svd.argmin()]
-        dist_to_goal = np.linalg.norm(ik_env.robots[robot_index].p_e - ik_env.goal)
         # TODO: make these general error terms
-        data['dists_to_goal'][i] = dist_to_goal
-    return data
+        # also TODO: put this in the autogenerate plots tab
+        if recompute_checker['dists_to_goal']:
+            #dist_to_goal = np.linalg.norm(ik_env.robots[robot_index].p_e - ik_env.goal)
+            #log_data['dists_to_goal'][i] = dist_to_goal
+            pass
+    return log_data
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 e9188a0b74543ac473e6f975f1fd748cce5cb800..aa401f468e0e56aee4e7822da510b5bffef5eac5 100644
--- a/python/ur_simple_control/visualize/manipulator_visual_motion_analyzer.py
+++ b/python/ur_simple_control/visualize/manipulator_visual_motion_analyzer.py
@@ -17,7 +17,8 @@ from matplotlib.gridspec import GridSpec
 from robot_stuff.InverseKinematics import InverseKinematicsEnv
 from robot_stuff.drawing import *
 from robot_stuff.inv_kinm import *
-from make_run import makeRun
+from ur_simple_control.visualize.make_run import makeRun, loadRun
+from ur_simple_control.managers import RobotManager
 
 import numpy as np
 # it is the best solution for a particular problem
@@ -28,6 +29,7 @@ from multiprocessing import Queue
 # but again, who cares, all of this is ugly as hell anyway ('cos it's front-end))
 import threading
 import time 
+import pickle
 
 
 
@@ -124,7 +126,7 @@ ManipulatorVisualMotionAnalyzer
 # this list is to be updated only if you load a new run.
 # or even skip this and reload everything, who cares.
 class ManipulatorVisualMotionAnalyzer:
-    def __init__(self, root, queue, real_time_flag, **kwargs):
+    def __init__(self, root, queue, data, real_time_flag, **kwargs):
         # need to put this in the main program, 
         # so you need to pass it here to use it
         self.root = root
@@ -168,7 +170,10 @@ class ManipulatorVisualMotionAnalyzer:
         ########################
         # TODO: remove from here,
         # we won't be generating runs here later
-        self.n_iters = 200
+        if data == None: 
+            self.n_iters = 200
+        else:
+            self.n_iters = data['qs'].shape[0]
         # the word time is used for timing
         self.t = np.arange(self.n_iters)
         # local kinematics integrator
@@ -190,8 +195,15 @@ class ManipulatorVisualMotionAnalyzer:
         # but deliver the same format.
         # TODO: ensure you're saving AT LEAST what's required here
         # NOTE: the jacobian svd is computed offline in these
+        # TODO: make loading of multiple datas possible
         #self.ik_env.robots.append(Robot_raw(robot_name="no_sim"))
-        self.ik_env.data.append(makeRun(self.controller1, self.ik_env, self.n_iters, 0))
+        # TODO this data has 0 bussiness being defined in ik_env dude
+        # it was probably there to get object permanence before this was a class,
+        # but still dawg
+        if data == None:
+            self.ik_env.data.append(makeRun(self.controller1, self.ik_env, self.n_iters, 0))
+        else:
+            self.ik_env.data.append(data)
         #self.ik_env.data.append(makeRun(self.controller2, self.ik_env, self.n_iters, 1))
 
 
@@ -705,7 +717,9 @@ class ManipulatorVisualMotionAnalyzer:
         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])
+            # TODO: fix actually (put dh parameters of current robot in)
+            #self.ik_env.robots[robot_index].setJoints(self.ik_env.data[robot_index]["qs"][index])
+            self.ik_env.robots[robot_index].setJoints(self.ik_env.data[robot_index]["qs"][index][:6])
             self.ik_env.robots[robot_index].drawStateAnim()
 #            for link in robot.lines:
 #                for line in link:
@@ -859,7 +873,18 @@ class ManipulatorVisualMotionAnalyzer:
 if __name__ == "__main__":
     queue = Queue()
     root = Tk()
-    gui = ManipulatorVisualMotionAnalyzer(root, queue, False, data=None)
+    # TODO: change to something different obviously
+    # or add a button to load or something, idc
+    log_data_file = open("/home/gospodar/lund/praxis/ur_simple_control/python/examples/data/clik_run_001.pickle", 'rb')
+    args_file = open("/home/gospodar/lund/praxis/ur_simple_control/python/examples/data/clik_run_001_args.pickle", 'rb')
+    log_data = pickle.load(log_data_file)
+    args = pickle.load(args_file)
+    # i need pinocchio etc, this is how i can get it with 0 additional hassle
+    args.simulation = True
+    args.pinocchio_only = True
+    robot = RobotManager(args)
+    log_data = loadRun(args, robot, log_data)
+    gui = ManipulatorVisualMotionAnalyzer(root, queue, log_data, False)
 
     # have mainloop 'cos from tkinter import *
     mainloop()