From 85e95e10c3ee64e29005e9d9161a0b7c1fd8331f Mon Sep 17 00:00:00 2001 From: Eshref Yozdemir Date: Wed, 15 Apr 2020 10:39:14 +0200 Subject: [PATCH 1/2] Fix experiment 7 valid fixations crash --- examples/pspm_pupil/exp7/bench.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/pspm_pupil/exp7/bench.py b/examples/pspm_pupil/exp7/bench.py index 8239a28..4d64281 100644 --- a/examples/pspm_pupil/exp7/bench.py +++ b/examples/pspm_pupil/exp7/bench.py @@ -15,20 +15,23 @@ MODEL_PATH = "exp7" EXP_OUTPUT_PATH = pathjoin(util.OUT_PATH, MODEL_PATH) -PP_LIST = ["pfe", "valid_fixations"] if __name__ == "__main__": os.makedirs(EXP_OUTPUT_PATH, exist_ok=True) # prepare models + model_list = [ + ("pfe", {}), + ("valid_fixations", {"fixation_angle": 5.0}), + ] models = [ PsPMModel( lib_paths=util.LIB_PATHS, import_base_path=MODEL_PATH, predict_fn="fit_all", - model_spec={"model_str": pp}, - name=pp, + model_spec=dict({"model_str": model_str}, **params), + name=model_str, ) - for pp in PP_LIST + for model_str, params in model_list ] suite = util.get_test_suite(EXP_OUTPUT_PATH) From 97f84b780260f6ac61e0d651aad6b42c079eb426 Mon Sep 17 00:00:00 2001 From: Eshref Yozdemir Date: Wed, 15 Apr 2020 11:31:51 +0200 Subject: [PATCH 2/2] Document libcommon functions in pupil bench exp --- examples/pspm_pupil/exp1/fit.m | 2 +- examples/pspm_pupil/exp2/fit.m | 2 +- examples/pspm_pupil/exp4/fit.m | 2 +- .../pspm_pupil/libcommon/exclude_and_average.m | 16 +++++++++++++++- examples/pspm_pupil/libcommon/fit_all.m | 16 ++++++++++++++++ examples/pspm_pupil/libcommon/get_conditions.m | 14 ++++++++++++++ .../libcommon/get_conditions_doxmem2.m | 13 +++++++++++++ .../pspm_pupil/libcommon/get_conditions_fer02.m | 13 +++++++++++++ .../pspm_pupil/libcommon/get_conditions_fss6b.m | 11 +++++++++++ .../pspm_pupil/libcommon/get_conditions_li.m | 13 +++++++++++++ .../pspm_pupil/libcommon/get_conditions_pubfe.m | 13 +++++++++++++ .../pspm_pupil/libcommon/get_conditions_sc4b.m | 11 +++++++++++ .../pspm_pupil/libcommon/get_conditions_vc7b.m | 11 +++++++++++ .../pspm_pupil/libcommon/perc_miss_overall.m | 11 +++++++++++ examples/pspm_pupil/libcommon/pp_pfe.m | 12 +++++++++++- .../pspm_pupil/libcommon/pp_valid_fixations.m | 10 ++++++++++ examples/pspm_pupil/libcommon/util.py | 17 +++++++++++++++-- examples/pspm_pupil/run_all.sh | 2 +- 18 files changed, 181 insertions(+), 8 deletions(-) diff --git a/examples/pspm_pupil/exp1/fit.m b/examples/pspm_pupil/exp1/fit.m index d29513c..81510ee 100644 --- a/examples/pspm_pupil/exp1/fit.m +++ b/examples/pspm_pupil/exp1/fit.m @@ -27,5 +27,5 @@ options.exclude_missing = struct('segment_length', exclude_segment_length, 'cutoff', exclude_cutoff); out = pspm_glm(model, options); - [out, stats] = exclude_and_average(out, csp, out.stats_exclude); + stats = exclude_and_average(out, csp, out.stats_exclude); end diff --git a/examples/pspm_pupil/exp2/fit.m b/examples/pspm_pupil/exp2/fit.m index 316c657..40eac88 100644 --- a/examples/pspm_pupil/exp2/fit.m +++ b/examples/pspm_pupil/exp2/fit.m @@ -26,5 +26,5 @@ out = pspm_glm(model, options); not_exclude = zeros(1, numel(cell2mat(csp)), 'uint8'); - [out, stats] = exclude_and_average(out, csp, not_exclude); + stats = exclude_and_average(out, csp, not_exclude); end diff --git a/examples/pspm_pupil/exp4/fit.m b/examples/pspm_pupil/exp4/fit.m index 694b351..9d4aef4 100644 --- a/examples/pspm_pupil/exp4/fit.m +++ b/examples/pspm_pupil/exp4/fit.m @@ -39,7 +39,7 @@ options.exclude_missing = struct('segment_length', exclusion_seg_len, 'cutoff', trial_exclusion_threshold); out = pspm_glm(model, options); - [out, stats] = exclude_and_average(out, csp, out.stats_exclude); + stats = exclude_and_average(out, csp, out.stats_exclude); end function [out, stats] = condition_wise(inarg) diff --git a/examples/pspm_pupil/libcommon/exclude_and_average.m b/examples/pspm_pupil/libcommon/exclude_and_average.m index 38ccd41..cd971e8 100644 --- a/examples/pspm_pupil/libcommon/exclude_and_average.m +++ b/examples/pspm_pupil/libcommon/exclude_and_average.m @@ -1,4 +1,18 @@ -function [glm, stats] = exclude_and_average(glm, csp, exclude_arr) +function [stats] = exclude_and_average(glm, csp, exclude_arr) + % Compute CS+ and CS- beta stat averages from a fitted single-trial GLM structure. + % + % Parameters + % ---------- + % glm : Fitted single-trial GLM structure. + % + % csp : A logical array where csp(i) is 1 if ith trial is a CS+ + % + % exclude_arr : A logical array where exclude_arr(i) is 1 if ith trial should be + % excluded from the average. + % + % Returns + % ------- + % stats : A 2-element array holding the CS+ and CS- beta averages. csp = cell2mat(csp); bfno = glm.bf.bfno; stats_csp = 0; diff --git a/examples/pspm_pupil/libcommon/fit_all.m b/examples/pspm_pupil/libcommon/fit_all.m index 1ff9ff3..78965db 100644 --- a/examples/pspm_pupil/libcommon/fit_all.m +++ b/examples/pspm_pupil/libcommon/fit_all.m @@ -1,4 +1,20 @@ function stats = fit_all(inarg) + % Fit all the subjects in the dataset given in inarg structure using the currently + % loaded fit.m function. + % + % Before the dataset is fit, it is copied to a temporary location specified with + % inarg.tmp_out_path so that the original data is left unmodified. + % + % Parameters + % ---------- + % inarg : Structure with the following fields: + % .datapath : field holding the path to the dataset to fit. + % .tmp_out_path : field holding the path to the temporary location to copy the dataset. + % .subject_ids : Array of subject IDs to fit + % + % Returns + % ------- + % stats : Array with shape [2, n_subj] holding CS+ and CS- beta fits for each subject. orig_datapath = inarg.datapath; ds_name = split(orig_datapath, '/'); ds_name = ds_name{end}; diff --git a/examples/pspm_pupil/libcommon/get_conditions.m b/examples/pspm_pupil/libcommon/get_conditions.m index 0a8dfbd..8bacee5 100644 --- a/examples/pspm_pupil/libcommon/get_conditions.m +++ b/examples/pspm_pupil/libcommon/get_conditions.m @@ -1,4 +1,18 @@ function [pupil_fpath, conditions] = get_conditions(datapath, subj_id) + % Return the pupil paths and timing structure for a subject. The type of the + % dataset is inferred from datapath. + % + % Parameters + % ---------- + % datapath : Path to the dataset. + % subj_id : ID of the subject + % + % Returns + % ------- + % pupil_fpath : Path or cell array holding the paths to the pupil files (all sessions) + % for the given subject. + % conditions : Struct or cell array holding the condition structures (all sessions) + % for the given subject. fparts = split(datapath, filesep); if isempty(fparts{end}) dataset_name = fparts{end-1}; diff --git a/examples/pspm_pupil/libcommon/get_conditions_doxmem2.m b/examples/pspm_pupil/libcommon/get_conditions_doxmem2.m index 33518be..a31577e 100644 --- a/examples/pspm_pupil/libcommon/get_conditions_doxmem2.m +++ b/examples/pspm_pupil/libcommon/get_conditions_doxmem2.m @@ -1,4 +1,17 @@ function [pupil_fpath, conditions] = get_conditions_doxmem2(datapath, subj_id) + % Return the pupil paths and timing structure for a subject from DoxMem2 dataset. + % + % Parameters + % ---------- + % datapath : Path to the doxmem2 dataset. + % subj_id : ID of the subject + % + % Returns + % ------- + % pupil_fpath : Cell array holding the paths to the pupil files (all sessions) for the + % given subject. + % conditions : Cell array holding the condition structures (all sessions) for the + % given subject. cogent_fpath = {... fullfile(datapath, sprintf('DoxMem2_cogent_%.2d_sn1.mat', subj_id)), fullfile(datapath, sprintf('DoxMem2_cogent_%.2d_sn2.mat', subj_id)), diff --git a/examples/pspm_pupil/libcommon/get_conditions_fer02.m b/examples/pspm_pupil/libcommon/get_conditions_fer02.m index 790e3fd..31817e2 100644 --- a/examples/pspm_pupil/libcommon/get_conditions_fer02.m +++ b/examples/pspm_pupil/libcommon/get_conditions_fer02.m @@ -1,4 +1,17 @@ function [pupil_fpath, conditions] = get_conditions_fer02(datapath, subj_id) + % Return the pupil paths and timing structure for a subject from FER02 dataset. + % + % Parameters + % ---------- + % datapath : Path to the FER02 dataset. + % subj_id : ID of the subject + % + % Returns + % ------- + % pupil_fpath : Cell array holding the paths to the pupil files (all sessions) for the + % given subject. + % conditions : Cell array holding the condition structures (all sessions) for the + % given subject. cogent_fpath = {}; cogent = {}; try diff --git a/examples/pspm_pupil/libcommon/get_conditions_fss6b.m b/examples/pspm_pupil/libcommon/get_conditions_fss6b.m index ae66573..40d5f9f 100644 --- a/examples/pspm_pupil/libcommon/get_conditions_fss6b.m +++ b/examples/pspm_pupil/libcommon/get_conditions_fss6b.m @@ -1,4 +1,15 @@ function [pupil_fpath, conditions] = get_conditions_fss6b(datapath, subj_id) + % Return the pupil paths and timing structure for a subject from FSS6B dataset. + % + % Parameters + % ---------- + % datapath : Path to the FSS6B dataset. + % subj_id : ID of the subject + % + % Returns + % ------- + % pupil_fpath : Path to the pupil file for the given subject. + % conditions : Condition structure for the given subject. pupil_fpath = fullfile(datapath, sprintf('FSS6B_pupil_%.2d.mat', subj_id)); psych_fpath = fullfile(datapath, sprintf('FSS6B_psych_%.2d.mat', subj_id)); pupil = load(pupil_fpath); diff --git a/examples/pspm_pupil/libcommon/get_conditions_li.m b/examples/pspm_pupil/libcommon/get_conditions_li.m index 480b1a1..e981ea0 100644 --- a/examples/pspm_pupil/libcommon/get_conditions_li.m +++ b/examples/pspm_pupil/libcommon/get_conditions_li.m @@ -1,4 +1,17 @@ function [pupil_fpath, conditions] = get_conditions_li(datapath, subj_id) + % Return the pupil paths and timing structure for a subject from LI dataset. + % + % Parameters + % ---------- + % datapath : Path to the LI dataset. + % subj_id : ID of the subject + % + % Returns + % ------- + % pupil_fpath : Cell array holding the paths to the pupil files (all sessions) for the + % given subject. + % conditions : Cell array holding the condition structures (all sessions) for the + % given subject. pupil_fpath = {... fullfile(datapath, sprintf('LI_pupil_%.2d_sn1.mat', subj_id)),... fullfile(datapath, sprintf('LI_pupil_%.2d_sn2.mat', subj_id)) ... diff --git a/examples/pspm_pupil/libcommon/get_conditions_pubfe.m b/examples/pspm_pupil/libcommon/get_conditions_pubfe.m index 61d51d0..9e46b36 100644 --- a/examples/pspm_pupil/libcommon/get_conditions_pubfe.m +++ b/examples/pspm_pupil/libcommon/get_conditions_pubfe.m @@ -1,4 +1,17 @@ function [pupil_fpath, conditions] = get_conditions_pubfe(datapath, subj_id) + % Return the pupil paths and timing structure for a subject from PubFe dataset. + % + % Parameters + % ---------- + % datapath : Path to the PubFe dataset. + % subj_id : ID of the subject + % + % Returns + % ------- + % pupil_fpath : Cell array holding the paths to the pupil files (all sessions) for the + % given subject. + % conditions : Cell array holding the condition structures (all sessions) for the + % given subject. pupil_fpath = {... fullfile(datapath, sprintf('PubFe_pupil_%.2d_sn1.mat', subj_id)),... fullfile(datapath, sprintf('PubFe_pupil_%.2d_sn2.mat', subj_id)) ... diff --git a/examples/pspm_pupil/libcommon/get_conditions_sc4b.m b/examples/pspm_pupil/libcommon/get_conditions_sc4b.m index 0f64118..dac1c17 100644 --- a/examples/pspm_pupil/libcommon/get_conditions_sc4b.m +++ b/examples/pspm_pupil/libcommon/get_conditions_sc4b.m @@ -1,4 +1,15 @@ function [pupil_fpath, conditions] = get_conditions_sc4b(datapath, subj_id) + % Return the pupil paths and timing structure for a subject from SC4B dataset. + % + % Parameters + % ---------- + % datapath : Path to the SC4B dataset. + % subj_id : ID of the subject + % + % Returns + % ------- + % pupil_fpath : Path to the pupil file for the given subject. + % conditions : Condition structure for the given subject. pupil_fpath = fullfile(datapath, sprintf('SC4B_pupil_%.2d_sn1.mat', subj_id)); cogent_fpath = fullfile(datapath, sprintf('SC4B_cogent_%.2d.mat', subj_id)); pupil = load(pupil_fpath); diff --git a/examples/pspm_pupil/libcommon/get_conditions_vc7b.m b/examples/pspm_pupil/libcommon/get_conditions_vc7b.m index 9471ab9..13306c9 100644 --- a/examples/pspm_pupil/libcommon/get_conditions_vc7b.m +++ b/examples/pspm_pupil/libcommon/get_conditions_vc7b.m @@ -1,4 +1,15 @@ function [pupil_fpath, conditions] = get_conditions_vc7b(datapath, subj_id) + % Return the pupil paths and timing structure for a subject from VC7B dataset. + % + % Parameters + % ---------- + % datapath : Path to the VC7B dataset. + % subj_id : ID of the subject + % + % Returns + % ------- + % pupil_fpath : Path to the pupil file for the given subject. + % conditions : Condition structure for the given subject. pupil_fpath = fullfile(datapath, sprintf('VC7B_pupil_%.2d_sn1.mat', subj_id)); psych_fpath = fullfile(datapath, sprintf('VC7B_psych_%.2d.mat', subj_id)); pupil = load(pupil_fpath); diff --git a/examples/pspm_pupil/libcommon/perc_miss_overall.m b/examples/pspm_pupil/libcommon/perc_miss_overall.m index d7f3d43..cc4df25 100644 --- a/examples/pspm_pupil/libcommon/perc_miss_overall.m +++ b/examples/pspm_pupil/libcommon/perc_miss_overall.m @@ -1,4 +1,15 @@ function perc = perc_miss_overall(fp, channel) + % Return the overall missing data percentage of the data of a subject in + % the given channel. + % + % Parameters + % ---------- + % fp : Path or cell to the paths (all sessions) of a subject. + % channel : Channels on which miss percentage should be computed. + % + % Returns + % ------- + % perc : Overall missing data percentage in the range [0, 100]. if ~iscell(fp) fp = {fp}; end diff --git a/examples/pspm_pupil/libcommon/pp_pfe.m b/examples/pspm_pupil/libcommon/pp_pfe.m index 2b9ab9b..034e877 100644 --- a/examples/pspm_pupil/libcommon/pp_pfe.m +++ b/examples/pspm_pupil/libcommon/pp_pfe.m @@ -1,6 +1,16 @@ function sts = pp_pfe(pupil_fpath) + % Perform pupil foreshortening error correction on the data of a subject. + % If the gaze channels are in pixels, they are first converted to milimeters. + % + % Parameters + % ---------- + % pupil_fpath : Path or cell of paths (all sessions) to pupil data of a subject. + % + % Returns + % ------- + % sts : Status flag. opt.mode = 'auto'; - opt.C_z = 525; + opt.C_z = 625; for i = 1:numel(pupil_fpath) fpath = pupil_fpath{i}; try diff --git a/examples/pspm_pupil/libcommon/pp_valid_fixations.m b/examples/pspm_pupil/libcommon/pp_valid_fixations.m index a60a5e1..a2d227d 100644 --- a/examples/pspm_pupil/libcommon/pp_valid_fixations.m +++ b/examples/pspm_pupil/libcommon/pp_valid_fixations.m @@ -1,4 +1,14 @@ function sts = pp_valid_fixations(pupil_fpath, fixation_angle) + % Perform valid fixations filtering on the data of a subject. + % If the gaze channels are in pixels, they are first converted to milimeters. + % + % Parameters + % ---------- + % pupil_fpath : Path or cell of paths (all sessions) to pupil data of a subject. + % + % Returns + % ------- + % sts : Status flag. for i = 1:numel(pupil_fpath) fpath = pupil_fpath{i}; try diff --git a/examples/pspm_pupil/libcommon/util.py b/examples/pspm_pupil/libcommon/util.py index 97cf273..3777b6e 100644 --- a/examples/pspm_pupil/libcommon/util.py +++ b/examples/pspm_pupil/libcommon/util.py @@ -8,14 +8,16 @@ import numpy as np import pandas as pd -Dataset = namedtuple("Dataset", "name subject_ids") - DATA_PATH = "data" OUT_PATH = "output" LIB_PATHS = ["/home/eozd/bachlab/pspm/src", "libcommon"] class Dataset: + """ + Simple class to represent a dataset (e.g. doxmem2) + """ + def __init__(self, *args, name, subject_ids): self.name = name self.subject_ids = subject_ids @@ -34,6 +36,10 @@ def __init__(self, *args, name, subject_ids): def sm_to_pandas(sm): + """ + Convert a score matrix that is the result of sciunit TestSuite + to a regular pandas dataframe. + """ n_rows, n_cols = sm.shape arr = np.empty(shape=(n_rows, n_cols), dtype=np.float64) for i in range(n_rows): @@ -44,6 +50,9 @@ def sm_to_pandas(sm): def get_obs_dict_list(exp_output_path): + """ + Get the observation dictionary that can be used in cognibench framework. + """ obs_dict_list = [ { "stimuli": { @@ -59,6 +68,10 @@ def get_obs_dict_list(exp_output_path): def get_test_suite(exp_output_path): + """ + Construct a test suite for pupil benchmarking. Each dataset in DATASET_LIST + will be a separate test in the suite. + """ # prepare tests obs_dict_list = get_obs_dict_list(exp_output_path) CohensD = partialclass(scores.CohensDScore, min_score=-5, max_score=5) diff --git a/examples/pspm_pupil/run_all.sh b/examples/pspm_pupil/run_all.sh index 3e7580c..0ad3231 100755 --- a/examples/pspm_pupil/run_all.sh +++ b/examples/pspm_pupil/run_all.sh @@ -2,7 +2,7 @@ # # STEPS # 1. If there is no data folder, download datasets using download_datasets.sh -# 2. Change PsPM src folder path in libcommon/util.py line 14 +# 2. Change PsPM src folder path in libcommon/util.py LIB_PATHS definition # 3. Run this script # # Outputs will be stored in output folder