# imports
import time
import datetime
import os
import pathlib as path
import math
import random
import warnings
import json
import itertools as it
import gc
from datetime import datetime
import matplotlib.pyplot as plt
import basic_funcs as bf
import numpy as np
from numpy.linalg import inv
import pandas as pd
import scipy as sp
from scipy.stats import norm
from scipy.optimize import curve_fit
from scipy.spatial.transform import Rotation as R
from scipy.signal import savgol_filter
import statsmodels.api as sm
import statsmodels.formula.api as smf
from statsmodels.stats.anova import AnovaRM
from IPython.display import display, HTML
#warnings.filterwarnings('ignore')
np.set_printoptions(suppress=True)
pd.set_option('display.float_format', lambda x: '%.3f' % x)
# final funcs
def print_df(df):
display(HTML(df.to_html()))
def df_from_file(d_file):
df = bf.df_from_log(d_file)
df = bf.add_recode_resp(df, "Response", {"Left": 0, "Right": 1})
df = bf.add_recode_resp(df, "TargetHoriPos", {-3: -1.37, -2: -0.92, -1: -0.46, 0: 0, 1: 0.46, 2: 0.92, 3: 1.37}) # here
# add dfile name as col
version = d_file.split("\\")[-1].split(".")[0].split("_")[1:6]
for idx, ele in enumerate(version):
if idx == 0:
version_str = ele
else:
version_str = version_str + "_" + ele
df["Version"] = [version_str] * df.shape[0]
# special serial dependency stuff
# df = serial_dependency_cols(df, "TargetSide", "TrialGain")
# df = gain_categorize(df, "SD_Gain")
# df = df.drop([df.index[0]]) # remove 1st trial since SD
file_col = [d_file] * df.shape[0]
df = df.assign(Filename = file_col)
return df
def df_multi_files(f_list):
df = df_from_file(f_list[0]) #bf.df_from_log(f_list[0])
if len(f_list) > 1:
for f_p in f_list[1:]:
df_app = df_from_file(f_p) #bf.df_from_log(f_p)
df = pd.concat([df, df_app]) # df = df.append(df_app, ignore_index=True)
return df
def check_for_multi_session(d_files):
ret_dict = {}
uni_ids = []
for d_file in d_files:
f_name = d_file.split("\\")[-1]
top_id = f_name.split("_")[0]
uni_ids.append(top_id)
uni_ids = list(set(uni_ids))
for subj in uni_ids:
ret_dict[subj] = []
for d_file in d_files:
f_name = d_file.split("\\")[-1]
i_id = f_name.split("_")[0]
if subj == i_id:
ret_dict[subj].append(d_file)
return ret_dict
def serial_dependency_cols(df, side_col, gain_col):
# gains
ada_gains = list(df[gain_col])
ada_gains.insert(0, False) # shift lists 1 forward + mark first trial as unusable
del ada_gains[-1] # remove last element
df = df.assign(SD_Gain = ada_gains)
# sides (goal: check if prior same side as trial n)
# same side as prior or not, absolute side irrelevant
sd_sides = []
ada_sides = list(df[side_col])
for idx, side in enumerate(ada_sides):
if idx == 0:
sd_sides.append(False)
elif side == ada_sides[idx - 1]:
sd_sides.append("Congruent")
elif side != ada_sides[idx - 1]:
sd_sides.append("Incongruent")
df = df.assign(SD_Side = sd_sides)
return df
def gain_categorize(df, gain_col):
ada_gains = list(df[gain_col])
cat_col = [False]
for gain in ada_gains[1:]:
if gain == 0:
cat_col.append("Baseline")
elif gain < 0:
cat_col.append("Negative")
elif gain > 0:
cat_col.append("Positive")
df = df.assign(SD_Gain = cat_col)
return df
def prob_stim_lvl(df,lvl_col,av_col):
stim_lvls = np.sort(list(set(list(df[lvl_col]))))
lvl_arr = []
resp_arr = []
points_arr = []
for lvl in stim_lvls:
lvl_arr.append(lvl)
arr = []
counter = 0
for idx,row in df.iterrows():
if row[lvl_col] == lvl:
arr.append(row[av_col])
counter = counter + 1
resp_arr.append(bf.mean(arr))
points_arr.append(counter)
ret_dict = {"Lvl_Arr": lvl_arr,
"Resp_Arr": resp_arr,
"Num_Points": points_arr}
return ret_dict
def parabola_func(x, a, b, c):
return a * np.power(x, 2) + b*x + c # np.exp(x * 2)
def calc_r2(y, y_fit):
ss_tot = np.sum([np.power(np.mean(y) - y_val, 2) for y_val in y])
ss_res = np.sum([np.power(y_fit_val - y_val, 2) for y_val, y_fit_val in zip(y, y_fit)])
r_2 = 1 - (ss_res / ss_tot)
return r_2
def fxn():
warnings.warn("deprecated", RuntimeWarning) #DeprecationWarning
def get_parabola_vals(a, b, c):
axis = - (b / 2*a)
focal_length = 1 / (4*a)
vertex = [-(b / (2 * a)), ((4 * a * c) - np.power(b, 2)) / 4 * a]
focus = [-(b / (2 * a)), ((4 * a * c) - np.power(b,2) + 1) / 4 * a]
directrix = (4 * a * c - np.power(b, 2) - 1) / (4 * a)
return [axis, focal_length, vertex, focus, directrix]
def parabola_pses(a,b,c):
# a * np.power(x, 2) + b*x + c
p = b / a
q = (c - 0.5) / a
x1 = -(p / 2) + np.sqrt(np.power((p / 2), 2) - q)
x2 = -(p / 2) - np.sqrt(np.power((p / 2), 2) - q)
return [x1,x2]
def balance_data(df, sub_col, cols):
col_lvls = [list(set(list(df[col]))) for col in cols]
combis_l = [x for x in it.product(*col_lvls)]
subs = np.sort(list(set(df[sub_col])))
inc_subs = []
for sub in subs:
sub_df = df[df[sub_col] == sub]
if sub_df.shape[0] == len(combis_l):
inc_subs.append(sub)
return df[df[sub_col].isin(inc_subs)]
# head funcs
def get_time_col(df):
cols = list(df.columns)
return [col for col in cols if "Time" in col][0]
def rot_from_str_rot(vector):
vec_arr = vector.split(" ")
vec_vals = [x.split("=")[1] for x in vec_arr]
pos_vec = [float(x) for x in vec_vals]
return pos_vec
# pf funcs
def balance_data(df, sub_col, cols):
col_lvls = [list(set(list(df[col]))) for col in cols]
combis_l = [x for x in it.product(*col_lvls)]
subs = np.sort(list(set(df[sub_col])))
inc_subs = []
for sub in subs:
sub_df = df[df[sub_col] == sub]
if sub_df.shape[0] == len(combis_l):
inc_subs.append(sub)
return df[df[sub_col].isin(inc_subs)]
def pos_from_matrix(list_saved_as_str):
list_mat = str_mat_to_mat(list_saved_as_str)
conv_mat = convert_steam_vr_matrix(list_mat)
inv_mat = inv(conv_mat)
matrix33 = [x[0:3] for idx, x in enumerate(inv_mat) if idx != 3] # remove scaling value + 4th row
np_mat = np.matrix(matrix33) #* 100 # ue4 units for 1
# offset to tracking pos 0,0,0 unknown, therefore only an estimate
# doesnt seem to be possible to get exact UE coordinates outside of UE
# and in UE it does not seem to be possible to retrieve the coordinates used in game with more than 90hz
estimate = [-inv_mat[3][2], inv_mat[3][0], inv_mat[3][1]]
estimate = [x * 100 for x in estimate] # 100 for world scale, 100 ue units = 1m
return estimate
# analysis funcs
def dep_ttest(comp_str, arr1, arr2, sided, num_corr, b_print):
t, p = sp.stats.ttest_rel(arr1, arr2, alternative=sided) #greater
if b_print:
print("{}: p = {}, corrected: {}".format(comp_str, np.round(p, 3), np.round(p * num_corr, 3)))
return t, p, len(arr1) - 1
def one_sample_ttest(comp_str, arr, value, sided, num_corr, b_print):
t, p = sp.stats.ttest_1samp(arr, 0, axis=0, alternative=sided) # greater
if b_print:
print("{}: t({}) = {}, p = {}, corrected: {}".format(comp_str, len(arr) - 1, np.round(t, 2), np.round(p, 3), np.round(p * 5, 3)))
return t, p, len(arr) - 1
# get data files
scripts_p = path.Path.cwd()
stats_p = scripts_p.parents[1]
data_p = stats_p.joinpath("effmann 2", "data", "Raw")
plot_p = stats_p.joinpath("effmann 2","plots")
dfs_p = stats_p.joinpath("effmann 2","dfs")
d_files = np.sort(bf.get_data(data_p,"csv","", ["timings", "head","eye"]))
d_timing_files = np.sort(bf.get_data(data_p,"csv","timings.csv", []))
d_eye_files = np.sort(bf.get_data(data_p,"csv","eye.csv", []))
d_head_files = np.sort(bf.get_data(data_p,"csv","head.csv", []))
d_head_app_files = np.sort(bf.get_data(data_p,"csv","head_app.csv", []))
print("Number of data files: {}".format(len(d_files)))
print(d_files[0])
print(d_timing_files[0])
print(d_eye_files[0])
print(d_head_files[0])
print(d_head_app_files[0])
Number of data files: 384 c:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\effmann 2\data\Raw\AD21_Eye_Movement_NoGain_PermanentTargets_Gabor_19_6_2023_10_16.csv c:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\effmann 2\data\Raw\AD21_Eye_Movement_NoGain_PermanentTargets_Gabor_19_6_2023_10_16_timings.csv c:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\effmann 2\data\Raw\AD21_Eye_Movement_NoGain_PermanentTargets_Gabor_19_6_2023_10_16_eye.csv c:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\effmann 2\data\Raw\AD21_Eye_Movement_NoGain_PermanentTargets_Gabor_19_6_2023_10_16_head.csv c:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\effmann 2\data\Raw\AD21_Eye_Movement_NoGain_PermanentTargets_Gabor_19.6.2023_6626_head_app.csv
# create randomized order of conds
conds = ["HeadEye_NoMovement_NoGain_PermanentTargets_NoGabor",
"Eye_Movement_NoGain_PermanentTargets_NoGabor",
"Eye_Movement_NoGain_TemporaryTargets_Gabor",
"Eye_Movement_NoGain_PermanentTargets_Gabor",
"HeadEye_NoMovement_NoGain_TemporaryTargets_NoGabor",
"HeadEye_Movement_NoGain_TemporaryTargets_Gabor",
"HeadEye_Movement_NoGain_TemporaryTargets_NoGabor",
"HeadEye_Movement_NoGain_PermanentTargets_NoGabor",
"HeadEye_Movement_NoGain_PermanentTargets_Gabor",
"HeadEye_NoMovement_NoGain_TemporaryTargets_Gabor",
"HeadEye_NoMovement_NoGain_PermanentTargets_Gabor",
"Eye_Movement_NoGain_TemporaryTargets_NoGabor"]
df_dict = {}
conds_vars = []
for x in list(range(0,20)):
conds = random.sample(conds, len(conds))
# random.shuffle(conds)
df_dict[x] = conds
conds_vars.append(conds)
pd.DataFrame(df_dict).to_csv(r"C:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\effmann 2\orders.csv")
len(list(np.unique(conds_vars, axis=0)))
20
# sub info
subs = np.sort(np.unique([x.split("\\")[-1].split("_")[0] for x in d_files]))
final_df = pd.DataFrame()
for sub in subs:
sub_files = [x for x in d_files if sub in x]
sub_df = pd.DataFrame()
for sub_file in sub_files:
df = df_from_file(sub_file)
sub_df = pd.concat([sub_df, df])
final_df = pd.concat([final_df, sub_df])
np.sort(np.unique(final_df["SubjectID"]))
array(['AD21', 'AO23', 'AP28', 'AS27', 'AT23', 'BW21', 'CF03', 'CS19', 'DC21', 'EW22', 'FA24', 'FH26', 'FS28', 'HS02', 'IB16', 'LB01', 'LC10', 'LK23', 'LS22', 'MF26', 'ML27', 'MM09', 'MR12', 'SH08', 'SJ24', 'SK29', 'SM03', 'SNK20', 'ST07', 'SW217', 'TK15', 'TT12', 'VM20', 'YS24'], dtype=object)
# check for incomplete data
for sub in subs:
for f_idx, files in enumerate([d_files, d_timing_files, d_eye_files, d_head_files, d_head_app_files]):
sub_files = [x for x in files if sub in x]
if len(sub_files) != 12:
print(sub, f_idx, len(sub_files))
CS19 4 1 DC21 4 11 ML27 4 3 SNK20 4 4
# excluded subs
# cs19 (half bad, complete exclusion)
# at23 (1 too bad, maybe stay in)
# write out which files were finally used for analysis
all_files = np.concatenate((d_files, d_timing_files, d_eye_files, d_head_files, d_head_app_files), axis=0) # + + + +
# np.sort(all_files)
all_files = [x.split("\\")[-1] for x in all_files]
# pd.DataFrame({"Files": np.sort(all_files)}).to_csv(r"D:\HeadRotationObjectLocalization\files_to_use.csv")
# all_files
# remove trials which did not fixate at correct times
# remove these files from pf data
# recalc pfs
### to dos
##### exclude trials based on head data
##### exclude trials based on eye data
#### pf analysis
#### descriptive stuff for head
#### used AHR1 as template
# funcs
def preprocess_head_files(d_timing_files, data_p):
keys = ["Trial", "PreStart", "Start", "End", "FirstStimulusOnset", "FirstStimulusOffset", "SecondStimulusOnset", "SecondStimulusOffset"]
for idx, file_path in enumerate(d_timing_files):
file_path_comps = file_path.split("\\")
# print(file_path_comps[-1].split("_"))
# ['AD21', 'Eye', 'Movement', 'NoGain', 'PermanentTargets', 'Gabor', '19', '6', '2023', '10', '16', 'timings.csv']
# ['ST07', 'Eye', 'Movement', 'NoGain', 'PermanentTargets', 'Gabor', '26', '6', '2023', '10', '35', 'timings.csv']
# try:
sub, run, move, gain, target, gabor, day, month, year, hour, minute, end = file_path_comps[-1].split("_")
file_name = data_p.joinpath("{}_{}_{}_{}_{}_{}.{}.{}_timings.pickle".format(sub, run, move, target, gabor, day, month, year))
file_name = str(file_name).replace("Raw", "Preprocessed")#.replace("csv", "pickle")
if not os.path.exists(file_name):
df_timing = pd.read_csv(file_path, index_col=0)
if df_timing.shape[0] > 0:
df_timing_preprocessed = pd.DataFrame()
time_c = "StimulusTime"
trial_num = 1
trials = []
for idx, row in df_timing.iterrows():
trials.append(trial_num)
if row["StimulusType"] == "SecondStimulus" and row["StimulusEvent"] == "StimulusOffset":
trial_num = trial_num + 1
df_timing["Trial"] = trials
# print_df(df_timing)
last_trial = max(trials)
trials = list(range(1, last_trial + 1))
for trial in trials:
trial_dict = {}
for key in keys:
trial_dict[key] = []
trial_df = df_timing.query('Trial == @trial')
# print_df(trial_df)
try:
start = trial_df.query('StimulusType == "FirstStimulus" & StimulusEvent == "StimulusOnset"')[time_c].iloc[-1] # select last as trial could have been restarted
pre_start = start - (200 * 1_000_000)
first_onset = start
first_offset = trial_df.query('StimulusType == "FirstStimulus" & StimulusEvent == "StimulusOffset"')[time_c].iloc[-1]
second_onset = trial_df.query('StimulusType == "SecondStimulus" & StimulusEvent == "StimulusOnset"')[time_c].iloc[-1]
end = trial_df.query('StimulusType == "SecondStimulus" & StimulusEvent == "StimulusOffset"')[time_c].iloc[-1]
second_offset = end
# if trial_df.query('StimulusType == "FirstStimulus" & StimulusEvent == "StimulusOnset"').shape[0] > 1:
# print(trial)
# print_df(trial_df.query('StimulusType == "FirstStimulus" & StimulusEvent == "StimulusOnset"'))
vals = [trial, pre_start, start, end, first_onset, first_offset, second_onset, second_offset]
for key, val in zip(keys, vals):
trial_dict[key].extend([val])
df_timing_preprocessed = pd.concat([df_timing_preprocessed, pd.DataFrame(trial_dict)])
except:
print(sub, run, move, target, gabor, trial)
else:
print(sub, run, move, target, gabor, "no trials")
if df_timing.shape[0] > 0:
df_timing_preprocessed = df_timing_preprocessed.reset_index(drop=True)
df_timing_preprocessed.to_pickle(file_name)
# print_df(df_timing_preprocessed)
# except:
# print("file info: {}".format(file_path_comps[-1].split("_")))
# preprocess timing files
timings = True
if timings:
preprocess_head_files(d_timing_files, data_p.parent.joinpath("preprocessed"))
else:
print("Timing preprocessing done")
# head tracking data to yaw
def str_mat_to_mat(str_mat):
return json.loads(str_mat)
def convert_steam_vr_matrix(pose):
return np.array((
(pose[0][0], pose[1][0], pose[2][0], 0.0),
(pose[0][1], pose[1][1], pose[2][1], 0.0),
(pose[0][2], pose[1][2], pose[2][2], 0.0),
(pose[0][3], pose[1][3], pose[2][3], 1.0),
), dtype=np.float32)
def vals_from_matrix(list_saved_as_str):
list_mat = str_mat_to_mat(list_saved_as_str)
# https://github.com/cmbruns/pyopenvr/blob/6c153f986d46b61a3e136c144011695841b56502/src/samples/glfw/hellovr_glfw.py#L880
conv_mat = convert_steam_vr_matrix(list_mat)
inv_mat = inv(conv_mat)
matrix33 = [x[0:3] for idx, x in enumerate(inv_mat) if idx != 3] # remove scaling value + 4th row
np_mat = np.matrix(matrix33) #* 100 # ue4 units for 1
rot = R.from_matrix(np_mat)
pitch, yaw, roll = rot.as_euler('xyz', degrees=True)
return pitch, yaw * -1, roll
def vals_from_str_rot(str_rot):
return [float(x.split("=")[1]) for x in str_rot.split(" ")]
# funcs
def preprocess_head_data(timing_files, thread_files, app_files):
for idx, timing_file in enumerate(timing_files):
sub, run, move, target, gabor, date, end = timing_file.split("\\")[-1].split("_")
file_name = data_p.joinpath("{}_{}_{}_{}_{}_{}_head.pickle".format(sub, run, move, target, gabor, date))
file_name = str(file_name).replace("Raw", "preprocessed").replace("csv", "pickle")
print("{} / {}: {}". format(idx + 1, len(timing_files), timing_file.split("\\")[-1]))
print(file_name)
if not os.path.exists(file_name):
date = date.replace(".", "_")
poss_thread_files = [x for x in thread_files if "{}_{}_{}_NoGain_{}_{}".format(sub, run, move, target, gabor) in x]
poss_app_files = [x for x in app_files if "{}_{}_{}_NoGain_{}_{}".format(sub, run, move, target, gabor) in x]
can_use_app_file = False
if len(poss_app_files) > 0:
can_use_app_file = True
print("Can use app file")
else:
print("Cannot use app file")
timing_df = pd.read_pickle(timing_file)
full_head_df = pd.DataFrame()
trials_with_app = 0
trials_with_thread = 0
for idx, row in timing_df.iterrows():
trial_start, trial_end = row["PreStart"], row["End"]
head_trial_df = pd.DataFrame()
app_provides_data = False
if can_use_app_file:
head_df = pd.read_csv(poss_app_files[0], index_col=0, sep=";", engine="python")
head_trial_df = head_df.query('Time >= @trial_start & Time <= @trial_end')
if head_trial_df.shape[0] > 0:
new_cols = {}
col_names = ["Pitch", "Yaw", "Roll"]
for col in col_names:
new_cols[col] = []
for idx, row in head_trial_df.iterrows():
for key, val in zip(col_names, vals_from_matrix(row["Matrix"])):
new_cols[key].append(val)
head_trial_df = head_trial_df.assign(**new_cols)
head_trial_df = head_trial_df[["Time", "Pitch", "Yaw", "Roll"]]
app_provides_data = True
trials_with_app = trials_with_app + 1
if not app_provides_data or not can_use_app_file:
head_df = pd.read_csv(poss_thread_files[0], index_col=0)
head_trial_df = head_df.query('Time >= @trial_start & Time <= @trial_end')
new_cols = {}
col_names = ["Pitch", "Yaw", "Roll"]
for col in col_names:
new_cols[col] = []
for idx, row in head_trial_df.iterrows():
for key, val in zip(col_names, vals_from_str_rot(row["Rotator"])):
new_cols[key].append(val)
head_trial_df = head_trial_df.assign(**new_cols)
head_trial_df = head_trial_df[["Time", "Pitch", "Yaw", "Roll"]]
trials_with_thread = trials_with_thread + 1
full_head_df = pd.concat([full_head_df, head_trial_df])
print("Thread trials: {}, App trials: {}".format(trials_with_thread, trials_with_app))
full_head_df.reset_index(drop=True).to_pickle(file_name)
# preprocess head files
timing_files = np.sort(bf.get_data(stats_p.joinpath("effmann 2","data", "preprocessed"),"pickle","timings", []))
head_pp_data = np.sort(bf.get_data(stats_p.joinpath("effmann 2","data", "preprocessed"),"pickle","head", ["eye", "timings"]))
if len(head_pp_data) < len(timing_files):
preprocess_head_data(timing_files, d_head_files, d_head_app_files)
else:
print("Head preprocessing done")
Head preprocessing done
# eye angle calc funcs
def unreal_pos_to_single_cols(df, col): # new func to get abs position
new_cols = {}
keys = ["X", "Y", "Z"]
keys = [col + "_" + x for x in keys]
for key in keys:
new_cols[key] = []
for idx, row in df.iterrows():
val = row[col]
vals = val.split(" ")
for key, val in zip(keys, vals):
new_cols[key].append(val.split("=")[1])
df = df.assign(**new_cols)
d_type_dict = {}
for key in keys:
d_type_dict[key] = "float64"
df = df.astype(d_type_dict)
return df
def angle_of_vectors(vec1, vec2, rel_idx):
# dont use z
# vec1, vec2 = vec1[0:2], vec2[0:2]
scalar_product = np.dot(vec1, vec2)
amount_vec1 = math.sqrt(np.sum([math.pow(x, 2) for x in vec1])) # betrag
amount_vec2 = math.sqrt(np.sum([math.pow(x, 2) for x in vec2]))
if (amount_vec1 * amount_vec2) != 0:
angle = math.degrees(math.acos(scalar_product / (amount_vec1 * amount_vec2)))
else:
angle = np.nan
if vec1[rel_idx] < vec2[rel_idx]: # angle below / left are negative
angle = angle * (-1)
return angle
def str_vec_to_array(str_vec):
ini_vec = [float(x.split("=")[1]) for x in str_vec.split(" ")]#[0] * coef
real_vec = [x * 250 for x in ini_vec] # (camera_rot.RotateVector(direction) * 250) + camera_pos;
vec_x, vec_y, vec_z = real_vec
straight_ahead = [250, 0, 0]
x = angle_of_vectors([vec_x, 0, 0], straight_ahead, 0)
y = angle_of_vectors([vec_x, vec_y, 0], straight_ahead, 1)
z = angle_of_vectors([vec_x, 0, vec_z], straight_ahead, 2)
return [x,y,z]
def string_vec_to_eye_pos(df, col, new_col_name):
new_cols = {}
keys = [new_col_name + "_{}".format(x) for x in ["X", "Y", "Z"]]
for key in keys:
new_cols[key] = []
for idx, row in df.iterrows():
vals = str_vec_to_array(row[col])
for key, val in zip(keys, vals):
new_cols[key].append(val)
df = df.assign(**new_cols)
return df
# string_vec_to_eye_pos(run_df, "Direction", "EyeAngle")
# funcs
def preprocess_eye_data(timing_files, eye_files):
problematic_runs = []
for idx, timing_file in enumerate(timing_files):
sub, run, move, target, gabor, date, end = timing_file.split("\\")[-1].split("_")
file_name = data_p.joinpath("{}_{}_{}_{}_{}_{}_eye.pickle".format(sub, run, move, target, gabor, date))
file_name = str(file_name).replace("Raw", "preprocessed").replace("csv", "pickle")
print("{} / {}: {}". format(idx + 1, len(timing_files), timing_file.split("\\")[-1]))
if not os.path.exists(file_name):
poss_eye_files = [x for x in eye_files if "{}_{}_{}_NoGain_{}_{}".format(sub, run, move, target, gabor) in x]
# print(poss_eye_files)
if len(poss_eye_files) > 0:
# print("Eye file found")
timing_df = pd.read_pickle(timing_file)
eye_df = pd.read_csv(poss_eye_files[0])
full_eye_df = pd.DataFrame()
problematic_trials = []
for idx, row in timing_df.iterrows():
trial_start, trial_end = row["PreStart"], row["End"]
eye_trial_df = eye_df.query('Time >= @trial_start & Time <= @trial_end')
# eye_trial_df = unreal_pos_to_single_cols(eye_trial_df, "Direction")
eye_trial_df = string_vec_to_eye_pos(eye_trial_df, "Direction", "EyeAngle")
eye_trial_df = eye_trial_df[["Time", "EyeAngle_Y", "EyeAngle_Z"]]
# trial_dur = (eye_trial_df["Time"].iloc[-1] - eye_trial_df["Time"].iloc[0]) / 1_000_000
# print("Trial duration: {}".format(trial_dur))
if eye_trial_df.shape[0] > 0:
full_eye_df = pd.concat([full_eye_df, eye_trial_df])
else:
problematic_trials.append(idx + 1)
if len(problematic_trials) > 0:
print("Number of trials without eye data: {}".format(len(problematic_trials)))
full_eye_df.reset_index(drop=True).to_pickle(file_name)
else:
print("No eye file found")
problematic_runs.append("{}_{}_{}".format(sub, run, date))
else:
print("Preprocessed file found")
print("Problematic Runs: {}".format(problematic_runs))
# preprocess eye files
timing_files = np.sort(bf.get_data(stats_p.joinpath("effmann 2", "data","preprocessed"),"pickle","timings", []))
eye_pp_data = np.sort(bf.get_data(stats_p.joinpath("effmann 2", "data","preprocessed"),"pickle","eye", ["head", "timings"]))
if len(eye_pp_data) < len(timing_files):
preprocess_eye_data(timing_files, d_eye_files)
else:
print("Eye preprocessing done")
Eye preprocessing done
# test for inconsistencies in transformation
def angle_of_vectors(vec1, vec2, rel_idx):
# dont use z
# vec1, vec2 = vec1[0:2], vec2[0:2]
scalar_product = np.dot(vec1, vec2)
amount_vec1 = math.sqrt(np.sum([math.pow(x, 2) for x in vec1])) # betrag
amount_vec2 = math.sqrt(np.sum([math.pow(x, 2) for x in vec2]))
if (amount_vec1 * amount_vec2) != 0:
angle = math.degrees(math.acos(scalar_product / (amount_vec1 * amount_vec2)))
else:
angle = np.nan
if vec1[rel_idx] < vec2[rel_idx]: # angle below / left are negative
angle = angle * (-1)
return angle
def str_vec_to_array(str_vec, time):
ini_vec = [float(x.split("=")[1]) for x in str_vec.split(" ")]#[0] * coef
real_vec = [x * 250 for x in ini_vec] # (camera_rot.RotateVector(direction) * 250) + camera_pos;
vec_x, vec_y, vec_z = real_vec
straight_ahead = [250, 0, 0]
x = angle_of_vectors([vec_x, 0, 0], straight_ahead, 0)
y = angle_of_vectors([vec_x, vec_y, 0], straight_ahead, 1)
z = angle_of_vectors([vec_x, 0, vec_z], straight_ahead, 2)
# print(time, ini_vec, [x,y,z])
return [x,y,z]
def string_vec_to_eye_pos(df, col, new_col_name):
new_cols = {}
keys = [new_col_name + "_{}".format(x) for x in ["X", "Y", "Z"]]
for key in keys:
new_cols[key] = []
for idx, row in df.iterrows():
time = (row["Time"] - df.iloc[0]["Time"]) / 1_000_000
vals = str_vec_to_array(row[col], time)
for key, val in zip(keys, vals):
new_cols[key].append(val)
df = df.assign(**new_cols)
return df
if False:
infos = [
["ALKA_MovementGain_", 31],
["ALKA_Movement_", 65],
["ALKA_MovementGain_", 62],
["ALKA_MovementGain_", 57],
["ALKA_MovementGainHigh_", 10]
]
for info in infos:
cond, trial = info
timing_file = [x for x in timing_files if cond in x][0]
eye_file = [x for x in d_eye_files if cond in x][0]
timing_df = pd.read_pickle(timing_file)
eye_df = pd.read_csv(eye_file)
for idx, row in timing_df.iterrows():
if row["Trial"] == trial:
trial_start, trial_end = row["PreStart"], row["End"]
eye_trial_df = eye_df.query('Time >= @trial_start & Time <= @trial_end')
eye_trial_df = string_vec_to_eye_pos(eye_trial_df, "Direction", "EyeAngle")
eye_trial_df = eye_trial_df.assign(Time = [(x-eye_trial_df.iloc[0]["Time"]) / 1_000_000 for x in eye_trial_df["Time"]])
# eye_trial_df = eye_trial_df.query('Time > 100 & Time < 250')
positions = [float(x.split(" ")[0].split("=")[1]) for x in eye_trial_df["Direction"]]
eye_trial_df = eye_trial_df.assign(ExcludeX = positions)
post_exc_positions = [float(x.split(" ")[0].split("=")[1]) for x in eye_trial_df["Direction"]]
plt.scatter(eye_trial_df["Time"], [x/10 for x in post_exc_positions], color="tab:green")
plt.scatter(eye_trial_df["Time"], eye_trial_df["EyeAngle_Y"], color="tab:blue")
val = np.mean(eye_trial_df["ExcludeX"]) - 10
eye_trial_df = eye_trial_df.query('ExcludeX >= @val')
plt.scatter(eye_trial_df["Time"], eye_trial_df["EyeAngle_Y"], color="tab:red")
# plt.show()
plt.close()
# plt.plot(eye_trial_df["Time"], eye_trial_df["EyeAngle_Y"], color="tab:blue", lw=1)
# eye_trial_df
# weird eye data is in fact due to weird output from eyetracker, not transformation fault
if False:
'''
216.332, 20.263, -91.944] 0.0, 5.3510664023392085, -23.026142566186646]
216.459, 21.24, -91.584] 0.0, 5.604197259628303, -22.933266151667787]
216.459, 21.24, -91.584] 0.0, 5.604197259628303, -22.933266151667787]
1.077, 4.478, 34.244] 0.0, 76.47668624442127, 88.19859769360522]
1.077, 4.478, 34.244] 0.0, 76.47668624442127, 88.19859769360522]
1.066, 4.511, 34.258] 0.0, 76.70427299139874, 88.21771266346411]
243.442, 33.533, -19.686] 0.0, 7.842871921914408, -4.623178192824711]
243.442, 33.533, -19.686] 0.0, 7.842871921914408, -4.623178192824711]
243.393, 34.572, -19.31] 0.0, 8.084320401776449, -4.536157267143796]
'''
# test problem runs for movement detection pp
def find_correct_files(sub, run, move, target, gabor, d_files, timing_files, head_pp_data, eye_pp_data):
d_file = [x for x in d_files if "{}_{}_{}_NoGain_{}_{}".format(sub, run, move, target, gabor) in x]
timing_file = [x for x in timing_files if "{}_{}_{}_{}_{}".format(sub, run, move, target, gabor) in x]
head_pp_d = [x for x in head_pp_data if "{}_{}_{}_{}_{}".format(sub, run, move, target, gabor) in x]
eye_pp_d = [x for x in eye_pp_data if "{}_{}_{}_{}_{}".format(sub, run, move, target, gabor) in x]
for idx, x in enumerate([d_file, timing_file, head_pp_d, eye_pp_d]):
if len(x) > 1:
print(idx, "several files found")
print(np.array(x))
return d_file[0], timing_file[0], head_pp_d[0], eye_pp_d[0]
if False:
scripts_p = path.Path.cwd()
stats_p = scripts_p.parents[1]
data_p = stats_p.joinpath("effmann 2", "data", "Raw") # C:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\effmann 2\data\Raw
plot_p = stats_p.joinpath("effmann 2","plots")
dfs_p = stats_p.joinpath("effmann 2","dfs")
d_files = np.sort(bf.get_data(data_p,"csv","", ["timings", "head","eye"]))
d_timing_files = np.sort(bf.get_data(data_p,"csv","timings.csv", []))
d_eye_files = np.sort(bf.get_data(data_p,"csv","eye.csv", []))
d_head_files = np.sort(bf.get_data(data_p,"csv","head.csv", []))
d_head_app_files = np.sort(bf.get_data(data_p,"csv","head_app.csv", []))
timing_files = np.sort(bf.get_data(stats_p.joinpath("effmann 2", "data","preprocessed"),"pickle","timings", []))
head_pp_data = np.sort(bf.get_data(stats_p.joinpath("effmann 2", "data","preprocessed"),"pickle","head", ["eye", "timings"]))
eye_pp_data = np.sort(bf.get_data(stats_p.joinpath("effmann 2", "data","preprocessed"),"pickle","eye", ["head", "timings"]))
timing_file = r"C:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\effmann 2\data\preprocessed\FS28_HeadEye_Movement_TemporaryTargets_Gabor_20.6.2023_timings.pickle" #[x for x in timing_files if "AD21_Eye_Movement_PermanentTargets_Gabor" in x][0]
test = pd.read_pickle(timing_file)
for t_file in timing_files[:1]:
timing_df = pd.read_pickle(timing_file)
sub, run, move, target, gabor, date, end = timing_file.split("\\")[-1].split("_")
d_file, timing_file, head_pp_d, eye_pp_d = find_correct_files(sub, run, move, target, gabor, d_files, timing_files, head_pp_data, eye_pp_data)
beh_df = pd.read_csv(d_file, index_col=0)
head_df = pd.read_pickle(head_pp_d)
eye_df = pd.read_pickle(eye_pp_d)
# test_p = plot_p.joinpath("test_tracking_data")
# for idx, row in timing_df.iterrows():
# trial, pre, start, end, f_onset, f_offset, s_onset, s_offset = row
# f_onset, f_offset, s_onset, s_offset = [(x - start) / 1_000_000 for x in [f_onset, f_offset, s_onset, s_offset]]
# beh_trial = beh_df.query('TrialNum == @trial').iloc[0]
# trial_eye = eye_df.query('Time >= @pre & Time <= @end')
# trial_eye = trial_eye.assign(Time = [(x - start) / 1_000_000 for x in trial_eye["Time"]])
# trial_head = head_df.query('Time >= @pre & Time <= @end')
# trial_head = trial_head.assign(Time = [(x - start) / 1_000_000 for x in trial_head["Time"]])
# plt.plot(trial_head["Time"], trial_head["Yaw"])
# plt.xlabel("Time")
# plt.xlabel("°")
# plt.ylim([-20,20])
# plt.savefig(test_p.joinpath("{}.png".format(trial)), facecolor="white")
# plt.close()
test.head(2)
# functions for trial movement
def find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data):
d_file = [x for x in d_files if "{}_{}_{}".format(sub, run, date) in x]
timing_file = [x for x in timing_files if "{}_{}_{}".format(sub, run, date) in x]
head_pp_d = [x for x in head_pp_data if "{}_{}_{}".format(sub, run, date) in x]
eye_pp_d = [x for x in eye_pp_data if "{}_{}_{}".format(sub, run, date) in x]
for idx, x in enumerate([d_file, timing_file, head_pp_d, eye_pp_d]):
if len(x) > 1:
print(idx, "several files found")
print(np.array(x))
return d_file[0], timing_file[0], head_pp_d[0], eye_pp_d[0]
def plot_trial_movements(beh, timing, head, eye, trials):
sub, run = beh.iloc[0]["SubjectID"], beh.iloc[0]["Version"]
if trials == "all":
rows = timing
else:
rows = timing.query('') #.iloc[0:num_trials]
for idx, row in rows.iterrows():
# get trial info
trial, pre, start, end, f_onset, f_offset, s_onset, s_offset = row
# print("Trial: {}".format(int(trial)))
trial_head = head.query('Time >= @pre & Time <= @end')
trial_eye = eye.query('Time >= @pre & Time <= @end')
stimuli_times = [(x - start) / 1_000_000 for x in [f_onset, f_offset, s_onset, s_offset]]
beh_trial = beh.query('TrialNum == @trial').iloc[0]
obj_positions = get_trial_object_positions(beh_trial["TargetHoriPos"], beh_trial["TargetVertPos"])
stim_positions = obj_positions["Stimulus"]
fix_positions = obj_positions["Fixation_Cross"]
for axis in ["Y", "Z"]:
save_p = plot_p.joinpath("trial_movements", "{}_{}_{}_{}.png".format(sub, run, int(trial), axis))
if not os.path.exists(save_p):
head_col = "Yaw"
upper_border = "Left_Border"
lower_border = "Right_Border"
if axis == "Z":
head_col = "Pitch"
upper_border = "Upper_Border"
lower_border = "Lower_Border"
# create plot
fig, ax = plt.subplots(1,1, figsize=[6,5])
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.set_ylabel(axis)
# head eye plotting
head_times = [(x - start) / 1_000_000 for x in trial_head["Time"]]
ax.plot(head_times, trial_head[head_col], color="tab:blue", label="Head")
ax.plot([(x - start) / 1_000_000 for x in trial_eye["Time"]], trial_eye["EyeAngle_{}".format(axis)], color="tab:red", label="Eye")
# stimuli plotting
ax.plot(stimuli_times[0:2], [stim_positions["Probe"][upper_border], stim_positions["Probe"][upper_border]], color="b", label="Probe")
ax.plot(stimuli_times[0:2], [stim_positions["Probe"][lower_border], stim_positions["Probe"][lower_border]], color="b")
ax.plot(stimuli_times[2:], [stim_positions["Reference"][upper_border], stim_positions["Reference"][upper_border]], color="b", label="Reference")
ax.plot(stimuli_times[2:], [stim_positions["Reference"][lower_border], stim_positions["Reference"][lower_border]], color="b")
# fixation cross
ax.plot(stimuli_times[0:2], [fix_positions["Left_Cross"][upper_border]] * 2, color="k", label="Left Fixation Cross")
ax.plot(stimuli_times[0:2], [fix_positions["Left_Cross"][lower_border]] * 2, color="k")
ax.plot(stimuli_times[2:], [fix_positions["Right_Cross"][upper_border]] * 2, color="k", label="Right Fixation Cross")
ax.plot(stimuli_times[2:], [fix_positions["Right_Cross"][lower_border]] * 2, color="k")
ax.legend(bbox_to_anchor=(1, 0.15, 0.5, 0.5), frameon=False)
plt.savefig(save_p, dpi=150, facecolor="white", bbox_inches="tight")
plt.close()
def plot_movements(print_b):
files_to_process = timing_files
for file_idx, file in enumerate(files_to_process):
print("{} / {}: {}".format(file_idx + 1, len(files_to_process), datetime.now()))
timing = pd.read_pickle(file)
sub, run, date = timing_files[file_idx].split("\\")[-1].split("_")[0:3]
d_file, timing_file, head_pp_d, eye_pp_d = find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data)
beh = pd.read_csv(d_file, index_col=0)
head = pd.read_pickle(head_pp_d)
eye = pd.read_pickle(eye_pp_d)
if print_b:
print(
d_file, "\n",
timing_file, "\n",
head_pp_d, "\n",
eye_pp_d
)
plot_trial_movements(beh, timing, head, eye, "all")
# single thread variant
if False:
plot_movements(False)
# parallel processing approach
def pp_plot_file_trials(file, timing_files, d_files, head_pp_data, eye_pp_data, print_b, plot_p):
import math
import os
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
def angle_of_vectors(vec1, vec2, rel_idx):
# dont use z
# vec1, vec2 = vec1[0:2], vec2[0:2]
scalar_product = np.dot(vec1, vec2)
amount_vec1 = math.sqrt(np.sum([math.pow(x, 2) for x in vec1])) # betrag
amount_vec2 = math.sqrt(np.sum([math.pow(x, 2) for x in vec2]))
if (amount_vec1 * amount_vec2) != 0:
angle = math.degrees(math.acos(scalar_product / (amount_vec1 * amount_vec2)))
else:
angle = np.nan
if vec1[rel_idx] < vec2[rel_idx]: # angle below / left are negative
angle = angle * (-1)
return angle
def get_trial_object_positions(stimulus_shift, probe_vert_pos):
fixation_size = 7.5 # 7.5 cm from center to outer edges
fixation_pos = 10 # -10 and 10 degree (horizontal axis)
stimulus_size = 10 # 10 cm from center to outer edges
ref_vert_pos = probe_vert_pos * -1
straight_vec = [250, 0, 0]
object_positions = {
"Fixation_Cross": {
"Left_Cross": {
"Left_Border": angle_of_vectors(straight_vec, [250, fixation_size, 0], 1) - fixation_pos,
"Right_Border": (angle_of_vectors(straight_vec, [250, fixation_size, 0], 1) + fixation_pos) * -1,
"Upper_Border": angle_of_vectors(straight_vec, [250, 0, -1 * fixation_size], 2),
"Lower_Border": angle_of_vectors(straight_vec, [250, 0, -1 * fixation_size], 2) * -1
},
"Right_Cross": {
"Left_Border": angle_of_vectors(straight_vec, [250, fixation_size, 0], 1) + fixation_pos,
"Right_Border": angle_of_vectors(straight_vec, [250, fixation_size, 0], 0) + fixation_pos,
"Upper_Border": angle_of_vectors(straight_vec, [250, 0, -1 * fixation_size], 2),
"Lower_Border": angle_of_vectors(straight_vec, [250, 0, -1 * fixation_size], 2) * -1
}
},
"Stimulus": {
"Probe": {
"Left_Border": angle_of_vectors(straight_vec, [250, stimulus_size + stimulus_shift, 0], 1),
"Right_Border": (angle_of_vectors(straight_vec, [250, stimulus_size + stimulus_shift, 0], 1)) * -1,
"Upper_Border": angle_of_vectors(straight_vec, [250, 0, probe_vert_pos + stimulus_size], 2),
"Lower_Border": angle_of_vectors(straight_vec, [250, 0, probe_vert_pos - stimulus_size], 2)# * -1
},
"Reference": {
"Left_Border": angle_of_vectors(straight_vec, [250, stimulus_size + stimulus_shift, 0], 1),
"Right_Border": (angle_of_vectors(straight_vec, [250, stimulus_size + stimulus_shift, 0], 1)) * -1,
"Upper_Border": angle_of_vectors(straight_vec, [250, 0, ref_vert_pos + stimulus_size], 2),
"Lower_Border": angle_of_vectors(straight_vec, [250, 0, ref_vert_pos - stimulus_size], 2)# * -1
}
}
}
return object_positions
def find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data):
d_file = [x for x in d_files if "{}_{}_{}".format(sub, run, date) in x]
timing_file = [x for x in timing_files if "{}_{}_{}".format(sub, run, date) in x]
head_pp_d = [x for x in head_pp_data if "{}_{}_{}".format(sub, run, date) in x]
eye_pp_d = [x for x in eye_pp_data if "{}_{}_{}".format(sub, run, date) in x]
for idx, x in enumerate([d_file, timing_file, head_pp_d, eye_pp_d]):
if len(x) > 1:
print(idx, "several files found")
print(np.array(x))
return d_file[0], timing_file[0], head_pp_d[0], eye_pp_d[0]
def plot_trial_movements(beh, timing, head, eye, num_trials):
sub, run = beh.iloc[0]["SubjectID"], beh.iloc[0]["Version"]
print("Started for: {}".format([sub, run]))
if num_trials == "all":
rows = timing
else:
rows = timing.iloc[0:num_trials]
for idx, row in rows.iterrows():
# get trial info
trial, pre, start, end, f_onset, f_offset, s_onset, s_offset = row
# print("Trial: {}".format(int(trial)))
trial_head = head.query('Time >= @pre & Time <= @end')
trial_eye = eye.query('Time >= @pre & Time <= @end')
stimuli_times = [(x - start) / 1_000_000 for x in [f_onset, f_offset, s_onset, s_offset]]
beh_trial = beh.query('TrialNum == @trial').iloc[0]
obj_positions = get_trial_object_positions(beh_trial["TargetHoriPos"], beh_trial["TargetVertPos"])
stim_positions = obj_positions["Stimulus"]
fix_positions = obj_positions["Fixation_Cross"]
for axis in ["Y", "Z"]:
save_p = plot_p.joinpath("trial_movements_pp", "{}_{}_{}_{}.png".format(sub, run, int(trial), axis))
if not os.path.exists(save_p):
head_col = "Yaw"
upper_border = "Left_Border"
lower_border = "Right_Border"
if axis == "Z":
head_col = "Pitch"
upper_border = "Upper_Border"
lower_border = "Lower_Border"
# create plot
fig, ax = plt.subplots(1,1, figsize=[6,5])
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.set_ylabel(axis)
# head eye plotting
head_times = [(x - start) / 1_000_000 for x in trial_head["Time"]]
ax.plot(head_times, trial_head[head_col], color="tab:blue", label="Head")
ax.plot([(x - start) / 1_000_000 for x in trial_eye["Time"]], trial_eye["EyeAngle_{}".format(axis)], color="tab:red", label="Eye")
# stimuli plotting
ax.plot(stimuli_times[0:2], [stim_positions["Probe"][upper_border], stim_positions["Probe"][upper_border]], color="b", label="Probe")
ax.plot(stimuli_times[0:2], [stim_positions["Probe"][lower_border], stim_positions["Probe"][lower_border]], color="b")
ax.plot(stimuli_times[2:], [stim_positions["Reference"][upper_border], stim_positions["Reference"][upper_border]], color="b", label="Reference")
ax.plot(stimuli_times[2:], [stim_positions["Reference"][lower_border], stim_positions["Reference"][lower_border]], color="b")
# fixation cross
ax.plot(stimuli_times[0:2], [fix_positions["Left_Cross"][upper_border]] * 2, color="k", label="Left Fixation Cross")
ax.plot(stimuli_times[0:2], [fix_positions["Left_Cross"][lower_border]] * 2, color="k")
ax.plot(stimuli_times[2:], [fix_positions["Right_Cross"][upper_border]] * 2, color="k", label="Right Fixation Cross")
ax.plot(stimuli_times[2:], [fix_positions["Right_Cross"][lower_border]] * 2, color="k")
ax.legend(bbox_to_anchor=(1, 0.15, 0.5, 0.5), frameon=False)
safe_save_fig(fig, save_p)
# plt.savefig(save_p, dpi=150, facecolor="white", bbox_inches="tight")
plt.close()
print("Finished for: {}".format([sub, run]))
def safe_save_fig(fig, path):
fig.savefig(path, dpi=150, facecolor="white", bbox_inches="tight")
timing = pd.read_pickle(file)
sub, run, date = file.split("\\")[-1].split("_")[0:3]
d_file, timing_file, head_pp_d, eye_pp_d = find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data)
beh = pd.read_csv(d_file, index_col=0)
head = pd.read_pickle(head_pp_d)
eye = pd.read_pickle(eye_pp_d)
if print_b:
print(
d_file, "\n",
timing_file, "\n",
head_pp_d, "\n",
eye_pp_d
)
plot_trial_movements(beh, timing, head, eye, "all")
###########################################################
if False:
from multiprocessing import Pool
import time
# in_arrs = [[file, timing_files, d_files, head_pp_data, eye_pp_data, False, plot_p] for file in timing_files]
in_arrs = [[timing_files[0], timing_files, d_files, head_pp_data, eye_pp_data, False, plot_p]]
start_t = time.perf_counter()
with Pool() as pool:
results = pool.map(pp_plot_file_trials, in_arrs)
for filename, duration in results:
print(f"{filename} completed in {duration:.2f}s")
end_t = time.perf_counter()
total_duration = end_t - start_t
print(f"took {total_duration:.2f}s total")
# files_to_process = timing_files#[:5]
# from multiprocessing.pool import ThreadPool as Pool
# with Pool(processes=len(files_to_process)) as pool:
# for file in files_to_process:
# result = pool.apply_async(func=pp_plot_file_trials,
# args=(file, timing_files, d_files, head_pp_data, eye_pp_data, False, plot_p,))
# # print(result.get())
# pool.close()
# pool.join()
# test new eye tracking preprocessing
if False:
files_to_process = ['c:\\Users\\serda\\Desktop\\CodeProjects\\UE\\ada_head_rot_eyetracking\\Z_Stats\\data\\Round Effmann\\Preprocessed\\AROA_NoMovement_15.11.2022_timings.pickle']
for file_idx, file in enumerate(files_to_process):
print("{} / {}: {}".format(file_idx + 1, len(files_to_process), datetime.now()))
timing = pd.read_pickle(file)
sub, run, date = timing_files[file_idx].split("\\")[-1].split("_")[0:3]
d_file, timing_file, head_pp_d, eye_pp_d = find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data)
beh = pd.read_csv(d_file, index_col=0)
head = pd.read_pickle(head_pp_d)
eye = pd.read_pickle(eye_pp_d)
print(
d_file, "\n",
timing_file, "\n",
head_pp_d, "\n",
eye_pp_d
)
plot_trial_movements(beh, timing, head, eye, [34])
# determine exclusion criteria for data
# manuscript 2\mp_data_exclusion.py
if False:
#C:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\effmann\plots\trial_movements_data
plot_data = bf.get_data(stats_p.joinpath("effmann", "plots", "trial_movements_data"), "pickle", "", [])
all_plot_data = pd.DataFrame()
for f in plot_data:
all_plot_data = pd.concat([all_plot_data, pd.read_pickle(f)])
d_dict = {}
keys = ["HeadPitch","HeadYaw","EyePitch","EyeYaw"]
for key in keys:
d_dict[key] = []
for key in keys:
[d_dict[key].extend(x) for x in all_plot_data[key]]
pd.Series(d_dict["EyeYaw"]).describe()
# exclude restrict eye data, head data fine
print("eye pitch: mean = 1.301, sd = 11.704, count = 6511301")
print("eye yaw: mean = -0.691, sd = 15.392, count = 6511301")
# exclusion based on speed (onset, offset)
def find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data):
d_file = [x for x in d_files if "{}_{}_{}".format(sub, run, date) in x]
timing_file = [x for x in timing_files if "{}_{}_{}".format(sub, run, date) in x]
head_pp_d = [x for x in head_pp_data if "{}_{}_{}".format(sub, run, date) in x]
eye_pp_d = [x for x in eye_pp_data if "{}_{}_{}".format(sub, run, date) in x]
for idx, x in enumerate([d_file, timing_file, head_pp_d, eye_pp_d]):
if len(x) > 1:
print(idx, "several files found")
print(np.array(x))
return d_file[0], timing_file[0], head_pp_d[0], eye_pp_d[0]
def plot_trial_movements(beh, timing, head, eye, trials):
sub, run = beh.iloc[0]["SubjectID"], beh.iloc[0]["Version"]
if trials == "all":
rows = timing
else:
rows = timing.query('Trial in @trials') #.iloc[0:trials]
for idx, row in rows.iterrows():
# get trial info
trial, pre, start, end, f_onset, f_offset, s_onset, s_offset = row
# print("Trial: {}".format(int(trial)))
trial_head = head.query('Time >= @pre & Time <= @end')
trial_eye = eye.query('Time >= @pre & Time <= @end')
stimuli_times = [(x - start) / 1_000_000 for x in [f_onset, f_offset, s_onset, s_offset]]
beh_trial = beh.query('TrialNum == @trial').iloc[0]
obj_positions = get_trial_object_positions(beh_trial["TargetHoriPos"], beh_trial["TargetVertPos"])
stim_positions = obj_positions["Stimulus"]
fix_positions = obj_positions["Fixation_Cross"]
for axis in ["Y", "Z"]:
head_col = "Yaw"
upper_border = "Left_Border"
lower_border = "Right_Border"
if axis == "Z":
head_col = "Pitch"
upper_border = "Upper_Border"
lower_border = "Lower_Border"
# create plot
fig, ax = plt.subplots(1,1, figsize=[6,5])
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.set_ylabel(axis)
# head eye plotting
head_times = [(x - start) / 1_000_000 for x in trial_head["Time"]]
# ax.plot(head_times, trial_head[head_col], color="tab:blue", label="Head")
eye_times = [(x - start) / 1_000_000 for x in trial_eye["Time"]]
eye_angles = list(trial_eye["EyeAngle_{}".format(axis)])
eye_speeds = []
for idx, angle in enumerate(eye_angles):
if idx == 0:
eye_speeds.append(0)
else:
angle_diff = angle - eye_angles[idx - 1]
time_diff = eye_times[idx] - eye_times[idx - 1]
try:
speed = abs(angle_diff / (time_diff / 1000))
eye_speeds.append(speed)
except:
eye_speeds.append(0)
excl_idxs = []
excl_following = False
follow_idx = -1
crit = 2500
crit_low = 500
# normal saccade speed 500°/s
for idx, speed in enumerate(eye_speeds):
if speed > crit or excl_following:
if not excl_following:
print("Starting to exclude: {}".format(eye_times[idx]))
# print(speed)
excl_following = True
follow_idx = idx
num_follow_samples = 3
excl_idxs.append(idx)
if excl_following and idx > follow_idx and speed > crit:
if num_follow_samples > 0:
num_follow_samples = num_follow_samples - 1
else:
excl_following = False
print("Stopping to exclude: {}".format(eye_times[idx]))
cut_eye_times = np.delete(np.array(eye_times), excl_idxs)
cut_eye_angles = np.delete(np.array(eye_angles), excl_idxs)
rel_idxs = [idx for idx, x in enumerate(eye_times) if x > 125 and x < 250]
for idx in rel_idxs:
print(eye_times[idx], eye_speeds[idx])
# print(excl_idxs)
ax.plot(eye_times, [x/100 for x in eye_speeds], color="tab:blue", label="Eye")
ax.plot(eye_times, eye_angles, color="tab:red", label="Eye", lw=6)
ax.plot(cut_eye_times, cut_eye_angles, color="tab:green", label="Eye", lw=3)
# print(cut_eye_times)
ax.set_xlim([100, 300])
# ax.set_ylim([0, 2500])
# # stimuli plotting
# ax.plot(stimuli_times[0:2], [stim_positions["Probe"][upper_border], stim_positions["Probe"][upper_border]], color="b", label="Probe")
# ax.plot(stimuli_times[0:2], [stim_positions["Probe"][lower_border], stim_positions["Probe"][lower_border]], color="b")
# ax.plot(stimuli_times[2:], [stim_positions["Reference"][upper_border], stim_positions["Reference"][upper_border]], color="b", label="Reference")
# ax.plot(stimuli_times[2:], [stim_positions["Reference"][lower_border], stim_positions["Reference"][lower_border]], color="b")
# # fixation cross
# ax.plot(stimuli_times[0:2], [fix_positions["Left_Cross"][upper_border]] * 2, color="k", label="Left Fixation Cross")
# ax.plot(stimuli_times[0:2], [fix_positions["Left_Cross"][lower_border]] * 2, color="k")
# ax.plot(stimuli_times[2:], [fix_positions["Right_Cross"][upper_border]] * 2, color="k", label="Right Fixation Cross")
# ax.plot(stimuli_times[2:], [fix_positions["Right_Cross"][lower_border]] * 2, color="k")
plt.show()
plt.close()
# ALKA_MovementGain_ 100-300 31, 57
if False:
files_to_process = [x for x in timing_files if "ALKA_MovementGain_" in x] #[:1]
for file_idx, file in enumerate(files_to_process):
print("{} / {}: {}".format(file_idx + 1, len(files_to_process), datetime.now()))
timing = pd.read_pickle(file)
sub, run, date = file.split("\\")[-1].split("_")[0:3]
d_file, timing_file, head_pp_d, eye_pp_d = find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data)
beh = pd.read_csv(d_file, index_col=0)
head = pd.read_pickle(head_pp_d)
eye = pd.read_pickle(eye_pp_d)
# print(d_file, "\n", timing_file, "\n", head_pp_d, "\n", eye_pp_d)
plot_trial_movements(beh, timing, head, eye, [31, 57])
# test speed crit
if False:
eye = pd.read_pickle(r"C:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\data\Round Effmann\Preprocessed\TSSE_MovementGain_20.12.2022_eye.pickle")
timing = pd.read_pickle(r"C:\Users\serda\Desktop\CodeProjects\UE\ada_head_rot_eyetracking\Z_Stats\data\Round Effmann\Preprocessed\TSSE_MovementGain_20.12.2022_timings.pickle")
# TSSE_MovementGain_49
timing = timing.iloc[48:49]
for idx, row in timing.iterrows():
trial, pre, start, end, f_onset, f_offset, s_onset, s_offset = row
trial_eye = eye.query('Time >= @pre & Time <= @end')
stimuli_times = [(x - start) / 1_000_000 for x in [f_onset, f_offset, s_onset, s_offset]]
for axis in ["Y"]: #, "Z"
fig, ax = plt.subplots(1,1, figsize=[6,5])
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.set_ylabel(axis)
trial_eye_axis = trial_eye.assign(Time = [(x - start) / 1_000_000 for x in trial_eye["Time"]])
trial_eye_axis = trial_eye_axis.assign(EyeAngle = list(trial_eye["EyeAngle_{}".format(axis)]))
trial_eye_filtered = trial_eye_axis.query('EyeAngle < 20 & EyeAngle > -20')
eye_speeds = []
last_idx = list(trial_eye_filtered.index)[0]
for idx, row in trial_eye_filtered.iterrows():
if idx == 0:
eye_speeds.append(0)
else:
angle_diff = row["EyeAngle"] - trial_eye_filtered["EyeAngle"].loc[last_idx]
time_diff = trial_eye_filtered["Time"].loc[idx] - trial_eye_filtered["Time"].loc[last_idx]
try:
speed = abs(angle_diff / (time_diff / 1000))
eye_speeds.append(speed)
except:
eye_speeds.append(0)
last_idx = idx
trial_eye_filtered = trial_eye_filtered.assign(Speed = eye_speeds)
spike_starts = []
spike_ends = []
spike_start_detected = False
speed_crit = 500
for idx, row in trial_eye_filtered.iterrows():
if row["Speed"] > speed_crit and not spike_start_detected:
spike_starts.append(idx)
spike_start_detected = True
else:
if spike_start_detected and row["Speed"] > speed_crit:
spike_ends.append(idx)
spike_start_detected = False
excl_idxs = []
for start, end in zip(spike_starts, spike_ends):
if start and end:
excl_idxs.extend(range(start, end + 1))
print(spike_starts)
print(spike_ends)
trial_eye_filtered = trial_eye_filtered.drop(excl_idxs)
# head eye plotting
ax.plot(trial_eye_axis["Time"], trial_eye_axis["EyeAngle"], color="tab:blue")
ax.plot(trial_eye_filtered["Time"], trial_eye_filtered["EyeAngle"], color="tab:red")
# ax.plot(trial_eye_filtered["Time"], trial_eye_filtered["Speed"], color="tab:green")
# ax.set_ylim([-100, 1000])
# check pp progress
if False:
move_files = bf.get_data(plot_p.joinpath("trial_movements_pp_final"), "png", "", [])
last_count = 0
final_count = 29040
while final_count > len(move_files):
move_files = bf.get_data(plot_p.joinpath("trial_movements_pp_final"), "png", "", [])
if (len(move_files) - last_count) >= 1000:
print("{} / {}".format(len(move_files), final_count))
last_count = len(move_files)
# stim infos
# fixaton object infos
# -10 and 10 degree (horizontal axis)
# 0 degree vertical pos
# size from center 7.5 cm to both sides
# stimulus
# 0 degree (horizontal axis)
# 10 cm to both sides
# 20 cm durchmesser
# funcs
def get_trial_object_positions(stimulus_shift, probe_vert_pos):
fixation_size = 7.5 # 7.5 cm from center to outer edges
fixation_pos = 10 # -10 and 10 degree (horizontal axis)
stimulus_size = 10 # 10 cm from center to outer edges
ref_vert_pos = probe_vert_pos * -1
straight_vec = [250, 0, 0]
object_positions = {
"Fixation_Cross": {
"Left_Cross": {
"Left_Border": angle_of_vectors(straight_vec, [250, fixation_size, 0], 1) - fixation_pos,
"Right_Border": (angle_of_vectors(straight_vec, [250, fixation_size, 0], 1) + fixation_pos) * -1,
"Upper_Border": angle_of_vectors(straight_vec, [250, 0, -1 * fixation_size], 2),
"Lower_Border": angle_of_vectors(straight_vec, [250, 0, -1 * fixation_size], 2) * -1
},
"Right_Cross": {
"Left_Border": angle_of_vectors(straight_vec, [250, fixation_size, 0], 1) + fixation_pos,
"Right_Border": angle_of_vectors(straight_vec, [250, fixation_size, 0], 0) + fixation_pos,
"Upper_Border": angle_of_vectors(straight_vec, [250, 0, -1 * fixation_size], 2),
"Lower_Border": angle_of_vectors(straight_vec, [250, 0, -1 * fixation_size], 2) * -1
}
},
"Stimulus": {
"Probe": {
"Left_Border": angle_of_vectors(straight_vec, [250, stimulus_size + stimulus_shift, 0], 1),
"Right_Border": (angle_of_vectors(straight_vec, [250, stimulus_size + stimulus_shift, 0], 1)) * -1,
"Upper_Border": angle_of_vectors(straight_vec, [250, 0, probe_vert_pos + stimulus_size], 2),
"Lower_Border": angle_of_vectors(straight_vec, [250, 0, probe_vert_pos - stimulus_size], 2)# * -1
},
"Reference": {
"Left_Border": angle_of_vectors(straight_vec, [250, stimulus_size + stimulus_shift, 0], 1),
"Right_Border": (angle_of_vectors(straight_vec, [250, stimulus_size + stimulus_shift, 0], 1)) * -1,
"Upper_Border": angle_of_vectors(straight_vec, [250, 0, ref_vert_pos + stimulus_size], 2),
"Lower_Border": angle_of_vectors(straight_vec, [250, 0, ref_vert_pos - stimulus_size], 2)# * -1
}
}
}
return object_positions
def find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data):
d_file = [x for x in d_files if "{}_{}_{}".format(sub, run, date) in x]
timing_file = [x for x in timing_files if "{}_{}_{}".format(sub, run, date) in x]
head_pp_d = [x for x in head_pp_data if "{}_{}_{}".format(sub, run, date) in x]
eye_pp_d = [x for x in eye_pp_data if "{}_{}_{}".format(sub, run, date) in x]
for idx, x in enumerate([d_file, timing_file, head_pp_d, eye_pp_d]):
if len(x) > 1:
print(idx, "several files found")
print(np.array(x))
return d_file[0], timing_file[0], head_pp_d[0], eye_pp_d[0]
# write out stimuli infos for manuscript
if False:
object_positions = get_trial_object_positions(3, 100)
for obj in ["Fixation_Cross", "Stimulus"]:
keys = object_positions[obj].keys()
# for key in keys:
# print(obj, key, object_positions[obj][key])
df_dict = {}
keys = ["Stimulus", "StimulusName", "Border", "BorderValue"]
for key in keys:
df_dict[key] = []
for k in object_positions:
for ke in object_positions[k]:
for key in object_positions[k][ke]:
for d_key, val in zip(keys, [k, ke, key, object_positions[k][ke][key]]):
df_dict[d_key].append(val)
pd.DataFrame(df_dict).to_pickle(stats_p.joinpath("effmann", "results", "stimuli_infos.pickle"))
# func to check for fixation
def check_fixation(sources, axes, stimuli_times, fix_positions, mercy_coef, eye_df, head_df, info, print_b, save_plots, save_dir):
ret = True
save_dir = save_dir.joinpath(info[0])
if not os.path.exists(save_dir):
os.makedirs(save_dir, exist_ok=True)
num_eye_outlier = 0
num_head_outlier = 0
for axis in axes:
for fixation_cross in ["Left_Cross", "Right_Cross"]:
if axis == "Y":
head_col = "Yaw"
up_border_name = "Right_Border"
low_border_name = "Left_Border"
eye_col = "EyeAngle_{}".format(axis)
elif axis == "Z":
head_col = "Pitch"
up_border_name = "Upper_Border"
low_border_name = "Lower_Border"
eye_col = "EyeAngle_{}".format(axis)
upper_border = fix_positions[fixation_cross][up_border_name]
lower_border = fix_positions[fixation_cross][low_border_name]
upper_border_corr = upper_border + ((upper_border - lower_border) * mercy_coef)
lower_border_corr = lower_border - ((upper_border - lower_border) * mercy_coef)
head_upper_border_corr = upper_border + ((upper_border - lower_border) * mercy_coef * 2)
head_lower_border_corr = lower_border - ((upper_border - lower_border) * mercy_coef * 2)
# cut trial dfs to fixtion time windows
if fixation_cross == "Left_Cross":
cross_times = stimuli_times[0:2]
eye_df_window = eye_df.query('(Time >= @cross_times[0] & Time <= @cross_times[1])')
head_df_window = head_df.query('(Time >= @cross_times[0] & Time <= @cross_times[1])')
else:
cross_times = stimuli_times[2:]
eye_df_window = eye_df.query('(Time >= @cross_times[0] & Time <= @cross_times[1])')
head_df_window = head_df.query('(Time >= @cross_times[0] & Time <= @cross_times[1])')
eye_df_outlier = eye_df_window.query('`{0}` > @upper_border_corr | `{0}` < @lower_border_corr'.format(eye_col))
num_eye_outlier = num_eye_outlier + eye_df_outlier.shape[0]
head_df_outlier = head_df_window.query('`{0}` > @head_upper_border_corr | `{0}` < @head_lower_border_corr'.format(head_col))
num_head_outlier = num_head_outlier + head_df_outlier.shape[0]
if save_plots:
if "eye" in sources:
plt.scatter(eye_df_window["Time"], eye_df_window[eye_col], color="tab:red", label="eye")
plt.scatter(eye_df_outlier["Time"], eye_df_outlier[eye_col], color="k", label="outlier")
if "head" in sources:
plt.scatter(head_df_window["Time"], head_df_window[head_col], color="tab:blue", label="head")
plt.scatter(head_df_outlier["Time"], head_df_outlier[head_col], color="k")
# fixation cross
plt.plot(cross_times, [fix_positions[fixation_cross][up_border_name]] * 2, color="grey", label=fixation_cross)
plt.plot(cross_times, [fix_positions[fixation_cross][low_border_name]] * 2, color="grey")
plt.legend(loc="best", frameon=False)
plt.savefig(save_dir.joinpath("{}_{}_{}.png".format(info, axis, fixation_cross)), facecolor="white", dpi=150)
plt.close()
# prep return
outliers = 0
if "eye" in sources:
outliers = outliers + num_eye_outlier
if "head" in sources:
outliers = outliers + num_head_outlier
if outliers > 0:
ret = False
if print_b:
print("{}: eye: {} / {}, head: {} / {}".format(info, num_eye_outlier, eye_df.shape[0] * 2, num_head_outlier, head_df.shape[0] * 2))
return ret
# trial exclusion
def add_fixation_to_timing_file(file, coef, excl_sources, excl_axes, print_info, save_plots, save_dir):
timing = pd.read_pickle(file)
sub, run, date = file.split("\\")[-1].split("_")[0:3]
d_file, timing_file, head_pp_d, eye_pp_d = find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data)
beh = pd.read_csv(d_file, index_col=0)
head = pd.read_pickle(head_pp_d)
eye = pd.read_pickle(eye_pp_d)
inc_col = []
for idx, row in timing.iterrows():
trial, pre, start, end, f_onset, f_offset, s_onset, s_offset = row
trial_head = head.query('Time >= @pre & Time <= @end')
trial_eye = eye.query('Time >= @pre & Time <= @end')
stimuli_times = [(x - start) / 1_000_000 for x in [f_onset, f_offset, s_onset, s_offset]]
trial_head = trial_head.assign(Time = [(x - start) / 1_000_000 for x in trial_head["Time"]])
trial_eye = trial_eye.assign(Time = [(x - start) / 1_000_000 for x in trial_eye["Time"]])
beh_trial = beh.query('TrialNum == @trial').iloc[0]
obj_positions = get_trial_object_positions(beh_trial["TargetHoriPos"], beh_trial["TargetVertPos"])
fix_positions = obj_positions["Fixation_Cross"]
# val = np.mean(trial_eye_axis["VectorX"]) - 10
# trial_eye_filtered = trial_eye_axis.query('VectorX >= @val') # 220
# check if fixated
fixated = check_fixation(excl_sources, excl_axes, stimuli_times, fix_positions, coef, trial_eye, trial_head, [sub, run, trial], print_info, save_plots, save_dir)
inc_col.append(fixated)
if not fixated:
print("{}: failed to fixate".format([sub, run, int(trial)]))
new_col = {"Included_{}".format(coef): inc_col}
timing = timing.assign(**new_col)
df_save_p = dfs_p.joinpath("trial_exclusions", "{}.pickle".format([sub, run, trial]))
timing.to_pickle(df_save_p)
# return timing
if False:
file = [x for x in timing_files if "AROA_NoMovement_" in x][0]
save_plot_dir = plot_p.joinpath("fixation_plots")
# test = add_fixation_to_timing_file(file, 0.5, ["eye"], ["Y", "Z"], False, True, save_plot_dir)
# trial exclusion based on fixation now also with parallel processing (mp_check_trial_fixation)
# ahr 1 - head movement detection funcs
def calc_speeds(df, pos_col):
# select only rows where yaw is different the next time stamp
idxs = []
for idx, row in df.iterrows():
if idx == df.index[0]:
idxs.append(idx)
else:
curr_yaw = row[pos_col]
prior_yaw = df.loc[prior_idx][pos_col]
if (curr_yaw - prior_yaw) != 0:
idxs.append(idx)
prior_idx = idx
df = df.loc[idxs]
# stop if too few points
moving_average_num = 10 # 10
if df.shape[0] > moving_average_num:
# calc speeds
speeds = []
for idx, row in df.iterrows():
if idx == list(df.index)[0]:
speeds.append(0)
prior_speed = 0
else:
yaw_diff = row[pos_col] - df.loc[prior_idx][pos_col]
time_diff = row["Time"] - df.loc[prior_idx]["Time"]
if time_diff == 0 or yaw_diff == 0 or (time_diff / 1_000) == 0:
speeds.append(prior_speed)
else:
speed = abs(yaw_diff / (time_diff / 1_000)) #1_000_000 since it is in um
# print("Speed calculated: {}".format(speed))
if speed > 250:
speeds.append(prior_speed)
speed = prior_speed
else:
speeds.append(speed)
prior_speed = speed
prior_idx = idx
df = df.assign(Speed = speeds)
# moving average
new_speeds = []
curr_speeds = df["Speed"]
for idx, speed in enumerate(curr_speeds):
if idx < (len(curr_speeds) - moving_average_num):
avg_speed = np.mean(curr_speeds[idx:idx+moving_average_num])
new_speeds.append(avg_speed)
# print(idx, "Worked")
else:
# print(idx, "Failed")
new_speeds.append(avg_speed)
# new_speeds.append(np.mean(curr_speeds[idx:]))
df = df.assign(Speed = new_speeds)
else:
df = pd.DataFrame()
return df
def detect_best_speed_peak(df):
peaks = []
max_speeds = np.sort(df["Speed"])[::-1]
for idx, speed in enumerate(max_speeds):
time_point = df.iloc[list(df["Speed"]).index(speed)]["Time"] #/ 1_000
if idx == 0:
peaks.append([speed, time_point])
else:
too_close = False
for peak, time_p in peaks:
if abs(time_point - time_p) < 200_000:
too_close = True
if not too_close:
peaks.append([speed, time_point])
highest_peak = max_speeds[0]
best_peaks = [peak for peak in peaks if peak[0] >= (highest_peak / 2)]
return best_peaks[0][1]
def find_trial_limits(df, best_peak_time, speed_crit):
start_df = df[df["Time"] <= best_peak_time][::-1] # we search from peak to trial start until speed too low
end_df = df[df["Time"] >= best_peak_time]
start = -1
end = -1
# speed_crit = 3 # 3
# find start
for idx, row in start_df.iterrows():
point_speed = start_df.loc[idx]["Speed"] # np.mean(start_df.loc[idx:idx - future_points]["Speed"])
if point_speed < speed_crit and start == -1: # < 3 since we go right to left
start = idx
if start == -1:
# print("Failed", start, start_df["Time"].loc[start])
start = list(df.index)[0]
# else:
# print("Success", start, start_df["Time"].loc[start])
# find end
for idx, row in end_df.iterrows():
point_speed = end_df.loc[idx]["Speed"] # np.mean(end_df.loc[idx:idx + future_points]["Speed"])
if point_speed < speed_crit and end == -1:
end = idx
if end == -1:
end = list(df.index)[-1]
return start, end
def detect_head_movement(df, pos_col, speed_crit):
max_yaw = max([abs(x) for x in df[pos_col]])
start_yaw = abs(df.loc[df.index[0]][pos_col])
df = calc_speeds(df, pos_col)
if df.shape[0] > 0:
speeds = df["Speed"]
# detect head movements
best_peak_time = detect_best_speed_peak(df)
trial_start, trial_end = find_trial_limits(df, best_peak_time, speed_crit)
move_df = df.loc[trial_start:trial_end]
else:
move_df = df
return move_df
# test old head movement detection funcs
if False:
timing_file = timing_files[0]
timing_df = pd.read_pickle(timing_file)
sub, run, date = timing_file.split("\\")[-1].split("_")[0:3]
d_file, timing_file, head_pp_d, eye_pp_d = find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data)
head_df = pd.read_pickle(head_pp_d)
trial, pre, start, end, f_onset, f_offset, s_onset, s_offset = timing_df.iloc[0]
trial_head = head_df.query('Time >= @pre & Time <= @end')
trial_head = trial_head.assign(Time = [(x - start) / 1_000_000 for x in trial_head["Time"]])
move_df = detect_head_movement(trial_head, "Yaw")
# move_df
plt.plot(trial_head["Time"], trial_head["Yaw"], color="k")
plt.plot(move_df["Time"], move_df["Yaw"], color="r")
# funcs for condition description
def check_arrival_time(df, pos_col, time_col, lower_bound, upper_bound, info):
idxs_in_bounds = [idx for idx, row in df.iterrows() if row[pos_col] >= lower_bound and row[pos_col] <= upper_bound]
in_bounds_time = 0
if len(idxs_in_bounds) > 0:
try:
in_bounds_time = df[time_col].loc[idxs_in_bounds[0]]
except:
print("Info: {}, DF Shape: {}, Num poss Idxs: {}".format(info, df.shape[0], len(idxs_in_bounds)))
return in_bounds_time
def check_fixation_duration(df, time_col, pos_col, time_start, time_end, lower_bound, upper_bound):
window_df = df.query('`{0}` >= @time_start & `{0}` <= @time_end'.format(time_col))
fixation_df = window_df.query('`{0}` >= @lower_bound & `{0}` <= @upper_bound'.format(pos_col))
fixation_duration = 0
fixation_start = window_df.iloc[-1]["Time"]
if fixation_df.shape[0] > 0:
fixation_duration = (time_end - time_start) * (fixation_df.shape[0] / window_df.shape[0])
fixation_start = fixation_df["Time"].iloc[0]
ret_dict = {
"total_data_points": [window_df.shape[0]],
"fixation_data_points": [fixation_df.shape[0]],
"total_duration": [time_end - time_start],
"fixation_duration": [fixation_duration],
"fixation_start": [fixation_start]
}
return pd.DataFrame(ret_dict)
def get_mercy_bounds(obj_positions, mercy_coef):
keys = [
"left_cross_y_lower", "left_cross_y_upper", "left_cross_z_lower", "left_cross_z_upper",
"right_cross_y_lower", "right_cross_y_upper", "right_cross_z_lower", "right_cross_z_upper",
"probe_y_lower", "probe_y_upper", "probe_z_lower", "probe_z_upper",
"reference_y_lower", "reference_y_upper", "reference_z_lower", "reference_z_upper"
]
ret_dict = {}
for key in keys:
if "cross" in key:
stim_type = "Fixation_Cross"
if "left_cross_" in key:
stim = "Left_Cross"
else:
stim = "Right_Cross"
else:
stim_type = "Stimulus"
if "Probe" in key:
stim = "Probe"
else:
stim = "Reference"
if "_y_" in key:
lb = "Left_Border"
ub = "Right_Border"
else:
lb = "Lower_Border"
ub = "Upper_Border"
if "_lower" in key:
bound = obj_positions[stim_type][stim][lb] - ((obj_positions[stim_type][stim][ub] - obj_positions[stim_type][stim][lb]) * mercy_coef)
else:
bound = obj_positions[stim_type][stim][ub] + ((obj_positions[stim_type][stim][ub] - obj_positions[stim_type][stim][lb]) * mercy_coef)
ret_dict[key] = bound
return ret_dict
def check_trial_head_eye_pattern(timing_file, mercy_coef, d_files, timing_files, head_pp_data, eye_pp_data, create_plots, plot_dir):
keys = ["SubjectID", "Run", "Trial",
"EyeArrivalRightCrossY", "EyeArrivalRightCrossZ",
"HeadArrivalRightCrossY", "HeadArrivalRightCrossZ",
"EyeArrivedFirstY", "EyeArrivedFirstZ",
"FixDurLeftCrossY", "FixDurLeftCrossZ", "FixDurRightCrossY", "FixDurRightCrossZ",
"RightCrossFixEyeDuringHeadMovement_Y", "RightCrossFixEyeDuringHeadMovement_Z",
"HeadMoveDurationY", "HeadMovePeakVelocityY", "HeadMoveAmplitudeY"]
ret_df = {}
for key in keys:
ret_df[key] = []
time_col = "Time"
timing_df = pd.read_pickle(timing_file)
sub, run, date = timing_file.split("\\")[-1].split("_")[0:3]
df_save_p = dfs_p.joinpath("movement_pattern", "{}.pickle".format([sub, run]))
d_file, timing_file, head_pp_d, eye_pp_d = find_correct_files(sub, run, date, d_files, timing_files, head_pp_data, eye_pp_data)
beh_df = pd.read_csv(d_file, index_col=0)
head_df = pd.read_pickle(head_pp_d)
eye_df = pd.read_pickle(eye_pp_d)
print("Started for {} {}".format(sub, run))
for idx, row in timing_df.iterrows():
trial, pre, start, end, f_onset, f_offset, s_onset, s_offset = row
f_onset, f_offset, s_onset, s_offset = [(x - start) / 1_000_000 for x in [f_onset, f_offset, s_onset, s_offset]]
beh_trial = beh_df.query('TrialNum == @trial').iloc[0]
obj_positions = get_trial_object_positions(beh_trial["TargetHoriPos"], beh_trial["TargetVertPos"])
mercy_bounds = get_mercy_bounds(obj_positions, mercy_coef)
# "left_cross_y_lower", "left_cross_y_upper", "left_cross_z_lower", "left_cross_z_upper",
# "right_cross_y_lower", "right_cross_y_upper", "right_cross_z_lower", "right_cross_z_upper",
# "probe_y_lower", "probe_y_upper", "probe_z_lower", "probe_z_upper",
# "reference_y_lower", "reference_y_upper", "reference_z_lower", "reference_z_upper"
trial_eye = eye_df.query('Time >= @pre & Time <= @end')
trial_eye = trial_eye.assign(Time = [(x - start) / 1_000_000 for x in trial_eye["Time"]])
trial_head = head_df.query('Time >= @pre & Time <= @end')
trial_head = trial_head.assign(Time = [(x - start) / 1_000_000 for x in trial_head["Time"]])
# print("First Onset: {}".format(f_onset))
# print("Eye: {}".format(trial_eye["Time"].iloc[0]))
# print("Head: {}".format(trial_head["Time"].iloc[0]))
# get values of interest
eye_arrive_right_cross_y = check_arrival_time(trial_eye, "EyeAngle_Y", time_col, mercy_bounds["right_cross_y_lower"], mercy_bounds["right_cross_y_upper"], [sub, run, trial])
eye_arrive_right_cross_z = check_arrival_time(trial_eye, "EyeAngle_Z", time_col, mercy_bounds["right_cross_z_lower"], mercy_bounds["right_cross_z_upper"], [sub, run, trial])
head_arrive_right_cross_y = check_arrival_time(trial_head, "Yaw", time_col, mercy_bounds["right_cross_y_lower"], mercy_bounds["right_cross_y_upper"], [sub, run, trial])
head_arrive_right_cross_z = check_arrival_time(trial_head, "Pitch", time_col, mercy_bounds["right_cross_z_lower"], mercy_bounds["right_cross_z_upper"], [sub, run, trial])
eye_fix_left_cross_y = check_fixation_duration(trial_eye, time_col, "EyeAngle_Y", f_onset, f_offset, mercy_bounds["left_cross_y_lower"], mercy_bounds["left_cross_y_upper"])
eye_fix_left_cross_z = check_fixation_duration(trial_eye, time_col, "EyeAngle_Z", f_onset, f_offset, mercy_bounds["left_cross_z_lower"], mercy_bounds["left_cross_z_upper"])
eye_fix_right_cross_y = check_fixation_duration(trial_eye, time_col, "EyeAngle_Y", s_onset, s_offset, mercy_bounds["right_cross_y_lower"], mercy_bounds["right_cross_y_upper"])
eye_fix_right_cross_z = check_fixation_duration(trial_eye, time_col, "EyeAngle_Z", s_onset, s_offset, mercy_bounds["right_cross_z_lower"], mercy_bounds["right_cross_z_upper"])
eye_arrived_first_y = True
if head_arrive_right_cross_y < eye_arrive_right_cross_y:
eye_arrived_first_y = False
eye_arrived_first_z = True
if head_arrive_right_cross_z < eye_arrive_right_cross_z:
eye_arrived_first_z = False
head_movement_df = detect_head_movement(trial_head, "Yaw")
head_move_duration = list(head_movement_df[time_col])[-1] - list(head_movement_df[time_col])[0]
head_peak_velocity = max(head_movement_df["Speed"])
head_amplitude = max(head_movement_df["Yaw"]) - min(head_movement_df["Yaw"]) #list(head_movement_df["Yaw"])[-1] - list(head_movement_df["Yaw"])[0]
head_movement_start = list(head_movement_df[time_col])[0]
head_movement_end = list(head_movement_df[time_col])[-1]
trial_eye_movement = trial_eye.query('Time >= @head_movement_start & Time <= @head_movement_end')
eye_fix_right_cross_during_head_y = check_fixation_duration(trial_eye_movement, time_col, "EyeAngle_Y", head_movement_start, head_movement_end, mercy_bounds["right_cross_y_lower"], mercy_bounds["right_cross_y_upper"])
eye_fix_right_cross_during_head_z = check_fixation_duration(trial_eye_movement, time_col, "EyeAngle_Z", head_movement_start, head_movement_end, mercy_bounds["right_cross_z_lower"], mercy_bounds["right_cross_z_upper"])
# save values
vals = [sub, run, int(trial),
eye_arrive_right_cross_y, eye_arrive_right_cross_z,
head_arrive_right_cross_y, head_arrive_right_cross_z,
eye_arrived_first_y, eye_arrived_first_z,
eye_fix_left_cross_y["fixation_duration"].iloc[0], eye_fix_left_cross_z["fixation_duration"].iloc[0],
eye_fix_right_cross_y["fixation_duration"].iloc[0], eye_fix_right_cross_z["fixation_duration"].iloc[0],
eye_fix_right_cross_during_head_y["fixation_duration"].iloc[0], eye_fix_right_cross_during_head_z["fixation_duration"].iloc[0],
head_move_duration, head_peak_velocity, head_amplitude]
for key, val in zip(keys, vals):
ret_df[key].append(val)
if create_plots:
# calculations
left_eye_fix_start = eye_fix_left_cross_y["fixation_start"].iloc[0]
left_eye_fix_end = left_eye_fix_start + eye_fix_left_cross_y["fixation_duration"].iloc[0]
trial_eye_left_fix = trial_eye.query('Time >= @left_eye_fix_start & Time <= @left_eye_fix_end')
right_eye_fix_start = eye_fix_right_cross_y["fixation_start"].iloc[0]
right_eye_fix_end = right_eye_fix_start + eye_fix_right_cross_y["fixation_duration"].iloc[0]
trial_eye_right_fix = trial_eye.query('Time >= @right_eye_fix_start & Time <= @right_eye_fix_end')
right_eye_fix_start_during_head = eye_fix_right_cross_during_head_y["fixation_start"].iloc[0]
right_eye_fix_during_head = trial_eye.query('Time >= @right_eye_fix_start_during_head & Time <= @head_movement_end')
# plotting
fig, ax = plt.subplots(1,1,figsize=[7,5])
ax.spines['top'].set_visible(False)
ax.spines['right'].set_visible(False)
ax.set_xlabel("Time [ms]")
ax.set_ylabel("Horizontal Pos [°]")
big = 4
small = 1.5
# base
ax.plot(trial_eye["Time"], trial_eye["EyeAngle_Y"], color="tab:red", alpha = 0.5, lw=big, label="eye")
ax.plot(trial_head["Time"], trial_head["Yaw"], color="tab:blue", alpha = 0.5, lw=big, label="head")
ax.plot(head_movement_df["Time"], head_movement_df["Yaw"], color="tab:blue", label="head_movement")
# ax.plot(head_movement_df["Time"], head_movement_df["Speed"], color="g", label="head speed")
# fixation
ax.plot(right_eye_fix_during_head["Time"], right_eye_fix_during_head["EyeAngle_Y"], color="tab:green", lw=big, label="eye fixation (head movement)")
ax.plot(trial_eye_left_fix["Time"], trial_eye_left_fix["EyeAngle_Y"], color="tab:red", lw=small, label="eye fixation")
ax.plot(trial_eye_right_fix["Time"], trial_eye_right_fix["EyeAngle_Y"], color="tab:red", lw=small)
# arrivals
ax.plot([eye_arrive_right_cross_y] * 2, [-15, 15], color="tab:red", ls="--", label="eye arrival")
ax.plot([head_arrive_right_cross_y] * 2, [-15, 15], color="tab:blue", ls="--", label="head arrival")
# stimuli
ax.plot([f_onset, f_offset], [mercy_bounds["left_cross_y_lower"]] * 2, color="k", label="fix cross")
ax.plot([f_onset, f_offset], [mercy_bounds["left_cross_y_upper"]] * 2, color="k")
ax.plot([s_onset, s_offset], [mercy_bounds["right_cross_y_lower"]] * 2, color="k")
ax.plot([s_onset, s_offset], [mercy_bounds["right_cross_y_upper"]] * 2, color="k")
ax.legend(loc='center right', bbox_to_anchor=(1.5, 0.5, 0.0, 0.0), frameon=False)
fig.savefig(plot_dir.joinpath("{}_{}_{}.png".format(sub, run, int(trial))), facecolor="white", dpi=150, bbox_inches="tight")
plt.close()
ret_df = pd.DataFrame(ret_df)
ret_df.to_pickle(df_save_p)
print("Finished for {} {}".format(sub, run))
# do testing of data collection
if False:
timing_file = timing_files[0]
mercy_coef = 0.5
create_plots = True
plot_dir = plot_p.joinpath("trial_movements_data_collection")
check_trial_head_eye_pattern(timing_file, mercy_coef, d_files, timing_files, head_pp_data, eye_pp_data, create_plots, plot_dir)
# check mercy bound calculation
if False:
beh_df = pd.read_csv(d_files[0])
trial = 1
beh_trial = beh_df.query('TrialNum == @trial').iloc[0]
obj_positions = get_trial_object_positions(beh_trial["TargetHoriPos"], beh_trial["TargetVertPos"])
# get_mercy_bounds(obj_positions, 0.5)
get_mercy_bounds(obj_positions, 0.5)
# trial movement pattern info now also with mp (mp_trial_movement_pattern)
# check how far pp progressed
if False:
move_files = bf.get_data(dfs_p.joinpath("movement_pattern"), "pickle", "", [])
day_start = datetime.fromisoformat('2023-05-30') #datetime.today()
modified_today = []
last_count = 0
while len(modified_today) < len(move_files):
modified_today = []
for f in move_files:
time_modified = path.Path(f).stat().st_mtime
time_modified_conv = datetime.fromtimestamp(time_modified)
if time_modified_conv > day_start:
# print(time_modified_conv)
modified_today.append(f)
if len(modified_today) > last_count:
print("{} / {}".format(len(modified_today), len(move_files)))
last_count = len(modified_today)