feat(matlab): learning figure + methods write-up + organized CSV data export
Adds make_figure (2-panel learning curves + per-phase slopes, colorblind-safe Box-B2/Box-A2 palette) -> results/figure_learning.png; analysis/writeup.md (figure + methods + results summary); and tdcs_export_all/run_export exporting every data variation into an organized export/ tree (curated_all, scenarios/9, anchors/3 with tDCS factor, phases/9 + MANIFEST). Adds tExport tests. Suite 36/36. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,89 @@
|
||||
%MAKE_FIGURE Two-panel learning figure (Box-B2 vs Box-A2), saved to results/.
|
||||
% Panel A: mean +/- SEM success per training day over the fair 0-13 window,
|
||||
% with the fast/slow phase boundary. Panel B: per-animal learning
|
||||
% slope (mean +/- 95% CI) by phase. Uses the mergeA2 grouping.
|
||||
% Usage: matlab -batch "make_figure"
|
||||
|
||||
cfg = tdcs_config();
|
||||
Sfull = tdcs_scenario_data('mergeA2_full');
|
||||
T = Sfull(ismember(Sfull.group, {cfg.anchorLow, cfg.anchorHigh}) & Sfull.day <= 13, :);
|
||||
|
||||
B2 = [42 120 214]/255; % #2a78d6 (categorical slot 1)
|
||||
A2 = [0 131 0]/255; % #008300 (categorical slot 2)
|
||||
groups = {cfg.anchorHigh, cfg.anchorLow};
|
||||
cols = {B2, A2};
|
||||
names = {'Box-B2 (tDCS)', 'Box-A2 (control)'};
|
||||
mk = {'o', 's'};
|
||||
ink = [0.10 0.10 0.10];
|
||||
|
||||
f = figure('Visible', 'off', 'Position', [100 100 1150 460], 'Color', 'w');
|
||||
tl = tiledlayout(f, 1, 2, 'Padding', 'compact', 'TileSpacing', 'compact');
|
||||
|
||||
% ---- Panel A: learning curves ----
|
||||
ax1 = nexttile(tl); hold(ax1, 'on');
|
||||
days = 0:13;
|
||||
hLines = gobjects(1, 2);
|
||||
for gi = 1:2
|
||||
G = T(T.group == groups{gi}, :);
|
||||
mu = nan(size(days)); se = nan(size(days));
|
||||
for d = days
|
||||
v = G.success(G.day == d);
|
||||
if ~isempty(v); mu(d+1) = mean(v); se(d+1) = std(v)/sqrt(numel(v)); end
|
||||
end
|
||||
ok = ~isnan(mu);
|
||||
fill(ax1, [days(ok) fliplr(days(ok))], [mu(ok)+se(ok) fliplr(mu(ok)-se(ok))], ...
|
||||
cols{gi}, 'FaceAlpha', 0.13, 'EdgeColor', 'none', 'HandleVisibility', 'off');
|
||||
hLines(gi) = plot(ax1, days(ok), mu(ok), '-', 'Color', cols{gi}, 'LineWidth', 2, ...
|
||||
'Marker', mk{gi}, 'MarkerFaceColor', cols{gi}, 'MarkerEdgeColor', cols{gi}, 'MarkerSize', 5);
|
||||
end
|
||||
yl = ylim(ax1);
|
||||
xline(ax1, 5.5, '--', 'Color', [0.45 0.45 0.45], 'HandleVisibility', 'off');
|
||||
text(ax1, 2.6, yl(2)*0.97, 'fast (0-5)', 'Color', ink, 'FontSize', 9, 'HorizontalAlignment', 'center');
|
||||
text(ax1, 9.6, yl(2)*0.97, 'slow (6-13)', 'Color', ink, 'FontSize', 9, 'HorizontalAlignment', 'center');
|
||||
xlabel(ax1, 'Training day (# Days Reach; day 0 = paper "Day 1")', 'Color', ink);
|
||||
ylabel(ax1, 'Successful reaches / session', 'Color', ink);
|
||||
title(ax1, 'A Learning curves (mean \pm SEM)', 'Color', ink);
|
||||
legend(ax1, hLines, names, 'Location', 'northwest', 'Box', 'off', 'TextColor', ink);
|
||||
grid(ax1, 'on'); ax1.GridAlpha = 0.10; ax1.XColor = ink; ax1.YColor = ink; ax1.Box = 'off';
|
||||
xlim(ax1, [-0.3 13.3]);
|
||||
|
||||
% ---- Panel B: per-animal slope by phase ----
|
||||
ax2 = nexttile(tl); hold(ax2, 'on');
|
||||
phases = {[0 5], [6 13]}; phaseX = [1 2]; off = 0.14;
|
||||
hB = gobjects(1, 2);
|
||||
for gi = 1:2
|
||||
for pi = 1:2
|
||||
sl = localSlopes(T, groups{gi}, phases{pi});
|
||||
m = mean(sl); ci = tinv(0.975, numel(sl)-1) * std(sl)/sqrt(numel(sl));
|
||||
x = phaseX(pi) + (2*gi-3)*off; % gi=1 -> -off, gi=2 -> +off
|
||||
h = errorbar(ax2, x, m, ci, 'Marker', mk{gi}, 'Color', cols{gi}, ...
|
||||
'MarkerFaceColor', cols{gi}, 'MarkerEdgeColor', cols{gi}, 'MarkerSize', 8, ...
|
||||
'LineWidth', 1.8, 'CapSize', 8);
|
||||
if pi == 1; hB(gi) = h; end
|
||||
end
|
||||
end
|
||||
yline(ax2, 0, ':', 'Color', [0.6 0.6 0.6], 'HandleVisibility', 'off');
|
||||
xticks(ax2, [1 2]); xticklabels(ax2, {'fast (0-5)', 'slow (6-13)'});
|
||||
xlim(ax2, [0.5 2.5]);
|
||||
ylabel(ax2, 'Learning slope (reaches / day)', 'Color', ink);
|
||||
title(ax2, 'B Per-animal learning rate by phase (mean, 95% CI)', 'Color', ink);
|
||||
legend(ax2, hB, names, 'Location', 'northeast', 'Box', 'off', 'TextColor', ink);
|
||||
grid(ax2, 'on'); ax2.GridAlpha = 0.10; ax2.XColor = ink; ax2.YColor = ink; ax2.Box = 'off';
|
||||
|
||||
thisDir = fileparts(mfilename('fullpath'));
|
||||
resDir = fullfile(thisDir, 'results');
|
||||
if ~exist(resDir, 'dir'); mkdir(resDir); end
|
||||
outPng = fullfile(resDir, 'figure_learning.png');
|
||||
exportgraphics(f, outPng, 'Resolution', 200);
|
||||
fprintf('wrote %s\n', outPng);
|
||||
|
||||
function sl = localSlopes(T, grp, ph)
|
||||
Tg = T(T.group == grp & T.day >= ph(1) & T.day <= ph(2), :);
|
||||
subs = unique(Tg.subject); sl = [];
|
||||
for i = 1:numel(subs)
|
||||
r = Tg.subject == subs(i);
|
||||
if numel(unique(Tg.day(r))) >= 2
|
||||
c = polyfit(Tg.day(r), Tg.success(r), 1); sl(end+1,1) = c(1); %#ok<AGROW>
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user