matlab(tdcs): data loading + curated group map

This commit is contained in:
Experiments DB Dev
2026-07-20 07:29:31 -04:00
parent 808040a522
commit 33121e3a8f
5 changed files with 316 additions and 0 deletions
+117
View File
@@ -0,0 +1,117 @@
function T = tdcs_load_data()
%TDCS_LOAD_DATA Load, join, and curate the raw tDCS reaching matrices.
% T = TDCS_LOAD_DATA() reads analysis/matlab/raw/raw_success.csv and
% raw_total.csv (app-exported matrix format: metric header line, blank
% line, file "Group" line, "# Days Reach" subject-header line, then one
% row per day with one value per subject column), reshapes each to long
% form, joins them on (subject, day), applies the curated 12-animal
% group map from tdcs_config (the file's own Group row is ignored),
% and restricts to day >= 0.
%
% Returns a table with variables:
% subject (string) animal name
% group (categorical) curated group (Naive, Electrode-Box-A,
% Electrode-Box-A2, Electrode-Box-B2,
% Right-Electrode)
% day (double) "# Days Reach" value, >= 0
% success (double) successful reaches in the session
% total (double) total attempts in the session
%
% Only the 12 curated animals (per tdcs_config().groups) are retained;
% any other animal present in the raw export is dropped.
thisDir = fileparts(mfilename('fullpath'));
successFile = fullfile(thisDir, 'raw', 'raw_success.csv');
totalFile = fullfile(thisDir, 'raw', 'raw_total.csv');
Tsuccess = localReadMatrix(successFile, 'success');
Ttotal = localReadMatrix(totalFile, 'total');
% Left join keyed on (subject, day): every non-blank Success cell becomes
% a row; Total is looked up for the same (subject, day). Per the plan's
% Global Constraints, Total is fully populated wherever Success is, so
% this should never introduce a missing total but the join is a left
% join (not an inner join) specifically so that an unmatched Success row
% would still be kept (with total = NaN) rather than silently dropped.
T = outerjoin(Tsuccess, Ttotal, 'Keys', {'subject', 'day'}, ...
'MergeKeys', true, 'Type', 'left');
% Apply the curated map: keep only the 12 curated animals, and assign
% group from the map (overriding the file's own Group row).
cfg = tdcs_config();
subjectsCell = cellstr(T.subject);
keep = isKey(cfg.groups, subjectsCell);
T = T(keep, :);
subjectsCell = subjectsCell(keep);
groupVals = cell(height(T), 1);
for i = 1:height(T)
groupVals{i} = cfg.groups(subjectsCell{i});
end
T.group = categorical(groupVals);
% Restrict to day >= 0 (analysis window).
T = T(T.day >= 0, :);
% Final variable order and a deterministic row order.
T = T(:, {'subject', 'group', 'day', 'success', 'total'});
T = sortrows(T, {'subject', 'day'});
end
function Tlong = localReadMatrix(filePath, valueName)
%LOCALREADMATRIX Parse one app-exported day-by-subject matrix to long form.
% Line 1 = "Data,<metric>" (skipped), line 2 blank (skipped), line 3 =
% "Group,<...>" (skipped -- grouping comes from the curated map, not
% this row), line 4 = "# Days Reach,<subject headers>" (columns 2:end
% are the subject names), lines 5+ = "<day>,<value per subject>" with
% blank cells meaning "no session that day for that subject".
lines = readlines(filePath);
% Defensive: drop any wholly-blank trailing line (e.g. if the file ends
% with a newline). Real data rows always start with a day number and are
% never zero-length.
while numel(lines) > 0 && strlength(strip(lines(end))) == 0
lines(end) = [];
end
headerParts = strsplit(lines(4), ',', 'CollapseDelimiters', false);
subjects = string(headerParts(2:end));
nSubjects = numel(subjects);
dataLines = lines(5:end);
dataLines = dataLines(strlength(strip(dataLines)) > 0);
nRows = numel(dataLines);
day = nan(nRows * nSubjects, 1);
subjectCol = strings(nRows * nSubjects, 1);
value = nan(nRows * nSubjects, 1);
idx = 0;
for r = 1:nRows
parts = strsplit(dataLines(r), ',', 'CollapseDelimiters', false);
dayVal = str2double(parts(1));
for c = 1:nSubjects
col = c + 1;
if col <= numel(parts)
cellStr = strtrim(parts(col));
else
cellStr = "";
end
if strlength(cellStr) == 0
continue
end
idx = idx + 1;
day(idx) = dayVal;
subjectCol(idx) = subjects(c);
value(idx) = str2double(cellStr);
end
end
day = day(1:idx);
subjectCol = subjectCol(1:idx);
value = value(1:idx);
Tlong = table(subjectCol, day, value, 'VariableNames', {'subject', 'day', valueName});
end