Esempio n. 1
0
    def debug_rotation(ast_trial):
        """
        Plot what the values look like when rotated, debugging tool
        """
        try:
            if ast_trial.is_ast_trial:
                rotated_points = AsteriskCalculations.rotate_points(
                    ast_trial.poses, AsteriskCalculations.rotations[
                        ast_trial.trial_translation])
            else:
                rotated_points = ast_trial
        except:
            rotated_points = ast_trial

        # plot the points
        x = pd.Series.to_list(rotated_points["x"].dropna())
        y = pd.Series.to_list(rotated_points["y"].dropna())

        plt.plot(x, y, color="xkcd:dark orange")

        # plot the target line
        tar_x, tar_y = AsteriskPlotting.get_c(100)
        plt.plot(tar_x, tar_y, color="xkcd:dark blue")

        # show plot
        plt.show()
Esempio n. 2
0
    def calc_max_area_region(ast_trial, percent_window_size=0.2):
        """
        Calculates the area of max error by sliding a window of 20% normalized length along the target line
        Seems that 10% is too small in regions of fast movement
        """
        # TODO: cheating again by rotating points... what about negative values?
        points = AsteriskCalculations.rotate_points(ast_trial.poses, AsteriskCalculations.rotations[ast_trial.trial_translation])
        t_x, t_y = AsteriskPlotting.get_c(100)  # TODO: maybe make target_line a pandas dataframe
        targets = np.column_stack((t_x, t_y))

        #AsteriskMetrics.debug_rotation(points)

        # prepare bound size
        bound_size = 0.5 * (percent_window_size * ast_trial.total_distance)
        x_center = bound_size + 0  # just being explicit here -> x_min is 0
        x_max = 2 * bound_size
        max_area_calculated = 0
        x_center_at_max = x_center

        while x_max <= ast_trial.total_distance:
            # print(f"Now at {x_center} || {x_max}/{ast_trial.total_distance}")
            bounded_points = AsteriskCalculations.get_points_df(points, x_center, bound_size)
            b_x = pd.Series.to_list(bounded_points["x"].dropna())
            b_y = pd.Series.to_list(bounded_points["y"].dropna())
            bounded_points_not_df = np.column_stack((b_x, b_y))

            target_points = AsteriskCalculations.get_points_list(targets, x_center, bound_size)

            try:
                area_calculated = sm.area_between_two_curves(bounded_points_not_df, target_points)
            except ValueError or IndexError:
                # usually this triggers if there aren't enough points (more than one) in the window
                # if there aren't enough points, make enough points!
                try:
                    area_calculated = AsteriskCalculations.interpolate_points(points, x_center,
                                                                              bounded_points, bound_size,
                                                                              target_points)

                    print("Successful interpolation!")
                except Exception as e:
                    print("Interpolation Failed.")
                    print(e)
                    # if not points were found at all in this region, depending on bound size
                    area_calculated = 0

            x_center = x_center + 0.1 * bound_size  # want to step in 1% increments
            x_max = x_center + bound_size

            if np.abs(area_calculated) > max_area_calculated:
                max_area_calculated = np.abs(area_calculated)
                x_center_at_max = x_center

        # percentage along the target_line line that the center of max error was located
        x_center_perc = x_center_at_max / 0.5  # gives us percentage along the full target line, for easy comparing

        # x_center_at_max_r = AsteriskMetrics.rotate_point([x_center_at_max, 0],
        #                                                  -1 * AsteriskMetrics.rotations[ast_trial.trial_translation])

        # print(f"results: {max_area_calculated}, {x_center_perc}")
        return max_area_calculated, x_center_perc
    def plot_all_target_lines(self, order_of_colors):
        """
        Plot all target lines on a plot for easy reference
        :param order_of_colors:
        """
        x_a, y_a = aplt.get_a()
        x_b, y_b = aplt.get_b()
        x_c, y_c = aplt.get_c()
        x_d, y_d = aplt.get_d()
        x_e, y_e = aplt.get_e()
        x_f, y_f = aplt.get_f()
        x_g, y_g = aplt.get_g()
        x_h, y_h = aplt.get_h()

        ideal_xs = [x_a, x_b, x_c, x_d, x_e, x_f, x_g, x_h]
        ideal_ys = [y_a, y_b, y_c, y_d, y_e, y_f, y_g, y_h]

        for i in range(8):
            plt.plot(ideal_xs[i], ideal_ys[i], color=order_of_colors[i], label='ideal', linestyle='--')
    def plot_orientation_errors(self, translation, subject=None, rotation="n", show_plot=True, save_plot=False):
        """
        line plot of orientation error throughout a trial for a specific direction
        :param translation: the type of translation
        :param subject: list of subjects. If none is provided, uses all of them
        :param rotation: type of rotation. Defaults to "n"
        :param show_plot: flag to show plot. Default is true
        :param save_plot: flat to save plot as a file. Default is False
        """
        if subject:
            trials = self._get_ast_dir(translation, subject, rotation)
        else:
            trials = self._get_ast_dir(translation, self.subjects_containing, rotation)

        # if self.averages and incl_avg:  # TODO: have an option to include the average?
        #     for a in self.averages:
        #         if a.trial_translation==direction_label and a.trial_rotation==rotation_label:
        #             trials.append(a)

        for t in trials:
            rot_err = t.calc_rot_err()
            # currently using the get_c function to generate a normalized set of x values to use as x values
            x, _ = aplt.get_c(len(rot_err))  # will need to multiply by 2 to get it to go to 1.0 instead of 0.5
            plt.plot(2*x, rot_err, label=f"Orientation Err {t.subject}, trial {t.trial_num}")

        if save_plot:
            if subject:
                plt.savefig(f"pics/angerror_{self.hand.get_name()}_{subject}_{translation}_{rotation}.jpg", format='jpg')
            else:
                plt.savefig(f"pics/angerror_{self.hand.get_name()}_all_{translation}_{rotation}.jpg", format='jpg')
            # name -> tuple: subj, hand  names
            print("Figure saved.")
            print(" ")

        if show_plot:
            plt.legend()
            plt.show()
    def check_no_backtracking(data,
                              translation_label,
                              threshold=5,
                              debug_rotation=False):
        """
        True if no (or little) backtracking, False is there is

        parameters
        ----------
        - data - dataframe, not normalized yet
        - threshold - how much backtracking to allow, default is 10 mm

        returns
        -------
        - decision - (True/False that there's no significant backtracking)
        - (the most backtracking, threshold) - provided for debugging,
        when True provides the highest cumulated backtrack
        TODO: test this one more thoroughly!
        """
        # convert to mm
        data = data * [1., 1., 1., 1000., 1000., 1000., 1., 1000.]
        data = data.round(4)

        # rotate everything to c direction
        rotated_df = AsteriskCalculations.rotate_points(
            data, AsteriskCalculations.rotations[translation_label])

        if debug_rotation:
            # plot the points
            x = pd.Series.to_list(rotated_df["x"].dropna())
            y = pd.Series.to_list(rotated_df["y"].dropna())

            plt.plot(x, y, color="xkcd:dark orange")

            # plot the target line
            tar_x, tar_y = AsteriskPlotting.get_c(100)
            plt.plot(tar_x * 100, tar_y * 100, color="xkcd:dark blue")

            # show plot
            plt.show()

        # calculate the delta x between each point
        dxs = []  # hold the delta x vals
        prev_x = 0
        for p in rotated_df.iterrows():
            x = p[1]['x']
            dx = x - prev_x
            dxs.append(dx)

            prev_x = x

        rotated_df["dx"] = dxs

        # for those in the wrong direction, see how much accumulates and how far they get
        c_val = 0  # variable which stores cumulative values
        max_c_val = 0
        for p in rotated_df.iterrows():
            if p[1]["dx"] < 0:
                c_val = c_val + p[1]["dx"]

                if c_val > threshold:
                    return False, (c_val, threshold)

                if abs(c_val) > abs(max_c_val):
                    max_c_val = c_val
            else:
                c_val = 0

            print(f"c:{c_val} for {p[1]['x']}, {p[1]['dx']}")

        # if we went through the entire path and found no significant backtracking, then True!
        return True, (c_val, threshold)