8128495049
MATLAB's minor grid ignored MinorTickValues and auto-subdivided finer than 0.02. Make 0.02 the actual (major) tick spacing for rate, label only every 0.1, and let grid on draw the fine 0.02 gridlines deterministically. Regenerated all figures. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
101 lines
4.3 KiB
Matlab
101 lines
4.3 KiB
Matlab
% Variation learning-curve plots, in the style of the paper:
|
|
% "Lines indicate mean (and SEM) across animals in the anodal (red) and
|
|
% control (blue) groups."
|
|
% Produces TWO figures from this folder's data.csv:
|
|
% learning_curve.png # successes (count) per training day
|
|
% learning_curve_rate.png success rate (success/attempts) per training day
|
|
% anodal / treatment = stim 1 (red); control = stim 0 (blue). Per-group N is
|
|
% read from the data. Training day is 1-indexed (our day 0 = paper "Day 1") and
|
|
% the x-axis tick labels are drawn vertically.
|
|
% Run: matlab -batch "plotcurve"
|
|
% (Copy of analysis/matlab/variation_plot.m; see make_variation_plot.m.)
|
|
|
|
here = fileparts(mfilename('fullpath'));
|
|
if isempty(here); here = pwd; end
|
|
vname = regexprep(here, '.*[/\\]', '');
|
|
|
|
D = readtable(fullfile(here, 'data.csv'), 'TextType', 'string');
|
|
days = unique(D.day);
|
|
xd = days + 1; % plot as 1-indexed training day (paper axis)
|
|
red = [0.85 0.10 0.10];
|
|
blue = [0.10 0.30 0.85];
|
|
|
|
localPlot(D, days, xd, 'count', '# successes', ...
|
|
fullfile(here, 'learning_curve.png'), vname, red, blue);
|
|
localPlot(D, days, xd, 'rate', 'success rate', ...
|
|
fullfile(here, 'learning_curve_rate.png'), vname, red, blue);
|
|
|
|
% ------------------------------------------------------------------ helpers
|
|
function localPlot(D, days, xd, metric, ylab, outFile, vname, red, blue)
|
|
[Ma, Sa, na] = localCurve(D, 1, days, metric); % anodal / treatment
|
|
[Mc, Sc, nc] = localCurve(D, 0, days, metric); % control
|
|
fig = figure('Visible', 'off', 'Color', 'w', 'Position', [100 100 560 460]);
|
|
hold on
|
|
e1 = errorbar(xd, Ma, Sa, '-o', 'Color', red, 'MarkerFaceColor', red, 'LineWidth', 2);
|
|
e2 = errorbar(xd, Mc, Sc, '-o', 'Color', blue, 'MarkerFaceColor', blue, 'LineWidth', 2);
|
|
hold off
|
|
legend([e1 e2], {sprintf('anodal, N = %d', na), sprintf('control, N = %d', nc)}, ...
|
|
'Location', 'northwest', 'Box', 'off');
|
|
xlabel('training day'); ylh = ylabel(ylab);
|
|
title(vname, 'Interpreter', 'none');
|
|
% Compact publication layout with a tight centred plot box and ticks pointing
|
|
% out. Setting XTickLabel {} then xticklabels('auto') resets the labels cleanly
|
|
% after the Position change.
|
|
set(gca, 'XTick', xd, 'XTickLabel', {}, 'Position', [0.2 0.30 0.60 0.60], ...
|
|
'FontName', 'Arial', 'FontSize', 13, 'LineWidth', 1.5, 'Box', 'off', 'TickDir', 'out');
|
|
xticklabels('auto')
|
|
set(gca, 'XTickLabelRotation', 0); % keep x labels horizontal (no auto-rotate)
|
|
xlim([min(xd) - 0.5, max(xd) + 0.5]); % half-day padding so points aren't on the edges
|
|
if strcmp(metric, 'count') % count: tick every 5, but label only every 10
|
|
yl = ylim(gca);
|
|
yt = floor(yl(1) / 5) * 5 : 5 : ceil(yl(2) / 5) * 5;
|
|
lbl = cell(1, numel(yt));
|
|
for k = 1:numel(yt)
|
|
if mod(yt(k), 10) == 0; lbl{k} = num2str(yt(k)); else; lbl{k} = ''; end
|
|
end
|
|
set(gca, 'YTick', yt, 'YTickLabel', lbl);
|
|
else % rate: tick every 0.02, label only every 0.1
|
|
yl = ylim(gca);
|
|
yt = 0 : 0.02 : ceil(yl(2) / 0.02) * 0.02;
|
|
lbl = cell(1, numel(yt));
|
|
for k = 1:numel(yt)
|
|
if abs(yt(k) / 0.1 - round(yt(k) / 0.1)) < 1e-9 % multiple of 0.1
|
|
lbl{k} = num2str(round(yt(k), 1));
|
|
else
|
|
lbl{k} = '';
|
|
end
|
|
end
|
|
set(gca, 'YTick', yt, 'YTickLabel', lbl);
|
|
end
|
|
grid on % gridlines fall on the ticks (rate: every 0.02)
|
|
% Add breathing room between the y-axis label and the tick numbers.
|
|
set(ylh, 'Units', 'normalized');
|
|
yp = get(ylh, 'Position');
|
|
set(ylh, 'Position', [yp(1) - 0.015, yp(2), 0]);
|
|
drawnow;
|
|
exportgraphics(fig, outFile, 'Resolution', 150);
|
|
close(fig);
|
|
fprintf('%s: wrote %s (anodal N=%d, control N=%d)\n', vname, outFile, na, nc);
|
|
end
|
|
|
|
function [M, S, n] = localCurve(D, stimVal, days, metric)
|
|
%LOCALCURVE Per-day mean and SEM across the animals in a group, for a metric.
|
|
subs = unique(D.subject(D.stim == stimVal));
|
|
n = numel(subs);
|
|
X = nan(numel(days), n);
|
|
for j = 1:n
|
|
for i = 1:numel(days)
|
|
r = D.subject == subs(j) & D.day == days(i);
|
|
if ~any(r); continue; end
|
|
if strcmp(metric, 'rate')
|
|
tot = sum(D.total(r));
|
|
if tot > 0; X(i, j) = sum(D.success(r)) / tot; end
|
|
else
|
|
X(i, j) = mean(D.success(r));
|
|
end
|
|
end
|
|
end
|
|
M = mean(X, 2, 'omitnan');
|
|
S = std(X, [], 2, 'omitnan') ./ sqrt(sum(~isnan(X), 2));
|
|
end
|