-
Notifications
You must be signed in to change notification settings - Fork 0
/
analyze_pupil_data.m
204 lines (173 loc) · 8.31 KB
/
analyze_pupil_data.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
% analyze_pupil_data.m
%
% Description:
% This script analyzes pupil diameter and firing rates in two experimental
% conditions (VT and V) within specified trial types. It calculates a pupil
% diameter threshold to create a double mask based on pupil diameter and motion.
% Firing rates are compared across trial types using the double mask, and
% modulation indices are calculated and visualized to assess the direction and
% magnitude of neuronal responses across clusters.
%
% Inputs:
% - experiment_groups (string): Identifier for the type of experiment.
% - trial_types (cell array): Array of trial types to analyze, each containing
% experimental conditions grouped by type.
%
% Outputs:
% - Plots showing the modulation index, firing rates, and masked histograms.
% - Calculations for mean, standard deviation, and standard error of the
% modulation indices across responsive clusters.
%
% Usage:
% Run the script after setting up experiment_groups, trial_types, and parameters.
% Ensure data for the specified probe IDs are accessible in RC2Analysis.
close all;
experiment_groups = 'visual_flow';
trial_types = {{'VT_RVT', 'VT_RV'}, {'V_RVT', 'V_RV'}};
% Initialize RC2Analysis and retrieve probe IDs
ctl = RC2Analysis();
probe_ids = ctl.get_probe_ids(experiment_groups);
% Initialize results storage
median_VT = [];
median_V = [];
direction = [];
median_VT_no_mask = [];
median_V_no_mask = [];
direction_no_mask = [];
VT_fr_per_bin = zeros(39, 4); % Placeholder arrays for future analysis
V_fr_per_bin = zeros(39, 4);
% Loop through probes to perform analysis for each one
for probe_i = 1 : length(probe_ids)
data = ctl.load_formatted_data(probe_ids{probe_i});
clusters = data.VISp_clusters();
% =====================================================================
% Collect and analyze pupil diameter across trial types
pupil_diameter_motion_all = zeros(length(trial_types), 100, 300000);
for type_i = 1 : length(trial_types)
% Retrieve trials and pupil diameter data
trials = data.get_trials_with_trial_group_label(trial_types{type_i});
for trial_i = 1 : length(trials)
trial = trials{trial_i}.to_aligned;
original_trial = trial.original_trial;
% Mask and store pupil diameter during motion periods
original_motion_mask = original_trial.motion_mask;
pupil_diameter = trial.pupil_diameter;
pupil_diameter_masked = pupil_diameter(original_motion_mask);
pupil_diameter_motion_all(type_i, trial_i, 1:length(pupil_diameter_masked)) = pupil_diameter_masked;
end
end
% Remove empty values and define bin edges for threshold calculation
pupil_diameter_motion_all(pupil_diameter_motion_all==0) = NaN;
edges = linspace(0, 100, 1000);
% Calculate pupil diameter threshold and plot histograms
[mask_threshold, smooth_counts1, smooth_counts2] = find_mask_threshold(...
pupil_diameter_motion_all(1, :), ...
pupil_diameter_motion_all(2, :), ...
edges, 100);
figure(probe_i);
hold on;
title(probe_ids(probe_i));
subplot(1, 2, 1);
histogram(pupil_diameter_motion_all(1, :), edges);
hold on;
histogram(pupil_diameter_motion_all(2, :), edges);
xlabel('Pupil diameter (pixel)');
ylabel('Counts');
xline(mask_threshold)
subplot(1, 2, 2);
hold on;
plot(smooth_counts1)
plot(smooth_counts2)
xlabel('Pupil diameter (pixel)');
ylabel('Smoothed distribution');
xline(mask_threshold * 10)
% Initialize arrays for firing rate calculations with and without mask
mean_spikes = zeros(length(trial_types), length(trials), length(clusters));
mean_spikes_no_mask = zeros(length(trial_types), length(trials), length(clusters));
pd_doubled_masking = zeros(length(trials), 300000);
% Apply double masking for each trial type and calculate mean firing rates
for type_i = 1 : length(trial_types)
trials = data.get_trials_with_trial_group_label(trial_types{type_i});
for trial_i = 1 : length(trials)
trial = trials{trial_i}.to_aligned;
original_trial = trial.original_trial;
original_motion_mask = original_trial.motion_mask;
pupil_diameter = trial.pupil_diameter;
pd_mask = pupil_diameter < mask_threshold;
if type_i == 1
% Combine motion and pupil diameter masks for trial type VT
pd_doubled_masking(trial_i, 1:length(pd_mask)) = pd_mask & original_motion_mask(1:length(pd_mask));
end
% Calculate mean firing rate for each cluster within double mask
for clust_i = 1 : length(clusters)
fr = clusters(clust_i).fr.get_convolution(trial.probe_t);
mask = logical(pd_doubled_masking(trial_i, 1:length(fr)));
mean_spikes(type_i, trial_i, clust_i) = nanmean(fr(mask));
mean_spikes_no_mask(type_i, trial_i, clust_i) = nanmean(fr(original_motion_mask));
end
end
end
% Compute median firing rates and test for directional response in each cluster
for clust_i = 1 : length(clusters)
mean_VT = mean_spikes(1, :, clust_i);
mean_V = mean_spikes(2, :, clust_i);
median_VT(end+1) = nanmedian(mean_VT);
median_V(end+1) = nanmedian(mean_V);
[~, ~, ~, direction(end+1)] = compare_groups_with_signrank(mean_V, mean_VT);
mean_VT_no_mask = mean_spikes_no_mask(1, :, clust_i);
mean_V_no_mask = mean_spikes_no_mask(2, :, clust_i);
median_VT_no_mask(end+1) = nanmedian(mean_VT_no_mask);
median_V_no_mask(end+1) = nanmedian(mean_V_no_mask);
[~, ~, ~, direction_no_mask(end+1)] = compare_groups_with_signrank(mean_V_no_mask, mean_VT_no_mask);
end
end
% Plot modulation index with unity plot
figure(5);
h_ax = subplot(1, 1, 1);
hold on;
fmt.xy_limits = [0, 60];
fmt.tick_space = 20;
fmt.line_order = 'top';
fmt.xlabel = trial_types{2};
fmt.ylabel = trial_types{1};
fmt.include_inset = false;
fmt.colour_by = 'significance';
unity_plot_plot(h_ax, median_V, median_VT, direction, fmt);
% Plot scatter for modulation indices with and without masking
figure(7);
hold on;
modulation_index = [];
modulation_index_no_mask = [];
for clust_i = 1 : 39
modulation_index(end+1) = (median_VT(clust_i) - median_V(clust_i)) / (median_VT(clust_i) + median_V(clust_i));
modulation_index_no_mask(end+1) = (median_VT_no_mask(clust_i) - median_V_no_mask(clust_i)) / (median_VT_no_mask(clust_i) + median_V_no_mask(clust_i));
if direction_no_mask(clust_i) ~= 0
if direction(clust_i) == 1
scatter(2, modulation_index(clust_i), scatterball_size(3), 'red', 'o');
elseif direction(clust_i) == -1
scatter(2, modulation_index(clust_i), scatterball_size(3), 'blue', 'o');
else
scatter(2, modulation_index(clust_i), scatterball_size(3), 'black', 'o');
end
if direction_no_mask(clust_i) == 1
scatter(1, modulation_index_no_mask(clust_i), scatterball_size(3), 'red', 'o');
elseif direction_no_mask(clust_i) == -1
scatter(1, modulation_index_no_mask(clust_i), scatterball_size(3), 'blue', 'o');
end
plot([1 2], [modulation_index_no_mask(clust_i), modulation_index(clust_i)], 'black');
end
end
xlim([0 3]);
ylim([-1.2 1.2]);
% Calculate and display statistics for responsive clusters
only_responsive_no_mask = direction_no_mask ~= 0;
avg_mi_no_mask = nanmean(modulation_index_no_mask(only_responsive_no_mask));
std_mi_no_mask = nanstd(modulation_index_no_mask(only_responsive_no_mask));
sem_mi_no_mask = nanstd(modulation_index_no_mask(only_responsive_no_mask)) / sqrt(39);
avg_mi = nanmean(modulation_index(only_responsive_no_mask));
std_mi = nanstd(modulation_index(only_responsive_no_mask));
sem_mi = nanstd(modulation_index(only_responsive_no_mask)) / sqrt(39);
[p] = signrank(modulation_index_no_mask(only_responsive_no_mask), modulation_index(only_responsive_no_mask));
% Perform ANOVA on firing rates per bin
[p_VT, tbl_VT, stats_VT] = anova1(VT_fr_per_bin);
[p_V, tbl_V, stats_V] = anova1(V_fr_per_bin);