diff --git a/analysis/MATLAB_functions/DM_morph_non_ref_coord.m b/analysis/MATLAB_functions/DM_morph_non_ref_coord.m new file mode 100644 index 0000000..429e944 --- /dev/null +++ b/analysis/MATLAB_functions/DM_morph_non_ref_coord.m @@ -0,0 +1,30 @@ +function [ref_coord]=DM_morph_non_ref_coord(non_ref_coord,xfrom_dir_path,pathname) +if pathname(end)~='\' + pathname=[pathname '\']; +end +vlist(:,1)=non_ref_coord(:,2); +vlist(:,2)=non_ref_coord(:,1); +vlist(:,3)=non_ref_coord(:,3); +f_list='temp.list'; +dlmwrite(fullfile(pathname,f_list),vlist,'delimiter','\t','newline','pc'); +str_list_in=strcat('<',pathname,f_list,'>'); +str_list_out=strcat(pathname,strrep(f_list,'.list','_out.list')); +dos(['C:\cmtk_files\bin\streamxform' ' ' '-- --inverse' ' ' xfrom_dir_path ' ' str_list_in ' ' str_list_out]); +fid=fopen(fullfile(pathname,strrep(f_list,'.list','_out.list'))); +myline=fgetl(fid); +rr=0; +while(ischar(myline)) + rr=rr+1; + substrings=regexp(myline,' ','split'); + ref_coord(rr,2)=str2num(substrings{1}); + ref_coord(rr,1)=str2num(substrings{2}); + ref_coord(rr,3)=str2num(substrings{3}); + if(numel(substrings)==4) + ref_coord(rr,4)=0; + else + ref_coord(rr,4)=1; + end + myline=fgetl(fid); +end +fclose(fid); +ref_coord(:,4)=[]; \ No newline at end of file diff --git a/analysis/MATLAB_functions/apply_morphing.m b/analysis/MATLAB_functions/apply_morphing.m new file mode 100644 index 0000000..98752f6 --- /dev/null +++ b/analysis/MATLAB_functions/apply_morphing.m @@ -0,0 +1,4 @@ +function [] = apply_morphing(str_ref, str_morph, str_final,affine_x) + +command_str_reform=['C:\cmtk_files\bin\reformatx --echo -o' ' ' str_final ' ' '--floating' ' ' str_morph ' ' str_ref ' ' affine_x]; +dos(command_str_reform,'-echo'); \ No newline at end of file diff --git a/analysis/MATLAB_functions/compute_reaf.m b/analysis/MATLAB_functions/compute_reaf.m new file mode 100644 index 0000000..b4bad88 --- /dev/null +++ b/analysis/MATLAB_functions/compute_reaf.m @@ -0,0 +1,27 @@ +function [grspeed] = compute_reaf (swim, vigor, reaf) +% dt = 0.005 +% reaf = [gain, lag(frames), shunted(1/0), gain drop start, gain drop end] +n=length(swim); +grspeed=10*ones(1,n); +start_frame=reaf(2)+1; +bout_frames=0; +for t=start_frame:n + if swim(t-reaf(2)) + grspeed(t)=10-28.5*vigor(t-reaf(2))*reaf(1); + end + if swim(t) + bout_frames=bout_frames+1; + else + if reaf(3)==1 + grspeed(t)=10; + end + end + if reaf(4)~=0 || reaf(5)~=0 + if bout_frames>=reaf(4) && bout_frames<=reaf(5) + grspeed(t)=10; + end + end + if t==n + a=1; + end +end \ No newline at end of file diff --git a/analysis/MATLAB_functions/dm_compute_triggered_traces.m b/analysis/MATLAB_functions/dm_compute_triggered_traces.m new file mode 100644 index 0000000..32d5555 --- /dev/null +++ b/analysis/MATLAB_functions/dm_compute_triggered_traces.m @@ -0,0 +1,25 @@ +function [trig_traces, time_trig] = dm_compute_triggered_traces(... + trig_list,... + s_pre,... + s_post,... + dt,... + time_im,... + traces) + +id_pre = s_pre/dt; +id_post = s_post/dt; +trig_length=(s_pre+s_post)/dt; +time_trig = -s_pre+dt:dt:s_post; +time_trig=round(time_trig*100)/100; +num_trig = length(trig_list); +num_traces=size(traces,1); +trig_traces = nan(num_traces,trig_length,num_trig,'single'); +for i=1:num_trig + this_trig=trig_list(i); + if ~isnan(this_trig) + [~, this_trig_id] = min(abs(time_im-this_trig)); + trig_traces(:,:,i) = traces(:,this_trig_id-id_pre+1:this_trig_id+id_post); + end +end +trig_traces = trig_traces - nanmean(trig_traces(:,1:id_pre,:),2); +end \ No newline at end of file diff --git a/analysis/MATLAB_functions/dm_dir.m b/analysis/MATLAB_functions/dm_dir.m new file mode 100644 index 0000000..2ada8a0 --- /dev/null +++ b/analysis/MATLAB_functions/dm_dir.m @@ -0,0 +1,3 @@ +function [cell_output] = dm_dir(str) +cell_output=struct2cell(dir(str)); +cell_output=cell_output(1,:)'; \ No newline at end of file diff --git a/analysis/MATLAB_functions/dm_fill_plot.m b/analysis/MATLAB_functions/dm_fill_plot.m new file mode 100644 index 0000000..b14affc --- /dev/null +++ b/analysis/MATLAB_functions/dm_fill_plot.m @@ -0,0 +1,3 @@ +function [] = dm_fill_plot(time,mean_trace,ste_trace,col,alpha) +fill([time flip(time)],[mean_trace-ste_trace flip(mean_trace+ste_trace)],col,'edgecolor','none','facealpha',alpha); +plot(time,mean_trace,'color',col,'linewidth',1.5); diff --git a/analysis/MATLAB_functions/dm_fix_fig_fonts.m b/analysis/MATLAB_functions/dm_fix_fig_fonts.m new file mode 100644 index 0000000..ed3ba73 --- /dev/null +++ b/analysis/MATLAB_functions/dm_fix_fig_fonts.m @@ -0,0 +1,25 @@ +function [] = dm_fix_fig_fonts(h,font_size) +drawnow +if nargin==0 + h=gcf; +end +if nargin<2 + font_size=10; +end +set(h,'InvertHardcopy','off','color',[1 1 1]); +all_axes=findall(h,'type','axes'); +set(all_axes,'fontsize',font_size,'fontweight','bold','FontName','Arial','layer','top','tickdir','out'); +for i=1:length(all_axes) + this_xcol=all_axes(i).XColor; + if isequal(this_xcol, [0.15 0.15 0.15]) + all_axes(i).XColor=[0 0 0]; + end + this_ycol=all_axes(i).YColor; + if isequal(this_ycol, [0.15 0.15 0.15]) + all_axes(i).YColor=[0 0 0]; + end +end +all_polaraxes=findall(h,'type','polaraxes'); +set(all_polaraxes,'fontsize',font_size,'fontweight','bold','FontName','Helvetica','layer','top'); +all_colorbars=findall(gcf,'type','colorbar'); +set(all_colorbars,'fontsize',font_size,'fontweight','bold','FontName','Helvetica','tickdir','out'); diff --git a/analysis/MATLAB_functions/dm_imagesc.m b/analysis/MATLAB_functions/dm_imagesc.m new file mode 100644 index 0000000..ebd97a1 --- /dev/null +++ b/analysis/MATLAB_functions/dm_imagesc.m @@ -0,0 +1,21 @@ +function dm_imagesc(time,data) +dt=time(2)-time(1); +num_traces=size(data,1); +set(gca,'xlim',[time(1)-dt time(end)]+dt/2,'ylim',[0 num_traces]+0.5,'ydir','reverse','layer','top'); +imagesc([time(1) time(end)],[1 num_traces],data,'AlphaData',double(~isnan(data))); +line([0 0],[0 num_traces]+0.5,'color','k','linestyle',':'); +c1=[40 75 62]; +c2=[90 0 0]; +c3=[40 16 -69]; +l = [linspace(c3(1), c2(1), 32) linspace(c2(1), c1(1), 32)]; +a = [linspace(c3(2), c2(2), 32) linspace(c2(2), c1(2), 32)]; +b = [linspace(c3(3), c2(3), 32) linspace(c2(3), c1(3), 32)]; +my_colormap=[l;a;b]'; +my_colormap(32,:)=[]; +my_colormap=dm_lab2rgb(my_colormap); +c_lim=get(gca,'clim'); +c_lim=max(abs(c_lim)); +c_lim=[-c_lim c_lim]*0.9; +set(gca,'clim',c_lim); +colormap(my_colormap); + \ No newline at end of file diff --git a/analysis/MATLAB_functions/dm_lab2rgb.m b/analysis/MATLAB_functions/dm_lab2rgb.m new file mode 100644 index 0000000..a451d47 --- /dev/null +++ b/analysis/MATLAB_functions/dm_lab2rgb.m @@ -0,0 +1,2 @@ +function [col] = dm_lab2rgb(col) +col=min(max(lab2rgb(col),0),1); \ No newline at end of file diff --git a/analysis/MATLAB_functions/genotype2tau.m b/analysis/MATLAB_functions/genotype2tau.m new file mode 100644 index 0000000..e4d5a23 --- /dev/null +++ b/analysis/MATLAB_functions/genotype2tau.m @@ -0,0 +1,10 @@ +function [ca_tau] = genotype2tau(genotype) +if contains(genotype,'GCaMP6s') + ca_tau=1.8; +elseif contains(genotype,'GCaMP6f') + ca_tau=0.4; +elseif contains(genotype,'GCaMP6sef05') || contains(genotype,'GCaMP6fef05') + ca_tau=0.65; +else + error ('Unknown genotype') +end \ No newline at end of file diff --git a/analysis/MATLAB_functions/mat2tiff.m b/analysis/MATLAB_functions/mat2tiff.m new file mode 100644 index 0000000..27a4686 --- /dev/null +++ b/analysis/MATLAB_functions/mat2tiff.m @@ -0,0 +1,25 @@ +function [] = mat2tiff(mat_file, pathname, filename) +warning('off','MATLAB:DELETE:FileNotFound'); +delete(fullfile(pathname, filename)) +if length(size(mat_file))==3 + num_planes=size(mat_file,3); + progressbar('saving tif stack') + for plane=1:num_planes + imwrite(mat_file(:,:,plane),fullfile(pathname, filename),'writemode','append'); + progressbar(plane/num_planes); + end +elseif length(size(mat_file))==4 + sz=size(mat_file); + if sz(3)~=3 + error('3d dimension of the stack should be rgb, not planes!'); + else + num_planes=size(mat_file,4); + progressbar('saving tif stack') + for plane=1:num_planes + imwrite(mat_file(:,:,:,plane),fullfile(pathname, filename),'writemode','append'); + progressbar(plane/num_planes); + end + end +else + error('Unexpected number of dimensions in the stack. It should be 3 or 4'); +end \ No newline at end of file diff --git a/analysis/MATLAB_functions/matplotlib/cividis.m b/analysis/MATLAB_functions/matplotlib/cividis.m new file mode 100644 index 0000000..c180f8f --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/cividis.m @@ -0,0 +1,64 @@ +function map = cividis(N) +% Perceptually uniform sequential colormap from MatPlotLib. Designed for colorblind. +% +% Copyright (c) 2017-2019 Stephen Cobeldick +% +%%% Syntax: +% map = cividis +% map = cividis(N) +% +% Colormap designed by Jamie R. Nuñez, Christopher R. Anderton, Ryan S. Renslow. +% +% Developed with consideration for color vision deficiency to enable accurate +% interpretation of scientific data. Full paper available here: +% +% The RGB data is from here: +% +% Note VIRIDIS replaces the awful JET as the MatPlotLib default colormap. +% +%% Examples %% +% +%%% Plot the scheme's RGB values: +% rgbplot(cividis(256)) +% +%%% New colors for the COLORMAP example: +% load spine +% image(X) +% colormap(cividis) +% +%%% New colors for the SURF example: +% [X,Y,Z] = peaks(30); +% surfc(X,Y,Z) +% colormap(cividis) +% axis([-3,3,-3,3,-10,5]) +% +%% Input and Output Arguments %% +% +%%% Inputs (*=default): +% N = NumericScalar, N>=0, an integer to define the colormap length. +% = *[], use the length of the current figure's colormap (see COLORMAP). +% +%%% Outputs: +% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. +% +% See also INFERNO MAGMA PLASMA VIRIDIS TWILIGHT TAB10 SET LINES COLORMAP PARULA + +if nargin<1 || isempty(N) + N = size(get(gcf,'colormap'),1); +else + assert(isscalar(N)&&isreal(N),'First argument must be a real numeric scalar.') +end +% +raw = [0.0000,0.1262,0.3015;0.0000,0.1292,0.3077;0.0000,0.1321,0.3142;0.0000,0.1350,0.3205;0.0000,0.1379,0.3269;0.0000,0.1408,0.3334;0.0000,0.1437,0.3400;0.0000,0.1465,0.3467;0.0000,0.1492,0.3537;0.0000,0.1519,0.3606;0.0000,0.1546,0.3676;0.0000,0.1574,0.3746;0.0000,0.1601,0.3817;0.0000,0.1629,0.3888;0.0000,0.1657,0.3960;0.0000,0.1685,0.4031;0.0000,0.1714,0.4102;0.0000,0.1743,0.4172;0.0000,0.1773,0.4241;0.0000,0.1798,0.4307;0.0000,0.1817,0.4347;0.0000,0.1834,0.4363;0.0000,0.1852,0.4368;0.0000,0.1872,0.4368;0.0000,0.1901,0.4365;0.0000,0.1930,0.4361;0.0000,0.1958,0.4356;0.0000,0.1987,0.4349;0.0000,0.2015,0.4343;0.0000,0.2044,0.4336;0.0000,0.2073,0.4329;0.0055,0.2101,0.4322;0.0236,0.2130,0.4314;0.0416,0.2158,0.4308;0.0576,0.2187,0.4301;0.0710,0.2215,0.4293;0.0827,0.2244,0.4287;0.0932,0.2272,0.4280;0.1030,0.2300,0.4274;0.1120,0.2329,0.4268;0.1204,0.2357,0.4262;0.1283,0.2385,0.4256;0.1359,0.2414,0.4251;0.1431,0.2442,0.4245;0.1500,0.2470,0.4241;0.1566,0.2498,0.4236;0.1630,0.2526,0.4232;0.1692,0.2555,0.4228;0.1752,0.2583,0.4224;0.1811,0.2611,0.4220;0.1868,0.2639,0.4217;0.1923,0.2667,0.4214;0.1977,0.2695,0.4212;0.2030,0.2723,0.4209;0.2082,0.2751,0.4207;0.2133,0.2780,0.4205;0.2183,0.2808,0.4204;0.2232,0.2836,0.4203;0.2281,0.2864,0.4202;0.2328,0.2892,0.4201;0.2375,0.2920,0.4200;0.2421,0.2948,0.4200;0.2466,0.2976,0.4200;0.2511,0.3004,0.4201;0.2556,0.3032,0.4201;0.2599,0.3060,0.4202;0.2643,0.3088,0.4203;0.2686,0.3116,0.4205;0.2728,0.3144,0.4206;0.2770,0.3172,0.4208;0.2811,0.3200,0.4210;0.2853,0.3228,0.4212;0.2894,0.3256,0.4215;0.2934,0.3284,0.4218;0.2974,0.3312,0.4221;0.3014,0.3340,0.4224;0.3054,0.3368,0.4227;0.3093,0.3396,0.4231;0.3132,0.3424,0.4236;0.3170,0.3453,0.4240;0.3209,0.3481,0.4244;0.3247,0.3509,0.4249;0.3285,0.3537,0.4254;0.3323,0.3565,0.4259;0.3361,0.3593,0.4264;0.3398,0.3622,0.4270;0.3435,0.3650,0.4276;0.3472,0.3678,0.4282;0.3509,0.3706,0.4288;0.3546,0.3734,0.4294;0.3582,0.3763,0.4302;0.3619,0.3791,0.4308;0.3655,0.3819,0.4316;0.3691,0.3848,0.4322;0.3727,0.3876,0.4331;0.3763,0.3904,0.4338;0.3798,0.3933,0.4346;0.3834,0.3961,0.4355;0.3869,0.3990,0.4364;0.3905,0.4018,0.4372;0.3940,0.4047,0.4381;0.3975,0.4075,0.4390;0.4010,0.4104,0.4400;0.4045,0.4132,0.4409;0.4080,0.4161,0.4419;0.4114,0.4189,0.4430;0.4149,0.4218,0.4440;0.4183,0.4247,0.4450;0.4218,0.4275,0.4462;0.4252,0.4304,0.4473;0.4286,0.4333,0.4485;0.4320,0.4362,0.4496;0.4354,0.4390,0.4508;0.4388,0.4419,0.4521;0.4422,0.4448,0.4534;0.4456,0.4477,0.4547;0.4489,0.4506,0.4561;0.4523,0.4535,0.4575;0.4556,0.4564,0.4589;0.4589,0.4593,0.4604;0.4622,0.4622,0.4620;0.4656,0.4651,0.4635;0.4689,0.4680,0.4650;0.4722,0.4709,0.4665;0.4756,0.4738,0.4679;0.4790,0.4767,0.4691;0.4825,0.4797,0.4701;0.4861,0.4826,0.4707;0.4897,0.4856,0.4714;0.4934,0.4886,0.4719;0.4971,0.4915,0.4723;0.5008,0.4945,0.4727;0.5045,0.4975,0.4730;0.5083,0.5005,0.4732;0.5121,0.5035,0.4734;0.5158,0.5065,0.4736;0.5196,0.5095,0.4737;0.5234,0.5125,0.4738;0.5272,0.5155,0.4739;0.5310,0.5186,0.4739;0.5349,0.5216,0.4738;0.5387,0.5246,0.4739;0.5425,0.5277,0.4738;0.5464,0.5307,0.4736;0.5502,0.5338,0.4735;0.5541,0.5368,0.4733;0.5579,0.5399,0.4732;0.5618,0.5430,0.4729;0.5657,0.5461,0.4727;0.5696,0.5491,0.4723;0.5735,0.5522,0.4720;0.5774,0.5553,0.4717;0.5813,0.5584,0.4714;0.5852,0.5615,0.4709;0.5892,0.5646,0.4705;0.5931,0.5678,0.4701;0.5970,0.5709,0.4696;0.6010,0.5740,0.4691;0.6050,0.5772,0.4685;0.6089,0.5803,0.4680;0.6129,0.5835,0.4673;0.6168,0.5866,0.4668;0.6208,0.5898,0.4662;0.6248,0.5929,0.4655;0.6288,0.5961,0.4649;0.6328,0.5993,0.4641;0.6368,0.6025,0.4632;0.6408,0.6057,0.4625;0.6449,0.6089,0.4617;0.6489,0.6121,0.4609;0.6529,0.6153,0.4600;0.6570,0.6185,0.4591;0.6610,0.6217,0.4583;0.6651,0.6250,0.4573;0.6691,0.6282,0.4562;0.6732,0.6315,0.4553;0.6773,0.6347,0.4543;0.6813,0.6380,0.4532;0.6854,0.6412,0.4521;0.6895,0.6445,0.4511;0.6936,0.6478,0.4499;0.6977,0.6511,0.4487;0.7018,0.6544,0.4475;0.7060,0.6577,0.4463;0.7101,0.6610,0.4450;0.7142,0.6643,0.4437;0.7184,0.6676,0.4424;0.7225,0.6710,0.4409;0.7267,0.6743,0.4396;0.7308,0.6776,0.4382;0.7350,0.6810,0.4368;0.7392,0.6844,0.4352;0.7434,0.6877,0.4338;0.7476,0.6911,0.4322;0.7518,0.6945,0.4307;0.7560,0.6979,0.4290;0.7602,0.7013,0.4273;0.7644,0.7047,0.4258;0.7686,0.7081,0.4241;0.7729,0.7115,0.4223;0.7771,0.7150,0.4205;0.7814,0.7184,0.4188;0.7856,0.7218,0.4168;0.7899,0.7253,0.4150;0.7942,0.7288,0.4129;0.7985,0.7322,0.4111;0.8027,0.7357,0.4090;0.8070,0.7392,0.4070;0.8114,0.7427,0.4049;0.8157,0.7462,0.4028;0.8200,0.7497,0.4007;0.8243,0.7532,0.3984;0.8287,0.7568,0.3961;0.8330,0.7603,0.3938;0.8374,0.7639,0.3915;0.8417,0.7674,0.3892;0.8461,0.7710,0.3869;0.8505,0.7745,0.3843;0.8548,0.7781,0.3818;0.8592,0.7817,0.3793;0.8636,0.7853,0.3766;0.8681,0.7889,0.3739;0.8725,0.7926,0.3712;0.8769,0.7962,0.3684;0.8813,0.7998,0.3657;0.8858,0.8035,0.3627;0.8902,0.8071,0.3599;0.8947,0.8108,0.3569;0.8992,0.8145,0.3538;0.9037,0.8182,0.3507;0.9082,0.8219,0.3474;0.9127,0.8256,0.3442;0.9172,0.8293,0.3409;0.9217,0.8330,0.3374;0.9262,0.8367,0.3340;0.9308,0.8405,0.3306;0.9353,0.8442,0.3268;0.9399,0.8480,0.3232;0.9444,0.8518,0.3195;0.9490,0.8556,0.3155;0.9536,0.8593,0.3116;0.9582,0.8632,0.3076;0.9628,0.8670,0.3034;0.9674,0.8708,0.2990;0.9721,0.8746,0.2947;0.9767,0.8785,0.2901;0.9814,0.8823,0.2856;0.9860,0.8862,0.2807;0.9907,0.8901,0.2759;0.9954,0.8940,0.2708;1.0000,0.8979,0.2655;1.0000,0.9018,0.2600;1.0000,0.9057,0.2593;1.0000,0.9094,0.2634;1.0000,0.9131,0.2680;1.0000,0.9169,0.2731]; +% +num = size(raw,1); +% With small extrapolation when N>num: +vec = linspace(0,num+1,N+2); +map = interp1(1:num,raw,vec(2:N+1),'linear','extrap'); +% Interpolation only for all values of N: +%map = interp1(1:num,raw,linspace(1,num,N),'spline') +% Range limits: +map = max(0,min(1,map)); +% +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%cividis \ No newline at end of file diff --git a/analysis/MATLAB_functions/matplotlib/inferno.m b/analysis/MATLAB_functions/matplotlib/inferno.m new file mode 100644 index 0000000..a8a3a90 --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/inferno.m @@ -0,0 +1,64 @@ +function map = inferno(N) +% Perceptually uniform sequential colormap from MatPlotLib. +% +% Copyright (c) 2017-2019 Stephen Cobeldick +% +%%% Syntax: +% map = inferno +% map = inferno(N) +% +% Colormap designed by Nathaniel J. Smith and Stefan van der Walt. +% +% For MatPlotLib 2.0 improved colormaps were created in the perceptually +% uniform colorspace CAM02-UCS. The new colormaps are introduced here: +% +% The RGB data is from here: +% +% Note VIRIDIS replaces the awful JET as the MatPlotLib default colormap. +% +%% Examples %% +% +%%% Plot the scheme's RGB values: +% rgbplot(inferno(256)) +% +%%% New colors for the COLORMAP example: +% load spine +% image(X) +% colormap(inferno) +% +%%% New colors for the SURF example: +% [X,Y,Z] = peaks(30); +% surfc(X,Y,Z) +% colormap(inferno) +% axis([-3,3,-3,3,-10,5]) +% +%% Input and Output Arguments %% +% +%%% Inputs (*=default): +% N = NumericScalar, N>=0, an integer to define the colormap length. +% = *[], use the length of the current figure's colormap (see COLORMAP). +% +%%% Outputs: +% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. +% +% See also CIVIDIS MAGMA PLASMA VIRIDIS TWILIGHT TAB10 SET LINES COLORMAP PARULA + +if nargin<1 || isempty(N) + N = size(get(gcf,'colormap'),1); +else + assert(isscalar(N)&&isreal(N),'First argument must be a real numeric scalar.') +end +% +raw = [0.001462,0.000466,0.013866; 0.002267,0.001270,0.018570; 0.003299,0.002249,0.024239; 0.004547,0.003392,0.030909; 0.006006,0.004692,0.038558; 0.007676,0.006136,0.046836; 0.009561,0.007713,0.055143; 0.011663,0.009417,0.063460; 0.013995,0.011225,0.071862; 0.016561,0.013136,0.080282; 0.019373,0.015133,0.088767; 0.022447,0.017199,0.097327; 0.025793,0.019331,0.105930; 0.029432,0.021503,0.114621; 0.033385,0.023702,0.123397; 0.037668,0.025921,0.132232; 0.042253,0.028139,0.141141; 0.046915,0.030324,0.150164; 0.051644,0.032474,0.159254; 0.056449,0.034569,0.168414; 0.061340,0.036590,0.177642; 0.066331,0.038504,0.186962; 0.071429,0.040294,0.196354; 0.076637,0.041905,0.205799; 0.081962,0.043328,0.215289; 0.087411,0.044556,0.224813; 0.092990,0.045583,0.234358; 0.098702,0.046402,0.243904; 0.104551,0.047008,0.253430; 0.110536,0.047399,0.262912; 0.116656,0.047574,0.272321; 0.122908,0.047536,0.281624; 0.129285,0.047293,0.290788; 0.135778,0.046856,0.299776; 0.142378,0.046242,0.308553; 0.149073,0.045468,0.317085; 0.155850,0.044559,0.325338; 0.162689,0.043554,0.333277; 0.169575,0.042489,0.340874; 0.176493,0.041402,0.348111; 0.183429,0.040329,0.354971; 0.190367,0.039309,0.361447; 0.197297,0.038400,0.367535; 0.204209,0.037632,0.373238; 0.211095,0.037030,0.378563; 0.217949,0.036615,0.383522; 0.224763,0.036405,0.388129; 0.231538,0.036405,0.392400; 0.238273,0.036621,0.396353; 0.244967,0.037055,0.400007; 0.251620,0.037705,0.403378; 0.258234,0.038571,0.406485; 0.264810,0.039647,0.409345; 0.271347,0.040922,0.411976; 0.277850,0.042353,0.414392; 0.284321,0.043933,0.416608; 0.290763,0.045644,0.418637; 0.297178,0.047470,0.420491; 0.303568,0.049396,0.422182; 0.309935,0.051407,0.423721; 0.316282,0.053490,0.425116; 0.322610,0.055634,0.426377; 0.328921,0.057827,0.427511; 0.335217,0.060060,0.428524; 0.341500,0.062325,0.429425; 0.347771,0.064616,0.430217; 0.354032,0.066925,0.430906; 0.360284,0.069247,0.431497; 0.366529,0.071579,0.431994; 0.372768,0.073915,0.432400; 0.379001,0.076253,0.432719; 0.385228,0.078591,0.432955; 0.391453,0.080927,0.433109; 0.397674,0.083257,0.433183; 0.403894,0.085580,0.433179; 0.410113,0.087896,0.433098; 0.416331,0.090203,0.432943; 0.422549,0.092501,0.432714; 0.428768,0.094790,0.432412; 0.434987,0.097069,0.432039; 0.441207,0.099338,0.431594; 0.447428,0.101597,0.431080; 0.453651,0.103848,0.430498; 0.459875,0.106089,0.429846; 0.466100,0.108322,0.429125; 0.472328,0.110547,0.428334; 0.478558,0.112764,0.427475; 0.484789,0.114974,0.426548; 0.491022,0.117179,0.425552; 0.497257,0.119379,0.424488; 0.503493,0.121575,0.423356; 0.509730,0.123769,0.422156; 0.515967,0.125960,0.420887; 0.522206,0.128150,0.419549; 0.528444,0.130341,0.418142; 0.534683,0.132534,0.416667; 0.540920,0.134729,0.415123; 0.547157,0.136929,0.413511; 0.553392,0.139134,0.411829; 0.559624,0.141346,0.410078; 0.565854,0.143567,0.408258; 0.572081,0.145797,0.406369; 0.578304,0.148039,0.404411; 0.584521,0.150294,0.402385; 0.590734,0.152563,0.400290; 0.596940,0.154848,0.398125; 0.603139,0.157151,0.395891; 0.609330,0.159474,0.393589; 0.615513,0.161817,0.391219; 0.621685,0.164184,0.388781; 0.627847,0.166575,0.386276; 0.633998,0.168992,0.383704; 0.640135,0.171438,0.381065; 0.646260,0.173914,0.378359; 0.652369,0.176421,0.375586; 0.658463,0.178962,0.372748; 0.664540,0.181539,0.369846; 0.670599,0.184153,0.366879; 0.676638,0.186807,0.363849; 0.682656,0.189501,0.360757; 0.688653,0.192239,0.357603; 0.694627,0.195021,0.354388; 0.700576,0.197851,0.351113; 0.706500,0.200728,0.347777; 0.712396,0.203656,0.344383; 0.718264,0.206636,0.340931; 0.724103,0.209670,0.337424; 0.729909,0.212759,0.333861; 0.735683,0.215906,0.330245; 0.741423,0.219112,0.326576; 0.747127,0.222378,0.322856; 0.752794,0.225706,0.319085; 0.758422,0.229097,0.315266; 0.764010,0.232554,0.311399; 0.769556,0.236077,0.307485; 0.775059,0.239667,0.303526; 0.780517,0.243327,0.299523; 0.785929,0.247056,0.295477; 0.791293,0.250856,0.291390; 0.796607,0.254728,0.287264; 0.801871,0.258674,0.283099; 0.807082,0.262692,0.278898; 0.812239,0.266786,0.274661; 0.817341,0.270954,0.270390; 0.822386,0.275197,0.266085; 0.827372,0.279517,0.261750; 0.832299,0.283913,0.257383; 0.837165,0.288385,0.252988; 0.841969,0.292933,0.248564; 0.846709,0.297559,0.244113; 0.851384,0.302260,0.239636; 0.855992,0.307038,0.235133; 0.860533,0.311892,0.230606; 0.865006,0.316822,0.226055; 0.869409,0.321827,0.221482; 0.873741,0.326906,0.216886; 0.878001,0.332060,0.212268; 0.882188,0.337287,0.207628; 0.886302,0.342586,0.202968; 0.890341,0.347957,0.198286; 0.894305,0.353399,0.193584; 0.898192,0.358911,0.188860; 0.902003,0.364492,0.184116; 0.905735,0.370140,0.179350; 0.909390,0.375856,0.174563; 0.912966,0.381636,0.169755; 0.916462,0.387481,0.164924; 0.919879,0.393389,0.160070; 0.923215,0.399359,0.155193; 0.926470,0.405389,0.150292; 0.929644,0.411479,0.145367; 0.932737,0.417627,0.140417; 0.935747,0.423831,0.135440; 0.938675,0.430091,0.130438; 0.941521,0.436405,0.125409; 0.944285,0.442772,0.120354; 0.946965,0.449191,0.115272; 0.949562,0.455660,0.110164; 0.952075,0.462178,0.105031; 0.954506,0.468744,0.099874; 0.956852,0.475356,0.094695; 0.959114,0.482014,0.089499; 0.961293,0.488716,0.084289; 0.963387,0.495462,0.079073; 0.965397,0.502249,0.073859; 0.967322,0.509078,0.068659; 0.969163,0.515946,0.063488; 0.970919,0.522853,0.058367; 0.972590,0.529798,0.053324; 0.974176,0.536780,0.048392; 0.975677,0.543798,0.043618; 0.977092,0.550850,0.039050; 0.978422,0.557937,0.034931; 0.979666,0.565057,0.031409; 0.980824,0.572209,0.028508; 0.981895,0.579392,0.026250; 0.982881,0.586606,0.024661; 0.983779,0.593849,0.023770; 0.984591,0.601122,0.023606; 0.985315,0.608422,0.024202; 0.985952,0.615750,0.025592; 0.986502,0.623105,0.027814; 0.986964,0.630485,0.030908; 0.987337,0.637890,0.034916; 0.987622,0.645320,0.039886; 0.987819,0.652773,0.045581; 0.987926,0.660250,0.051750; 0.987945,0.667748,0.058329; 0.987874,0.675267,0.065257; 0.987714,0.682807,0.072489; 0.987464,0.690366,0.079990; 0.987124,0.697944,0.087731; 0.986694,0.705540,0.095694; 0.986175,0.713153,0.103863; 0.985566,0.720782,0.112229; 0.984865,0.728427,0.120785; 0.984075,0.736087,0.129527; 0.983196,0.743758,0.138453; 0.982228,0.751442,0.147565; 0.981173,0.759135,0.156863; 0.980032,0.766837,0.166353; 0.978806,0.774545,0.176037; 0.977497,0.782258,0.185923; 0.976108,0.789974,0.196018; 0.974638,0.797692,0.206332; 0.973088,0.805409,0.216877; 0.971468,0.813122,0.227658; 0.969783,0.820825,0.238686; 0.968041,0.828515,0.249972; 0.966243,0.836191,0.261534; 0.964394,0.843848,0.273391; 0.962517,0.851476,0.285546; 0.960626,0.859069,0.298010; 0.958720,0.866624,0.310820; 0.956834,0.874129,0.323974; 0.954997,0.881569,0.337475; 0.953215,0.888942,0.351369; 0.951546,0.896226,0.365627; 0.950018,0.903409,0.380271; 0.948683,0.910473,0.395289; 0.947594,0.917399,0.410665; 0.946809,0.924168,0.426373; 0.946392,0.930761,0.442367; 0.946403,0.937159,0.458592; 0.946903,0.943348,0.474970; 0.947937,0.949318,0.491426; 0.949545,0.955063,0.507860; 0.951740,0.960587,0.524203; 0.954529,0.965896,0.540361; 0.957896,0.971003,0.556275; 0.961812,0.975924,0.571925; 0.966249,0.980678,0.587206; 0.971162,0.985282,0.602154; 0.976511,0.989753,0.616760; 0.982257,0.994109,0.631017; 0.988362,0.998364,0.644924]; +% +num = size(raw,1); +% With small extrapolation when N>num: +vec = linspace(0,num+1,N+2); +map = interp1(1:num,raw,vec(2:N+1),'linear','extrap'); +% Interpolation only for all values of N: +%map = interp1(1:num,raw,linspace(1,num,N),'spline') +% Range limits: +map = max(0,min(1,map)); +% +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%inferno \ No newline at end of file diff --git a/analysis/MATLAB_functions/matplotlib/license.txt b/analysis/MATLAB_functions/matplotlib/license.txt new file mode 100644 index 0000000..0951ce7 --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/license.txt @@ -0,0 +1,25 @@ +Copyright (c) 2019, Stephen Cobeldick +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution +* Neither the name of nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/analysis/MATLAB_functions/matplotlib/magma.m b/analysis/MATLAB_functions/matplotlib/magma.m new file mode 100644 index 0000000..b66354a --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/magma.m @@ -0,0 +1,64 @@ +function map = magma(N) +% Perceptually uniform sequential colormap from MatPlotLib. +% +% Copyright (c) 2017-2019 Stephen Cobeldick +% +%%% Syntax: +% map = magma +% map = magma(N) +% +% Colormap designed by Nathaniel J. Smith and Stefan van der Walt. +% +% For MatPlotLib 2.0 improved colormaps were created in the perceptually +% uniform colorspace CAM02-UCS. The new colormaps are introduced here: +% +% The RGB data is from here: +% +% Note VIRIDIS replaces the awful JET as the MatPlotLib default colormap. +% +%% Examples %% +% +%%% Plot the scheme's RGB values: +% rgbplot(magma(256)) +% +%%% New colors for the COLORMAP example: +% load spine +% image(X) +% colormap(magma) +% +%%% New colors for the SURF example: +% [X,Y,Z] = peaks(30); +% surfc(X,Y,Z) +% colormap(magma) +% axis([-3,3,-3,3,-10,5]) +% +%% Input and Output Arguments %% +% +%%% Inputs (*=default): +% N = NumericScalar, N>=0, an integer to define the colormap length. +% = *[], use the length of the current figure's colormap (see COLORMAP). +% +%%% Outputs: +% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. +% +% See also CIVIDIS INFERNO PLASMA VIRIDIS TWILIGHT TAB10 SET LINES COLORMAP PARULA + +if nargin<1 || isempty(N) + N = size(get(gcf,'colormap'),1); +else + assert(isscalar(N)&&isreal(N),'First argument must be a real numeric scalar.') +end +% +raw = [0.001462,0.000466,0.013866; 0.002258,0.001295,0.018331; 0.003279,0.002305,0.023708; 0.004512,0.003490,0.029965; 0.005950,0.004843,0.037130; 0.007588,0.006356,0.044973; 0.009426,0.008022,0.052844; 0.011465,0.009828,0.060750; 0.013708,0.011771,0.068667; 0.016156,0.013840,0.076603; 0.018815,0.016026,0.084584; 0.021692,0.018320,0.092610; 0.024792,0.020715,0.100676; 0.028123,0.023201,0.108787; 0.031696,0.025765,0.116965; 0.035520,0.028397,0.125209; 0.039608,0.031090,0.133515; 0.043830,0.033830,0.141886; 0.048062,0.036607,0.150327; 0.052320,0.039407,0.158841; 0.056615,0.042160,0.167446; 0.060949,0.044794,0.176129; 0.065330,0.047318,0.184892; 0.069764,0.049726,0.193735; 0.074257,0.052017,0.202660; 0.078815,0.054184,0.211667; 0.083446,0.056225,0.220755; 0.088155,0.058133,0.229922; 0.092949,0.059904,0.239164; 0.097833,0.061531,0.248477; 0.102815,0.063010,0.257854; 0.107899,0.064335,0.267289; 0.113094,0.065492,0.276784; 0.118405,0.066479,0.286321; 0.123833,0.067295,0.295879; 0.129380,0.067935,0.305443; 0.135053,0.068391,0.315000; 0.140858,0.068654,0.324538; 0.146785,0.068738,0.334011; 0.152839,0.068637,0.343404; 0.159018,0.068354,0.352688; 0.165308,0.067911,0.361816; 0.171713,0.067305,0.370771; 0.178212,0.066576,0.379497; 0.184801,0.065732,0.387973; 0.191460,0.064818,0.396152; 0.198177,0.063862,0.404009; 0.204935,0.062907,0.411514; 0.211718,0.061992,0.418647; 0.218512,0.061158,0.425392; 0.225302,0.060445,0.431742; 0.232077,0.059889,0.437695; 0.238826,0.059517,0.443256; 0.245543,0.059352,0.448436; 0.252220,0.059415,0.453248; 0.258857,0.059706,0.457710; 0.265447,0.060237,0.461840; 0.271994,0.060994,0.465660; 0.278493,0.061978,0.469190; 0.284951,0.063168,0.472451; 0.291366,0.064553,0.475462; 0.297740,0.066117,0.478243; 0.304081,0.067835,0.480812; 0.310382,0.069702,0.483186; 0.316654,0.071690,0.485380; 0.322899,0.073782,0.487408; 0.329114,0.075972,0.489287; 0.335308,0.078236,0.491024; 0.341482,0.080564,0.492631; 0.347636,0.082946,0.494121; 0.353773,0.085373,0.495501; 0.359898,0.087831,0.496778; 0.366012,0.090314,0.497960; 0.372116,0.092816,0.499053; 0.378211,0.095332,0.500067; 0.384299,0.097855,0.501002; 0.390384,0.100379,0.501864; 0.396467,0.102902,0.502658; 0.402548,0.105420,0.503386; 0.408629,0.107930,0.504052; 0.414709,0.110431,0.504662; 0.420791,0.112920,0.505215; 0.426877,0.115395,0.505714; 0.432967,0.117855,0.506160; 0.439062,0.120298,0.506555; 0.445163,0.122724,0.506901; 0.451271,0.125132,0.507198; 0.457386,0.127522,0.507448; 0.463508,0.129893,0.507652; 0.469640,0.132245,0.507809; 0.475780,0.134577,0.507921; 0.481929,0.136891,0.507989; 0.488088,0.139186,0.508011; 0.494258,0.141462,0.507988; 0.500438,0.143719,0.507920; 0.506629,0.145958,0.507806; 0.512831,0.148179,0.507648; 0.519045,0.150383,0.507443; 0.525270,0.152569,0.507192; 0.531507,0.154739,0.506895; 0.537755,0.156894,0.506551; 0.544015,0.159033,0.506159; 0.550287,0.161158,0.505719; 0.556571,0.163269,0.505230; 0.562866,0.165368,0.504692; 0.569172,0.167454,0.504105; 0.575490,0.169530,0.503466; 0.581819,0.171596,0.502777; 0.588158,0.173652,0.502035; 0.594508,0.175701,0.501241; 0.600868,0.177743,0.500394; 0.607238,0.179779,0.499492; 0.613617,0.181811,0.498536; 0.620005,0.183840,0.497524; 0.626401,0.185867,0.496456; 0.632805,0.187893,0.495332; 0.639216,0.189921,0.494150; 0.645633,0.191952,0.492910; 0.652056,0.193986,0.491611; 0.658483,0.196027,0.490253; 0.664915,0.198075,0.488836; 0.671349,0.200133,0.487358; 0.677786,0.202203,0.485819; 0.684224,0.204286,0.484219; 0.690661,0.206384,0.482558; 0.697098,0.208501,0.480835; 0.703532,0.210638,0.479049; 0.709962,0.212797,0.477201; 0.716387,0.214982,0.475290; 0.722805,0.217194,0.473316; 0.729216,0.219437,0.471279; 0.735616,0.221713,0.469180; 0.742004,0.224025,0.467018; 0.748378,0.226377,0.464794; 0.754737,0.228772,0.462509; 0.761077,0.231214,0.460162; 0.767398,0.233705,0.457755; 0.773695,0.236249,0.455289; 0.779968,0.238851,0.452765; 0.786212,0.241514,0.450184; 0.792427,0.244242,0.447543; 0.798608,0.247040,0.444848; 0.804752,0.249911,0.442102; 0.810855,0.252861,0.439305; 0.816914,0.255895,0.436461; 0.822926,0.259016,0.433573; 0.828886,0.262229,0.430644; 0.834791,0.265540,0.427671; 0.840636,0.268953,0.424666; 0.846416,0.272473,0.421631; 0.852126,0.276106,0.418573; 0.857763,0.279857,0.415496; 0.863320,0.283729,0.412403; 0.868793,0.287728,0.409303; 0.874176,0.291859,0.406205; 0.879464,0.296125,0.403118; 0.884651,0.300530,0.400047; 0.889731,0.305079,0.397002; 0.894700,0.309773,0.393995; 0.899552,0.314616,0.391037; 0.904281,0.319610,0.388137; 0.908884,0.324755,0.385308; 0.913354,0.330052,0.382563; 0.917689,0.335500,0.379915; 0.921884,0.341098,0.377376; 0.925937,0.346844,0.374959; 0.929845,0.352734,0.372677; 0.933606,0.358764,0.370541; 0.937221,0.364929,0.368567; 0.940687,0.371224,0.366762; 0.944006,0.377643,0.365136; 0.947180,0.384178,0.363701; 0.950210,0.390820,0.362468; 0.953099,0.397563,0.361438; 0.955849,0.404400,0.360619; 0.958464,0.411324,0.360014; 0.960949,0.418323,0.359630; 0.963310,0.425390,0.359469; 0.965549,0.432519,0.359529; 0.967671,0.439703,0.359810; 0.969680,0.446936,0.360311; 0.971582,0.454210,0.361030; 0.973381,0.461520,0.361965; 0.975082,0.468861,0.363111; 0.976690,0.476226,0.364466; 0.978210,0.483612,0.366025; 0.979645,0.491014,0.367783; 0.981000,0.498428,0.369734; 0.982279,0.505851,0.371874; 0.983485,0.513280,0.374198; 0.984622,0.520713,0.376698; 0.985693,0.528148,0.379371; 0.986700,0.535582,0.382210; 0.987646,0.543015,0.385210; 0.988533,0.550446,0.388365; 0.989363,0.557873,0.391671; 0.990138,0.565296,0.395122; 0.990871,0.572706,0.398714; 0.991558,0.580107,0.402441; 0.992196,0.587502,0.406299; 0.992785,0.594891,0.410283; 0.993326,0.602275,0.414390; 0.993834,0.609644,0.418613; 0.994309,0.616999,0.422950; 0.994738,0.624350,0.427397; 0.995122,0.631696,0.431951; 0.995480,0.639027,0.436607; 0.995810,0.646344,0.441361; 0.996096,0.653659,0.446213; 0.996341,0.660969,0.451160; 0.996580,0.668256,0.456192; 0.996775,0.675541,0.461314; 0.996925,0.682828,0.466526; 0.997077,0.690088,0.471811; 0.997186,0.697349,0.477182; 0.997254,0.704611,0.482635; 0.997325,0.711848,0.488154; 0.997351,0.719089,0.493755; 0.997351,0.726324,0.499428; 0.997341,0.733545,0.505167; 0.997285,0.740772,0.510983; 0.997228,0.747981,0.516859; 0.997138,0.755190,0.522806; 0.997019,0.762398,0.528821; 0.996898,0.769591,0.534892; 0.996727,0.776795,0.541039; 0.996571,0.783977,0.547233; 0.996369,0.791167,0.553499; 0.996162,0.798348,0.559820; 0.995932,0.805527,0.566202; 0.995680,0.812706,0.572645; 0.995424,0.819875,0.579140; 0.995131,0.827052,0.585701; 0.994851,0.834213,0.592307; 0.994524,0.841387,0.598983; 0.994222,0.848540,0.605696; 0.993866,0.855711,0.612482; 0.993545,0.862859,0.619299; 0.993170,0.870024,0.626189; 0.992831,0.877168,0.633109; 0.992440,0.884330,0.640099; 0.992089,0.891470,0.647116; 0.991688,0.898627,0.654202; 0.991332,0.905763,0.661309; 0.990930,0.912915,0.668481; 0.990570,0.920049,0.675675; 0.990175,0.927196,0.682926; 0.989815,0.934329,0.690198; 0.989434,0.941470,0.697519; 0.989077,0.948604,0.704863; 0.988717,0.955742,0.712242; 0.988367,0.962878,0.719649; 0.988033,0.970012,0.727077; 0.987691,0.977154,0.734536; 0.987387,0.984288,0.742002; 0.987053,0.991438,0.749504]; +% +num = size(raw,1); +% With small extrapolation when N>num: +vec = linspace(0,num+1,N+2); +map = interp1(1:num,raw,vec(2:N+1),'linear','extrap'); +% Interpolation only for all values of N: +%map = interp1(1:num,raw,linspace(1,num,N),'spline') +% Range limits: +map = max(0,min(1,map)); +% +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%magma \ No newline at end of file diff --git a/analysis/MATLAB_functions/matplotlib/matplotlib.png b/analysis/MATLAB_functions/matplotlib/matplotlib.png new file mode 100644 index 0000000..972430d Binary files /dev/null and b/analysis/MATLAB_functions/matplotlib/matplotlib.png differ diff --git a/analysis/MATLAB_functions/matplotlib/plasma.m b/analysis/MATLAB_functions/matplotlib/plasma.m new file mode 100644 index 0000000..9b42c34 --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/plasma.m @@ -0,0 +1,64 @@ +function map = plasma(N) +% Perceptually uniform sequential colormap from MatPlotLib. +% +% Copyright (c) 2017-2019 Stephen Cobeldick +% +%%% Syntax: +% map = plasma +% map = plasma(N) +% +% Colormap designed by Nathaniel J. Smith and Stefan van der Walt. +% +% For MatPlotLib 2.0 improved colormaps were created in the perceptually +% uniform colorspace CAM02-UCS. The new colormaps are introduced here: +% +% The RGB data is from here: +% +% Note VIRIDIS replaces the awful JET as the MatPlotLib default colormap. +% +%% Examples %% +% +%%% Plot the scheme's RGB values: +% rgbplot(plasma(256)) +% +%%% New colors for the COLORMAP example: +% load spine +% image(X) +% colormap(plasma) +% +%%% New colors for the SURF example: +% [X,Y,Z] = peaks(30); +% surfc(X,Y,Z) +% colormap(plasma) +% axis([-3,3,-3,3,-10,5]) +% +%% Input and Output Arguments %% +% +%%% Inputs (*=default): +% N = NumericScalar, N>=0, an integer to define the colormap length. +% = *[], use the length of the current figure's colormap (see COLORMAP). +% +%%% Outputs: +% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. +% +% See also CIVIDIS INFERNO MAGMA VIRIDIS TWILIGHT TAB10 SET LINES COLORMAP PARULA + +if nargin<1 || isempty(N) + N = size(get(gcf,'colormap'),1); +else + assert(isscalar(N)&&isreal(N),'First argument must be a real numeric scalar.') +end +% +raw = [0.050383,0.029803,0.527975; 0.063536,0.028426,0.533124; 0.075353,0.027206,0.538007; 0.086222,0.026125,0.542658; 0.096379,0.025165,0.547103; 0.105980,0.024309,0.551368; 0.115124,0.023556,0.555468; 0.123903,0.022878,0.559423; 0.132381,0.022258,0.563250; 0.140603,0.021687,0.566959; 0.148607,0.021154,0.570562; 0.156421,0.020651,0.574065; 0.164070,0.020171,0.577478; 0.171574,0.019706,0.580806; 0.178950,0.019252,0.584054; 0.186213,0.018803,0.587228; 0.193374,0.018354,0.590330; 0.200445,0.017902,0.593364; 0.207435,0.017442,0.596333; 0.214350,0.016973,0.599239; 0.221197,0.016497,0.602083; 0.227983,0.016007,0.604867; 0.234715,0.015502,0.607592; 0.241396,0.014979,0.610259; 0.248032,0.014439,0.612868; 0.254627,0.013882,0.615419; 0.261183,0.013308,0.617911; 0.267703,0.012716,0.620346; 0.274191,0.012109,0.622722; 0.280648,0.011488,0.625038; 0.287076,0.010855,0.627295; 0.293478,0.010213,0.629490; 0.299855,0.009561,0.631624; 0.306210,0.008902,0.633694; 0.312543,0.008239,0.635700; 0.318856,0.007576,0.637640; 0.325150,0.006915,0.639512; 0.331426,0.006261,0.641316; 0.337683,0.005618,0.643049; 0.343925,0.004991,0.644710; 0.350150,0.004382,0.646298; 0.356359,0.003798,0.647810; 0.362553,0.003243,0.649245; 0.368733,0.002724,0.650601; 0.374897,0.002245,0.651876; 0.381047,0.001814,0.653068; 0.387183,0.001434,0.654177; 0.393304,0.001114,0.655199; 0.399411,0.000859,0.656133; 0.405503,0.000678,0.656977; 0.411580,0.000577,0.657730; 0.417642,0.000564,0.658390; 0.423689,0.000646,0.658956; 0.429719,0.000831,0.659425; 0.435734,0.001127,0.659797; 0.441732,0.001540,0.660069; 0.447714,0.002080,0.660240; 0.453677,0.002755,0.660310; 0.459623,0.003574,0.660277; 0.465550,0.004545,0.660139; 0.471457,0.005678,0.659897; 0.477344,0.006980,0.659549; 0.483210,0.008460,0.659095; 0.489055,0.010127,0.658534; 0.494877,0.011990,0.657865; 0.500678,0.014055,0.657088; 0.506454,0.016333,0.656202; 0.512206,0.018833,0.655209; 0.517933,0.021563,0.654109; 0.523633,0.024532,0.652901; 0.529306,0.027747,0.651586; 0.534952,0.031217,0.650165; 0.540570,0.034950,0.648640; 0.546157,0.038954,0.647010; 0.551715,0.043136,0.645277; 0.557243,0.047331,0.643443; 0.562738,0.051545,0.641509; 0.568201,0.055778,0.639477; 0.573632,0.060028,0.637349; 0.579029,0.064296,0.635126; 0.584391,0.068579,0.632812; 0.589719,0.072878,0.630408; 0.595011,0.077190,0.627917; 0.600266,0.081516,0.625342; 0.605485,0.085854,0.622686; 0.610667,0.090204,0.619951; 0.615812,0.094564,0.617140; 0.620919,0.098934,0.614257; 0.625987,0.103312,0.611305; 0.631017,0.107699,0.608287; 0.636008,0.112092,0.605205; 0.640959,0.116492,0.602065; 0.645872,0.120898,0.598867; 0.650746,0.125309,0.595617; 0.655580,0.129725,0.592317; 0.660374,0.134144,0.588971; 0.665129,0.138566,0.585582; 0.669845,0.142992,0.582154; 0.674522,0.147419,0.578688; 0.679160,0.151848,0.575189; 0.683758,0.156278,0.571660; 0.688318,0.160709,0.568103; 0.692840,0.165141,0.564522; 0.697324,0.169573,0.560919; 0.701769,0.174005,0.557296; 0.706178,0.178437,0.553657; 0.710549,0.182868,0.550004; 0.714883,0.187299,0.546338; 0.719181,0.191729,0.542663; 0.723444,0.196158,0.538981; 0.727670,0.200586,0.535293; 0.731862,0.205013,0.531601; 0.736019,0.209439,0.527908; 0.740143,0.213864,0.524216; 0.744232,0.218288,0.520524; 0.748289,0.222711,0.516834; 0.752312,0.227133,0.513149; 0.756304,0.231555,0.509468; 0.760264,0.235976,0.505794; 0.764193,0.240396,0.502126; 0.768090,0.244817,0.498465; 0.771958,0.249237,0.494813; 0.775796,0.253658,0.491171; 0.779604,0.258078,0.487539; 0.783383,0.262500,0.483918; 0.787133,0.266922,0.480307; 0.790855,0.271345,0.476706; 0.794549,0.275770,0.473117; 0.798216,0.280197,0.469538; 0.801855,0.284626,0.465971; 0.805467,0.289057,0.462415; 0.809052,0.293491,0.458870; 0.812612,0.297928,0.455338; 0.816144,0.302368,0.451816; 0.819651,0.306812,0.448306; 0.823132,0.311261,0.444806; 0.826588,0.315714,0.441316; 0.830018,0.320172,0.437836; 0.833422,0.324635,0.434366; 0.836801,0.329105,0.430905; 0.840155,0.333580,0.427455; 0.843484,0.338062,0.424013; 0.846788,0.342551,0.420579; 0.850066,0.347048,0.417153; 0.853319,0.351553,0.413734; 0.856547,0.356066,0.410322; 0.859750,0.360588,0.406917; 0.862927,0.365119,0.403519; 0.866078,0.369660,0.400126; 0.869203,0.374212,0.396738; 0.872303,0.378774,0.393355; 0.875376,0.383347,0.389976; 0.878423,0.387932,0.386600; 0.881443,0.392529,0.383229; 0.884436,0.397139,0.379860; 0.887402,0.401762,0.376494; 0.890340,0.406398,0.373130; 0.893250,0.411048,0.369768; 0.896131,0.415712,0.366407; 0.898984,0.420392,0.363047; 0.901807,0.425087,0.359688; 0.904601,0.429797,0.356329; 0.907365,0.434524,0.352970; 0.910098,0.439268,0.349610; 0.912800,0.444029,0.346251; 0.915471,0.448807,0.342890; 0.918109,0.453603,0.339529; 0.920714,0.458417,0.336166; 0.923287,0.463251,0.332801; 0.925825,0.468103,0.329435; 0.928329,0.472975,0.326067; 0.930798,0.477867,0.322697; 0.933232,0.482780,0.319325; 0.935630,0.487712,0.315952; 0.937990,0.492667,0.312575; 0.940313,0.497642,0.309197; 0.942598,0.502639,0.305816; 0.944844,0.507658,0.302433; 0.947051,0.512699,0.299049; 0.949217,0.517763,0.295662; 0.951344,0.522850,0.292275; 0.953428,0.527960,0.288883; 0.955470,0.533093,0.285490; 0.957469,0.538250,0.282096; 0.959424,0.543431,0.278701; 0.961336,0.548636,0.275305; 0.963203,0.553865,0.271909; 0.965024,0.559118,0.268513; 0.966798,0.564396,0.265118; 0.968526,0.569700,0.261721; 0.970205,0.575028,0.258325; 0.971835,0.580382,0.254931; 0.973416,0.585761,0.251540; 0.974947,0.591165,0.248151; 0.976428,0.596595,0.244767; 0.977856,0.602051,0.241387; 0.979233,0.607532,0.238013; 0.980556,0.613039,0.234646; 0.981826,0.618572,0.231287; 0.983041,0.624131,0.227937; 0.984199,0.629718,0.224595; 0.985301,0.635330,0.221265; 0.986345,0.640969,0.217948; 0.987332,0.646633,0.214648; 0.988260,0.652325,0.211364; 0.989128,0.658043,0.208100; 0.989935,0.663787,0.204859; 0.990681,0.669558,0.201642; 0.991365,0.675355,0.198453; 0.991985,0.681179,0.195295; 0.992541,0.687030,0.192170; 0.993032,0.692907,0.189084; 0.993456,0.698810,0.186041; 0.993814,0.704741,0.183043; 0.994103,0.710698,0.180097; 0.994324,0.716681,0.177208; 0.994474,0.722691,0.174381; 0.994553,0.728728,0.171622; 0.994561,0.734791,0.168938; 0.994495,0.740880,0.166335; 0.994355,0.746995,0.163821; 0.994141,0.753137,0.161404; 0.993851,0.759304,0.159092; 0.993482,0.765499,0.156891; 0.993033,0.771720,0.154808; 0.992505,0.777967,0.152855; 0.991897,0.784239,0.151042; 0.991209,0.790537,0.149377; 0.990439,0.796859,0.147870; 0.989587,0.803205,0.146529; 0.988648,0.809579,0.145357; 0.987621,0.815978,0.144363; 0.986509,0.822401,0.143557; 0.985314,0.828846,0.142945; 0.984031,0.835315,0.142528; 0.982653,0.841812,0.142303; 0.981190,0.848329,0.142279; 0.979644,0.854866,0.142453; 0.977995,0.861432,0.142808; 0.976265,0.868016,0.143351; 0.974443,0.874622,0.144061; 0.972530,0.881250,0.144923; 0.970533,0.887896,0.145919; 0.968443,0.894564,0.147014; 0.966271,0.901249,0.148180; 0.964021,0.907950,0.149370; 0.961681,0.914672,0.150520; 0.959276,0.921407,0.151566; 0.956808,0.928152,0.152409; 0.954287,0.934908,0.152921; 0.951726,0.941671,0.152925; 0.949151,0.948435,0.152178; 0.946602,0.955190,0.150328; 0.944152,0.961916,0.146861; 0.941896,0.968590,0.140956; 0.940015,0.975158,0.131326]; +% +num = size(raw,1); +% With small extrapolation when N>num: +vec = linspace(0,num+1,N+2); +map = interp1(1:num,raw,vec(2:N+1),'linear','extrap'); +% Interpolation only for all values of N: +%map = interp1(1:num,raw,linspace(1,num,N),'spline') +% Range limits: +map = max(0,min(1,map)); +% +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%plasma \ No newline at end of file diff --git a/analysis/MATLAB_functions/matplotlib/tab10.m b/analysis/MATLAB_functions/matplotlib/tab10.m new file mode 100644 index 0000000..4854250 --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/tab10.m @@ -0,0 +1,70 @@ +function map = tab10(N) +% Qualitative colormap from MatPlotLib, for plots using the line ColorOrder. +% In MatPlotLib 2 it is named VEGA10, for MatPlotLib 3 was renamed TAB10. +% +% Copyright (c) 2017-2019 Stephen Cobeldick +% +%%% Syntax: +% map = tab10 +% map = tab10(N) +% +% For MatPlotLib 2.0 improved colormaps were created for plot lines of +% categorical data. The new colormaps are introduced here: +% +% VEGA10/TAB10 is the default Line Color Order for MatPlotLib 2 and 3. +% +% MATLAB axes ColorOrder (note that this is NOT the axes COLORMAP): +% +% +% +%% Examples %% +% +%%% PLOT using matrices: +% N = 10; +% axes('ColorOrder',tab10(N),'NextPlot','replacechildren') +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*sin(x+2*n*pi/N), X(:), 1:N); +% plot(X,Y, 'linewidth',4) +% +%%% PLOT in a loop: +% N = 10; +% set(0,'DefaultAxesColorOrder',tab10(N)) +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*sin(x+2*n*pi/N), X(:), 1:N); +% for n = 1:N +% plot(X(:),Y(:,n), 'linewidth',4); +% hold all +% end +% +%%% LINE using matrices: +% N = 10; +% set(0,'DefaultAxesColorOrder',tab10(N)) +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*cos(x+2*n*pi/N), X(:), 1:N); +% line(X(:),Y) +% +%% Input and Output Arguments %% +% +%%% Inputs (*=default): +% N = NumericScalar, N>=0, an integer to define the colormap length. +% = *[], use the length of the current figure's colormap (see COLORMAP). +% +%%% Outputs: +% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. +% +% See also TAB20 TAB20B TAB20C SET VIRIDIS TWILIGHT LINES COLORMAP PARULA + +if nargin<1 + N = size(get(gcf,'colormap'),1); +else + assert(isscalar(N)&&isreal(N),'First argument must be a real numeric scalar.') + assert(fix(N)==N&&N>=0,'First argument must be a positive integer.') +end +% +hex = ['#1f77b4';'#ff7f0e';'#2ca02c';'#d62728';'#9467bd';'#8c564b';'#e377c2';'#7f7f7f';'#bcbd22';'#17becf']; +raw = sscanf(hex.','#%2x%2x%2x',[3,Inf]).'; +% +map = raw(1+mod(0:N-1,size(raw,1)),:) / 255; +% +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%tab10 \ No newline at end of file diff --git a/analysis/MATLAB_functions/matplotlib/tab20.m b/analysis/MATLAB_functions/matplotlib/tab20.m new file mode 100644 index 0000000..7919ee6 --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/tab20.m @@ -0,0 +1,70 @@ +function map = tab20(N) +% Qualitative colormap from MatPlotLib, for plots using the line ColorOrder. +% In MatPlotLib 2 it is named VEGA20, for MatPlotLib 3 was renamed TAB20. +% +% Copyright (c) 2017-2019 Stephen Cobeldick +% +%%% Syntax: +% map = tab20 +% map = tab20(N) +% +% For MatPlotLib 2.0 improved colormaps were created for plot lines of +% categorical data. The new colormaps are introduced here: +% +% VEGA10/TAB10 is the default Line Color Order for MatPlotLib 2 and 3. +% +% MATLAB axes ColorOrder (note that this is NOT the axes COLORMAP): +% +% +% +%% Examples %% +% +%%% PLOT using matrices: +% N = 20; +% axes('ColorOrder',tab20(N),'NextPlot','replacechildren') +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*sin(x+2*n*pi/N), X(:), 1:N); +% plot(X,Y, 'linewidth',4) +% +%%% PLOT in a loop: +% N = 20; +% set(0,'DefaultAxesColorOrder',tab20(N)) +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*sin(x+2*n*pi/N), X(:), 1:N); +% for n = 1:N +% plot(X(:),Y(:,n), 'linewidth',4); +% hold all +% end +% +%%% LINE using matrices: +% N = 20; +% set(0,'DefaultAxesColorOrder',tab20(N)) +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*cos(x+2*n*pi/N), X(:), 1:N); +% line(X(:),Y) +% +%% Input and Output Arguments %% +% +%%% Inputs (*=default): +% N = NumericScalar, N>=0, an integer to define the colormap length. +% = *[], use the length of the current figure's colormap (see COLORMAP). +% +%%% Outputs: +% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. +% +% See also TAB10 TAB20B TAB20C SET TWILIGHT VIRIDIS LINES COLORMAP PARULA + +if nargin<1 + N = size(get(gcf,'colormap'),1); +else + assert(isscalar(N)&&isreal(N),'First argument must be a real numeric scalar.') + assert(fix(N)==N&&N>=0,'First argument must be a positive integer.') +end +% +hex = ['#1f77b4';'#aec7e8';'#ff7f0e';'#ffbb78';'#2ca02c';'#98df8a';'#d62728';'#ff9896';'#9467bd';'#c5b0d5';'#8c564b';'#c49c94';'#e377c2';'#f7b6d2';'#7f7f7f';'#c7c7c7';'#bcbd22';'#dbdb8d';'#17becf';'#9edae5']; +raw = sscanf(hex.','#%2x%2x%2x',[3,Inf]).'; +% +map = raw(1+mod(0:N-1,size(raw,1)),:) / 255; +% +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%tab20 \ No newline at end of file diff --git a/analysis/MATLAB_functions/matplotlib/tab20b.m b/analysis/MATLAB_functions/matplotlib/tab20b.m new file mode 100644 index 0000000..fc4fb99 --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/tab20b.m @@ -0,0 +1,70 @@ +function map = tab20b(N) +% Qualitative colormap from MatPlotLib, for plots using the line ColorOrder. +% In MatPlotLib 2 it is named VEGA20b, for MatPlotLib 3 was renamed TAB20b. +% +% Copyright (c) 2017-2019 Stephen Cobeldick +% +%%% Syntax: +% map = tab20b +% map = tab20b(N) +% +% For MatPlotLib 2.0 improved colormaps were created for plot lines of +% categorical data. The new colormaps are introduced here: +% +% VEGA10/TAB10 is the default Line Color Order for MatPlotLib 2 and 3. +% +% MATLAB axes ColorOrder (note that this is NOT the axes COLORMAP): +% +% +% +%% Examples %% +% +%%% PLOT using matrices: +% N = 20; +% axes('ColorOrder',tab20b(N),'NextPlot','replacechildren') +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*sin(x+2*n*pi/N), X(:), 1:N); +% plot(X,Y, 'linewidth',4) +% +%%% PLOT in a loop: +% N = 20; +% set(0,'DefaultAxesColorOrder',tab20b(N)) +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*sin(x+2*n*pi/N), X(:), 1:N); +% for n = 1:N +% plot(X(:),Y(:,n), 'linewidth',4); +% hold all +% end +% +%%% LINE using matrices: +% N = 20; +% set(0,'DefaultAxesColorOrder',tab20b(N)) +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*cos(x+2*n*pi/N), X(:), 1:N); +% line(X(:),Y) +% +%% Input and Output Arguments %% +% +%%% Inputs (*=default): +% N = NumericScalar, N>=0, an integer to define the colormap length. +% = *[], use the length of the current figure's colormap (see COLORMAP). +% +%%% Outputs: +% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. +% +% See also TAB10 TAB20 TAB20C SET TWILIGHT VIRIDIS LINES COLORMAP PARULA + +if nargin<1 + N = size(get(gcf,'colormap'),1); +else + assert(isscalar(N)&&isreal(N),'First argument must be a real numeric scalar.') + assert(fix(N)==N&&N>=0,'First argument must be a positive integer.') +end +% +hex = ['#393b79';'#5254a3';'#6b6ecf';'#9c9ede';'#637939';'#8ca252';'#b5cf6b';'#cedb9c';'#8c6d31';'#bd9e39';'#e7ba52';'#e7cb94';'#843c39';'#ad494a';'#d6616b';'#e7969c';'#7b4173';'#a55194';'#ce6dbd';'#de9ed6']; +raw = sscanf(hex.','#%2x%2x%2x',[3,Inf]).'; +% +map = raw(1+mod(0:N-1,size(raw,1)),:) / 255; +% +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%tab20b \ No newline at end of file diff --git a/analysis/MATLAB_functions/matplotlib/tab20c.m b/analysis/MATLAB_functions/matplotlib/tab20c.m new file mode 100644 index 0000000..08e2b01 --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/tab20c.m @@ -0,0 +1,70 @@ +function map = tab20c(N) +% Qualitative colormap from MatPlotLib, for plots using the line ColorOrder. +% In MatPlotLib 2 it is named VEGA20c, for MatPlotLib 3 was renamed TAB20c. +% +% Copyright (c) 2017-2019 Stephen Cobeldick +% +%%% Syntax: +% map = tab20c +% map = tab20c(N) +% +% For MatPlotLib 2.0 improved colormaps were created for plot lines of +% categorical data. The new colormaps are introduced here: +% +% VEGA10/TAB10 is the default Line Color Order for MatPlotLib 2 and 3. +% +% MATLAB axes ColorOrder (note that this is NOT the axes COLORMAP): +% +% +% +%% Examples %% +% +%%% PLOT using matrices: +% N = 20; +% axes('ColorOrder',tab20c(N),'NextPlot','replacechildren') +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*sin(x+2*n*pi/N), X(:), 1:N); +% plot(X,Y, 'linewidth',4) +% +%%% PLOT in a loop: +% N = 20; +% set(0,'DefaultAxesColorOrder',tab20c(N)) +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*sin(x+2*n*pi/N), X(:), 1:N); +% for n = 1:N +% plot(X(:),Y(:,n), 'linewidth',4); +% hold all +% end +% +%%% LINE using matrices: +% N = 20; +% set(0,'DefaultAxesColorOrder',tab20c(N)) +% X = linspace(0,pi*3,1000); +% Y = bsxfun(@(x,n)sqrt(n)*cos(x+2*n*pi/N), X(:), 1:N); +% line(X(:),Y) +% +%% Input and Output Arguments %% +% +%%% Inputs (*=default): +% N = NumericScalar, N>=0, an integer to define the colormap length. +% = *[], use the length of the current figure's colormap (see COLORMAP). +% +%%% Outputs: +% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. +% +% See also TAB10 TAB20 TAB20B SET TWILIGHT VIRIDIS LINES COLORMAP PARULA + +if nargin<1 + N = size(get(gcf,'colormap'),1); +else + assert(isscalar(N)&&isreal(N),'First argument must be a real numeric scalar.') + assert(fix(N)==N&&N>=0,'First argument must be a positive integer.') +end +% +hex = ['#3182bd';'#6baed6';'#9ecae1';'#c6dbef';'#e6550d';'#fd8d3c';'#fdae6b';'#fdd0a2';'#31a354';'#74c476';'#a1d99b';'#c7e9c0';'#756bb1';'#9e9ac8';'#bcbddc';'#dadaeb';'#636363';'#969696';'#bdbdbd';'#d9d9d9']; +raw = sscanf(hex.','#%2x%2x%2x',[3,Inf]).'; +% +map = raw(1+mod(0:N-1,size(raw,1)),:) / 255; +% +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%tab20c \ No newline at end of file diff --git a/analysis/MATLAB_functions/matplotlib/twilight.m b/analysis/MATLAB_functions/matplotlib/twilight.m new file mode 100644 index 0000000..f68207a --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/twilight.m @@ -0,0 +1,60 @@ +function map = twilight(N) +% Perceptually uniform cyclic colormap from MatPlotLib. +% +% Copyright (c) 2015 Bastian Bechtold +% Copyright (c) 2017-2019 Stephen Cobeldick +% +%%% Syntax: +% map = twilight +% map = twilight(N) +% +% Colormap designed by Bastian Bechtold. +% +% Cyclic colormaps are designed for plotting data that repeats, therefore the +% colormap loops around (the first and last colors tend to the same color). +% Note that MatPlotLib's TWILIGHT_SHIFTED can be generated very easily: +% map = flipud(circshift(twilight(N),fix(N/2),1)); +% +%% Examples %% +% +%%% Plot the scheme's RGB values: +% rgbplot(twilight(256)) +% +%%% New colors for the COLORMAP example: +% load spine +% image(X) +% colormap(twilight) +% +%%% New colors for the SURF example: +% [X,Y,Z] = peaks(30); +% surfc(X,Y,Z) +% colormap(twilight) +% axis([-3,3,-3,3,-10,5]) +% +%% Input and Output Arguments %% +% +%%% Inputs (*=default): +% N = NumericScalar, N>=0, an integer to define the colormap length. +% = *[], use the length of the current figure's colormap (see COLORMAP). +% +%%% Outputs: +% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. +% +% See also CIVIDIS INFERNO MAGMA PLASMA VIRIDIS TAB10 SET LINES COLORMAP PARULA + +if nargin<1 || isempty(N) + N = size(get(gcf,'colormap'),1); +else + assert(isscalar(N)&&isreal(N),'First argument must be a real numeric scalar.') +end +% +raw = [0.95588623,0.91961077,0.95812116;0.94967876,0.91615763,0.95315546;0.94353853,0.91268927,0.94824212;0.9374452,0.90921449,0.94337733;0.93140447,0.90573033,0.93856712;0.92542215,0.90223373,0.93381777;0.91947392,0.89873478,0.92912752;0.91357865,0.89522463,0.92450721;0.90772105,0.89170929,0.91995838;0.90189106,0.88819234,0.91548457;0.8960938,0.8846711,0.91109116;0.89031153,0.88115247,0.90677917;0.88453669,0.87763908,0.90255063;0.87877004,0.87413042,0.89840629;0.87299914,0.87063131,0.89434535;0.86721094,0.86714674,0.89036725;0.86141058,0.86367475,0.88646923;0.85559299,0.86021735,0.88264858;0.84974682,0.85677881,0.87890418;0.84387192,0.85335917,0.87523342;0.83797164,0.84995717,0.87163289;0.83204469,0.84657319,0.86810058;0.82609045,0.84320733,0.86463493;0.82010052,0.83986227,0.86123767;0.81408416,0.83653448,0.85790541;0.80804251,0.83322322,0.85463767;0.80197661,0.82992779,0.85143441;0.79588772,0.82664733,0.84829592;0.78977733,0.82338091,0.8452227;0.78364717,0.82012747,0.84221541;0.7774989,0.81688599,0.83927495;0.77133274,0.81365586,0.83640309;0.76515383,0.81043494,0.83359933;0.75896452,0.80722199,0.83086447;0.75276734,0.80401573,0.82819926;0.74656497,0.80081486,0.82560433;0.74036019,0.79761806,0.82308018;0.73415594,0.79442399,0.82062712;0.72795524,0.79123135,0.81824533;0.7217612,0.78803884,0.81593475;0.71557653,0.78484528,0.81369544;0.70940398,0.78164957,0.81152729;0.70324772,0.77845022,0.80942895;0.69711099,0.77524608,0.8073995;0.69099696,0.77203607,0.8054378;0.68490872,0.76881916,0.80354253;0.67884928,0.76559441,0.80171222;0.67282151,0.76236096,0.79994524;0.66682814,0.75911802,0.79823983;0.66087179,0.7558649,0.79659413;0.65495439,0.75260107,0.7950067;0.64907877,0.74932586,0.79347499;0.64324724,0.74603878,0.79199677;0.63746171,0.74273942,0.79056997;0.63172396,0.73942747,0.7891925;0.62603562,0.73610266,0.78786229;0.62039814,0.73276477,0.78657732;0.61481293,0.72941363,0.78533547;0.60928127,0.72604912,0.7841347;0.60380419,0.72267116,0.78297314;0.59838267,0.71927971,0.78184895;0.59301756,0.71587476,0.78076036;0.58770967,0.7124563,0.77970565;0.5824597,0.70902436,0.77868317;0.57726849,0.70557897,0.77769104;0.5721366,0.70212016,0.77672775;0.56706445,0.69864803,0.7757921;0.56205254,0.69516262,0.77488269;0.55710135,0.69166401,0.7739982;0.55221135,0.68815225,0.77313735;0.54738299,0.68462741,0.77229891;0.54261669,0.68108954,0.7714817;0.53791302,0.6775387,0.77068427;0.53327235,0.67397494,0.76990557;0.52869499,0.67039831,0.76914482;0.52418136,0.66680884,0.76840101;0.51973187,0.66320657,0.76767313;0.51534697,0.65959152,0.76696023;0.51102708,0.6559637,0.76626135;0.50677264,0.65232312,0.76557558;0.50258409,0.64866978,0.76490201;0.49846187,0.64500368,0.76423976;0.49440652,0.64132483,0.7635876;0.49041839,0.63763319,0.76294498;0.48649792,0.63392874,0.76231111;0.48264558,0.63021144,0.76168515;0.4788618,0.62648125,0.76106626;0.47514703,0.62273814,0.76045361;0.4715017,0.61898207,0.75984637;0.46792623,0.61521297,0.75924371;0.46442103,0.6114308,0.75864479;0.4609865,0.6076355,0.7580488;0.45762301,0.60382702,0.7574549;0.45433091,0.60000529,0.75686228;0.45111051,0.59617026,0.75626997;0.44796212,0.59232188,0.75567717;0.44488599,0.58846006,0.75508316;0.44188237,0.58458473,0.7544871;0.43895145,0.58069584,0.75388814;0.43609336,0.5767933,0.75328544;0.43330824,0.57287707,0.75267815;0.43059613,0.56894708,0.75206541;0.42795705,0.56500326,0.75144639;0.42539095,0.56104556,0.75082021;0.42289775,0.55707392,0.75018601;0.42047728,0.55308828,0.74954294;0.41812934,0.54908859,0.74889012;0.41585365,0.54507481,0.7482267;0.41364987,0.54104688,0.7475518;0.41151761,0.53700476,0.74686455;0.40945636,0.53294843,0.74616402;0.40746562,0.52887785,0.74544937;0.40554478,0.52479298,0.74471976;0.4036932,0.52069379,0.74397434;0.40191012,0.51658025,0.74321222;0.40019476,0.51245234,0.74243254;0.39854625,0.50831006,0.74163443;0.39696364,0.50415338,0.74081703;0.39544595,0.4999823,0.73997947;0.39399211,0.49579683,0.7391209;0.39260099,0.49159695,0.73824046;0.39127141,0.48738268,0.73733729;0.39000213,0.48315403,0.73641054;0.38879184,0.478911,0.73545936;0.3876392,0.47465363,0.73448291;0.38654279,0.47038193,0.73348035;0.38550116,0.46609593,0.73245082;0.38451281,0.46179566,0.73139351;0.3835762,0.45748116,0.73030757;0.38268975,0.45315247,0.72919218;0.38185182,0.44880962,0.7280465;0.38106076,0.44445268,0.72686969;0.38031486,0.44008169,0.72566094;0.37961245,0.43569671,0.72441943;0.37895177,0.43129778,0.72314434;0.37833106,0.42688498,0.72183484;0.37774855,0.42245837,0.72049011;0.37720243,0.41801803,0.71910933;0.37669089,0.41356403,0.71769166;0.37621211,0.40909646,0.71623627;0.37576424,0.4046154,0.71474232;0.37534545,0.40012094,0.71320896;0.3749539,0.39561319,0.71163536;0.37458773,0.39109226,0.71002064;0.3742451,0.38655825,0.70836394;0.37392415,0.38201129,0.7066644;0.37362303,0.3774515,0.70492111;0.37333991,0.37287903,0.70313318;0.37307294,0.36829402,0.70129969;0.37282029,0.36369664,0.69941971;0.37258013,0.35908705,0.69749231;0.37235064,0.35446544,0.6955165;0.37212999,0.349832,0.69349132;0.3719164,0.34518697,0.69141574;0.37170804,0.34053056,0.68928875;0.37150314,0.33586303,0.68710929;0.37130003,0.33118458,0.68487633;0.37109685,0.32649557,0.68258873;0.3708918,0.32179632,0.68024534;0.37068312,0.31708718,0.67784499;0.37046904,0.31236853,0.67538648;0.3702478,0.3076408,0.67286859;0.37001764,0.30290445,0.67029004;0.3697768,0.29815996,0.66764952;0.36952351,0.29340788,0.6649457;0.36925602,0.28864881,0.66217719;0.36897256,0.28388339,0.65934258;0.36867134,0.27911233,0.6564404;0.36835059,0.27433641,0.65346914;0.3680085,0.26955647,0.65042726;0.36764328,0.26477344,0.64731318;0.36725311,0.25998832,0.64412527;0.3668366,0.25520194,0.64086184;0.36639158,0.2504157,0.63752117;0.36591607,0.24563096,0.63410149;0.36540817,0.24084915,0.63060103;0.36486595,0.23607183,0.62701797;0.36428747,0.2313007,0.62335047;0.36367073,0.2265376,0.61959664;0.36301372,0.22178452,0.61575461;0.36231439,0.21704365,0.61182247;0.36157068,0.21231734,0.60779834;0.36078129,0.20760765,0.60367993;0.35994327,0.20291779,0.59946566;0.35905442,0.19825076,0.59515371;0.35811253,0.19360973,0.59074229;0.35711536,0.18899812,0.5862297;0.35606065,0.18441957,0.5816143;0.35494612,0.17987796,0.57689459;0.35377006,0.17537711,0.57206861;0.35252969,0.17092163,0.56713551;0.35122252,0.1665162,0.56209448;0.34984626,0.16216558,0.55694478;0.34839867,0.15787473,0.5516859;0.34687754,0.15364873,0.54631766;0.34528103,0.14949272,0.54083967;0.34360674,0.1454121,0.535253;0.34185263,0.14141215,0.5295588;0.34001688,0.13749807,0.52375852;0.33809785,0.13367489,0.51785407;0.33609404,0.12994744,0.51184794;0.33400409,0.12632016,0.50574349;0.33182701,0.12279709,0.49954424;0.32956205,0.11938176,0.49325427;0.32720876,0.11607711,0.48687817;0.32476698,0.1128854,0.48042104;0.32223661,0.10980755,0.47389029;0.31961836,0.10684434,0.46729116;0.31691312,0.10399563,0.46062961;0.31412208,0.10126033,0.45391229;0.31124668,0.09863647,0.44714607;0.30828872,0.09612127,0.44033795;0.30525021,0.09371113,0.433495;0.30213347,0.09140049,0.42662674;0.29894109,0.08918489,0.41973884;0.29567576,0.08705943,0.41283683;0.2923403,0.08501829,0.40592705;0.28893761,0.08305536,0.39901552;0.28547067,0.08116432,0.39210787;0.28194249,0.07933875,0.38520933;0.27835606,0.07757226,0.37832469;0.27471434,0.07585853,0.37145825;0.27102024,0.07419145,0.36461386;0.26727656,0.0725651,0.35779486;0.263486,0.07097387,0.35100416;0.25965113,0.06941247,0.34424417;0.2557744,0.06787594,0.33751691;0.2518586,0.06635773,0.33082656;0.24790678,0.06485041,0.32417842;0.24392,0.06335391,0.31756813;0.23990011,0.0618647,0.31099621;0.23584881,0.06037959,0.30446287;0.23176762,0.05889569,0.29796805;0.22765793,0.05741044,0.29151145;0.2235249,0.0559091,0.28510781;0.21936673,0.05439937,0.2787442;0.21518395,0.05288082,0.27241805;0.21097738,0.05135188,0.26612831;0.20675095,0.04980177,0.25988492;0.20250558,0.04822872,0.25368699;0.19823879,0.04664038,0.24752274;0.19395092,0.04503581,0.24139075;0.18964939,0.04339464,0.2353118;0.18532874,0.04173194,0.22926588;0.18098806,0.04004406,0.22324832;0.17663372,0.03832764,0.21727622;0.1722628,0.0366263,0.21133883;0.16787203,0.03494898,0.20542535;0.16346916,0.03327796,0.19955633;0.15904897,0.03162694,0.19371576;0.15460852,0.03000286,0.18789489;0.15015881,0.02838308,0.18212224;0.1456879,0.02679372,0.17636536;0.14120085,0.02522488,0.17063713;0.13669847,0.02367601,0.16493914;0.13217294,0.02216185,0.15925166;0.13715771,0.0238647,0.16279915;0.142138,0.02560107,0.16632081;0.14712696,0.02735575,0.16981697;0.15211729,0.02913553,0.17328696;0.15711127,0.03093684,0.17673054;0.1621132,0.03275335,0.18014741;0.16711334,0.03459602,0.18353723;0.17212778,0.03644357,0.18689953;0.17714184,0.03831372,0.19023414;0.18216272,0.04019623,0.19354057;0.18719181,0.04204197,0.19681833;0.19222138,0.04385446,0.20006748;0.19726438,0.04562162,0.20328673;0.20231059,0.04735883,0.20647637;0.20736026,0.04906721,0.20963605;0.21242374,0.05073417,0.21276409;0.21748944,0.05237662,0.21586133;0.22256097,0.05399093,0.21892687;0.2276448,0.05556951,0.22195906;0.2327317,0.05712593,0.22495882;0.23782409,0.05865801,0.2279252;0.24292948,0.06015655,0.23085593;0.24803856,0.06163518,0.23375227;0.25315165,0.06309447,0.23661359;0.25827753,0.06452336,0.23943683;0.26340901,0.06593256,0.24222299;0.26854476,0.0673248,0.24497172;0.27368637,0.06869883,0.24768176;0.27883959,0.07004759,0.25035015;0.28399705,0.0713821,0.2529784;0.28915882,0.07270312,0.2555656;0.29432497,0.07401148,0.25811079;0.29950154,0.07529967,0.26061023;0.30468256,0.07657683,0.26306525;0.30986729,0.07784489,0.26547507;0.31505561,0.07910492,0.2678386;0.32024732,0.0803581,0.2701547;0.32544482,0.08160204,0.27242069;0.33064667,0.08283969,0.27463586;0.33585053,0.08407525,0.27680013;0.34105598,0.08531029,0.27891231;0.34626256,0.08654644,0.28097121;0.35146972,0.08778547,0.28297562;0.35667687,0.08902924,0.28492434;0.36188334,0.09027973,0.28681618;0.36708839,0.09153902,0.28864998;0.37229131,0.09280915,0.2904245;0.37749189,0.09409153,0.29213802;0.38268807,0.09539008,0.29379048;0.38787885,0.09670726,0.29538088;0.39306317,0.09804561,0.29690835;0.39823991,0.09940776,0.29837204;0.40340787,0.10079637,0.29977124;0.40856581,0.10221419,0.30110533;0.41371275,0.10366356,0.30237338;0.41884758,0.10514695,0.30357463;0.42396841,0.1066678,0.3047094;0.42907377,0.10822892,0.30577763;0.43416218,0.10983307,0.3067794;0.43923211,0.11148296,0.30771496;0.44428204,0.11318118,0.30858474;0.44931042,0.11493024,0.30938934;0.45431572,0.11673249,0.31012956;0.45929645,0.11859012,0.31080632;0.46425232,0.12050381,0.31141829;0.46918047,0.12247703,0.31196941;0.47407948,0.12451142,0.31246122;0.47894794,0.12660841,0.31289546;0.48378454,0.12876919,0.31327402;0.48858861,0.13099415,0.31359736;0.49335851,0.13328448,0.3138686;0.4980928,0.13564099,0.31409096;0.50279043,0.13806389,0.31426689;0.50745058,0.1405531,0.31439855;0.51207262,0.14310825,0.31448774;0.51665528,0.1457293,0.31453872;0.52119791,0.14841559,0.31455424;0.52569995,0.15116629,0.31453693;0.53016101,0.15398036,0.31448913;0.53458045,0.1568568,0.31441462;0.53895794,0.15979435,0.31431622;0.54329324,0.16279163,0.31419663;0.54758618,0.16584718,0.31405871;0.55183659,0.16895949,0.3139054;0.55604443,0.17212695,0.31373936;0.56020971,0.17534794,0.31356335;0.56433247,0.1786208,0.31338008;0.56841285,0.18194387,0.31319183;0.57245099,0.1853155,0.31300097;0.57644706,0.18873401,0.31281029;0.58040129,0.19219776,0.31262196;0.58431392,0.19570523,0.31243779;0.58818523,0.19925487,0.31225983;0.59201548,0.20284508,0.31209072;0.59580496,0.20647443,0.31193222;0.59955398,0.2101416,0.31178574;0.60326283,0.21384527,0.31165305;0.60693181,0.21758404,0.31153632;0.61056126,0.22135662,0.31143744;0.61415144,0.22516202,0.3113573;0.61770261,0.22899913,0.31129746;0.62121505,0.23286692,0.3112594;0.62468917,0.23676405,0.31124564;0.6281251,0.24068989,0.31125653;0.63152309,0.24464358,0.3112934;0.63488335,0.24862429,0.3113576;0.63820616,0.25263112,0.31145067;0.64149182,0.25666317,0.31157436;0.64474038,0.26072,0.31172919;0.64795203,0.26480095,0.3119164;0.65112691,0.26890541,0.31213721;0.65426523,0.27303275,0.31239299;0.65736724,0.27718218,0.31268539;0.66043291,0.28135348,0.31301496;0.66346234,0.28554617,0.31338289;0.66645563,0.28975979,0.31379035;0.66941285,0.29399391,0.31423853;0.67233423,0.29824791,0.31472899;0.67521975,0.30252154,0.31526265;0.67806939,0.30681452,0.31584052;0.68088318,0.3111265,0.31646379;0.68366117,0.31545715,0.31713364;0.68640337,0.31980615,0.31785128;0.68910996,0.324173,0.31861821;0.69178081,0.32855759,0.31943534;0.6944159,0.33295966,0.32030382;0.69701522,0.33737894,0.32122489;0.69957876,0.34181516,0.32219978;0.70210653,0.34626807,0.3232297;0.7045986,0.35073729,0.32431605;0.70705492,0.35522263,0.32545997;0.70947542,0.3597239,0.32666265;0.7118601,0.36424085,0.32792534;0.71420894,0.36877323,0.3292493;0.71652194,0.37332079,0.3306358;0.71879913,0.37788325,0.33208612;0.72104061,0.38246028,0.3336016;0.72324628,0.38705172,0.33518339;0.72541618,0.3916573,0.33683277;0.72755035,0.39627674,0.33855099;0.72964884,0.40090978,0.34033932;0.73171172,0.40555611,0.34219899;0.73373911,0.41021541,0.34413127;0.73573115,0.41488736,0.34613738;0.73768789,0.41957169,0.34821851;0.73960949,0.42426807,0.35037584;0.7414961,0.42897616,0.35261056;0.74334793,0.43369562,0.35492382;0.74516521,0.43842607,0.35731674;0.74694821,0.44316712,0.35979044;0.74869724,0.44791835,0.36234598;0.75041257,0.4526794,0.36498439;0.75209454,0.45744986,0.36770666;0.75374356,0.46222929,0.37051374;0.75536003,0.46701725,0.37340656;0.75694444,0.47181326,0.37638597;0.75849733,0.47661683,0.37945279;0.76001934,0.48142741,0.38260777;0.76151097,0.48624456,0.38585161;0.76297286,0.49106776,0.38918495;0.76440573,0.49589647,0.39260837;0.76581031,0.50073015,0.39612236;0.76718741,0.50556824,0.39972737;0.76853788,0.51041015,0.40342376;0.76986291,0.51525513,0.40721173;0.77116324,0.52010271,0.41109152;0.77243989,0.5249523,0.41506327;0.77369391,0.52980327,0.41912699;0.77492645,0.53465502,0.42328264;0.77613869,0.53950688,0.42753006;0.77733187,0.54435824,0.43186902;0.77850729,0.54920844,0.43629918;0.77966679,0.55405656,0.44081985;0.78081138,0.55890219,0.4454307;0.78194248,0.56374468,0.45013112;0.7830616,0.5685834,0.45492037;0.78417029,0.57341769,0.45979765;0.78527014,0.57824693,0.46476204;0.78636281,0.58307048,0.46981252;0.78744997,0.58788771,0.474948;0.78853333,0.59269801,0.48016727;0.78961491,0.59750067,0.48546886;0.79069671,0.60229498,0.49085119;0.79178009,0.6070806,0.49631312;0.79286688,0.61185698,0.50185312;0.7939589,0.61662359,0.50746956;0.79505802,0.62137992,0.51316075;0.79616609,0.62612549,0.51892492;0.79728497,0.63085984,0.52476024;0.79841652,0.63558252,0.53066483;0.7995626,0.64029314,0.53663673;0.80072505,0.64499131,0.54267394;0.80190568,0.64967668,0.54877442;0.80310632,0.65434893,0.55493609;0.80432873,0.65900778,0.56115682;0.80557466,0.66365295,0.56743447;0.80684582,0.66828424,0.57376686;0.80814389,0.67290145,0.58015179;0.8094705,0.67750443,0.58658707;0.81082722,0.68209304,0.59307049;0.81221558,0.68666721,0.59959981;0.81363705,0.69122688,0.60617284;0.81509306,0.69577202,0.61278737;0.81658494,0.70030265,0.6194412;0.81811398,0.70481883,0.62613217;0.81968139,0.70932062,0.63285811;0.82128832,0.71380816,0.63961689;0.82293582,0.71828159,0.64640643;0.82462489,0.7227411,0.65322464;0.82635642,0.72718691,0.66006948;0.82813124,0.73161926,0.66693898;0.82995006,0.73603846,0.67383115;0.83181351,0.74044483,0.68074409;0.83372214,0.74483873,0.68767592;0.83567636,0.74922057,0.69462479;0.83767708,0.75359061,0.70158791;0.83972535,0.75794913,0.70856199;0.84181991,0.76229704,0.71554745;0.84396065,0.76663495,0.72254259;0.84614733,0.77096352,0.72954568;0.8483795,0.77528348,0.73655503;0.85065653,0.77959564,0.74356888;0.85297758,0.7839009,0.75058542;0.8553436,0.7881998,0.75759877;0.8577521,0.79249376,0.76460878;0.86020061,0.79678427,0.77161459;0.8626872,0.80107277,0.77861331;0.86520968,0.80536087,0.78560141;0.86776571,0.8096503,0.79257445;0.87035656,0.81394216,0.79951954;0.87297684,0.81823907,0.80643635;0.87562545,0.82254271,0.81331573;0.87830287,0.82685434,0.8201464;0.88101291,0.83117417,0.82691355;0.88376436,0.8355008,0.83359813;0.88656419,0.83983241,0.84019282;0.88942615,0.84416471,0.84668696;0.89236612,0.84849196,0.85307571;0.89540326,0.85280703,0.85935491;0.89854578,0.85710498,0.86554325;0.90180023,0.86138156,0.87165915;0.90516762,0.86563454,0.87772373;0.90864556,0.86986351,0.88375343;0.91222303,0.87407051,0.8897753;0.91589042,0.87825797,0.89580632;0.91963903,0.88242879,0.9018554;0.92345937,0.88658601,0.90793267;0.92734253,0.89073234,0.914049;0.93128235,0.89487013,0.92020762;0.93527444,0.89900167,0.92640565;0.93931328,0.90312833,0.93265281;0.94339574,0.90725141,0.93895042;0.9475205,0.91137261,0.94528884;0.95168443,0.9154922,0.95167893;0.95588623,0.91961077,0.95812116]; +% +num = size(raw,1); +vec = linspace(1,num,N+1); +map = interp1(1:num,raw,vec(1:N),'spline'); +% Range limits: +map = max(0,min(1,map)); +% +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%twilight \ No newline at end of file diff --git a/analysis/MATLAB_functions/matplotlib/viridis.m b/analysis/MATLAB_functions/matplotlib/viridis.m new file mode 100644 index 0000000..09d5207 --- /dev/null +++ b/analysis/MATLAB_functions/matplotlib/viridis.m @@ -0,0 +1,64 @@ +function map = viridis(N) +% Perceptually uniform sequential colormap from MatPlotLib. +% +% Copyright (c) 2017-2019 Stephen Cobeldick +% +%%% Syntax: +% map = viridis +% map = viridis(N) +% +% Colormap designed by Eric Firing, Nathaniel J. Smith, and Stefan van der Walt. +% +% For MatPlotLib 2.0 improved colormaps were created in the perceptually +% uniform colorspace CAM02-UCS. The new colormaps are introduced here: +% +% The RGB data is from here: +% +% Note VIRIDIS replaces the awful JET as the MatPlotLib default colormap. +% +%% Examples %% +% +%%% Plot the scheme's RGB values: +% rgbplot(viridis(256)) +% +%%% New colors for the COLORMAP example: +% load spine +% image(X) +% colormap(viridis) +% +%%% New colors for the SURF example: +% [X,Y,Z] = peaks(30); +% surfc(X,Y,Z) +% colormap(viridis) +% axis([-3,3,-3,3,-10,5]) +% +%% Input and Output Arguments %% +% +%%% Inputs (*=default): +% N = NumericScalar, N>=0, an integer to define the colormap length. +% = *[], use the length of the current figure's colormap (see COLORMAP). +% +%%% Outputs: +% map = NumericMatrix, size Nx3, a colormap of RGB values between 0 and 1. +% +% See also CIVIDIS INFERNO MAGMA PLASMA TWILIGHT TAB10 SET LINES COLORMAP PARULA + +if nargin<1 || isempty(N) + N = size(get(gcf,'colormap'),1); +else + assert(isscalar(N)&&isreal(N),'First argument must be a real numeric scalar.') +end +% +raw = [0.267004,0.004874,0.329415; 0.268510,0.009605,0.335427; 0.269944,0.014625,0.341379; 0.271305,0.019942,0.347269; 0.272594,0.025563,0.353093; 0.273809,0.031497,0.358853; 0.274952,0.037752,0.364543; 0.276022,0.044167,0.370164; 0.277018,0.050344,0.375715; 0.277941,0.056324,0.381191; 0.278791,0.062145,0.386592; 0.279566,0.067836,0.391917; 0.280267,0.073417,0.397163; 0.280894,0.078907,0.402329; 0.281446,0.084320,0.407414; 0.281924,0.089666,0.412415; 0.282327,0.094955,0.417331; 0.282656,0.100196,0.422160; 0.282910,0.105393,0.426902; 0.283091,0.110553,0.431554; 0.283197,0.115680,0.436115; 0.283229,0.120777,0.440584; 0.283187,0.125848,0.444960; 0.283072,0.130895,0.449241; 0.282884,0.135920,0.453427; 0.282623,0.140926,0.457517; 0.282290,0.145912,0.461510; 0.281887,0.150881,0.465405; 0.281412,0.155834,0.469201; 0.280868,0.160771,0.472899; 0.280255,0.165693,0.476498; 0.279574,0.170599,0.479997; 0.278826,0.175490,0.483397; 0.278012,0.180367,0.486697; 0.277134,0.185228,0.489898; 0.276194,0.190074,0.493001; 0.275191,0.194905,0.496005; 0.274128,0.199721,0.498911; 0.273006,0.204520,0.501721; 0.271828,0.209303,0.504434; 0.270595,0.214069,0.507052; 0.269308,0.218818,0.509577; 0.267968,0.223549,0.512008; 0.266580,0.228262,0.514349; 0.265145,0.232956,0.516599; 0.263663,0.237631,0.518762; 0.262138,0.242286,0.520837; 0.260571,0.246922,0.522828; 0.258965,0.251537,0.524736; 0.257322,0.256130,0.526563; 0.255645,0.260703,0.528312; 0.253935,0.265254,0.529983; 0.252194,0.269783,0.531579; 0.250425,0.274290,0.533103; 0.248629,0.278775,0.534556; 0.246811,0.283237,0.535941; 0.244972,0.287675,0.537260; 0.243113,0.292092,0.538516; 0.241237,0.296485,0.539709; 0.239346,0.300855,0.540844; 0.237441,0.305202,0.541921; 0.235526,0.309527,0.542944; 0.233603,0.313828,0.543914; 0.231674,0.318106,0.544834; 0.229739,0.322361,0.545706; 0.227802,0.326594,0.546532; 0.225863,0.330805,0.547314; 0.223925,0.334994,0.548053; 0.221989,0.339161,0.548752; 0.220057,0.343307,0.549413; 0.218130,0.347432,0.550038; 0.216210,0.351535,0.550627; 0.214298,0.355619,0.551184; 0.212395,0.359683,0.551710; 0.210503,0.363727,0.552206; 0.208623,0.367752,0.552675; 0.206756,0.371758,0.553117; 0.204903,0.375746,0.553533; 0.203063,0.379716,0.553925; 0.201239,0.383670,0.554294; 0.199430,0.387607,0.554642; 0.197636,0.391528,0.554969; 0.195860,0.395433,0.555276; 0.194100,0.399323,0.555565; 0.192357,0.403199,0.555836; 0.190631,0.407061,0.556089; 0.188923,0.410910,0.556326; 0.187231,0.414746,0.556547; 0.185556,0.418570,0.556753; 0.183898,0.422383,0.556944; 0.182256,0.426184,0.557120; 0.180629,0.429975,0.557282; 0.179019,0.433756,0.557430; 0.177423,0.437527,0.557565; 0.175841,0.441290,0.557685; 0.174274,0.445044,0.557792; 0.172719,0.448791,0.557885; 0.171176,0.452530,0.557965; 0.169646,0.456262,0.558030; 0.168126,0.459988,0.558082; 0.166617,0.463708,0.558119; 0.165117,0.467423,0.558141; 0.163625,0.471133,0.558148; 0.162142,0.474838,0.558140; 0.160665,0.478540,0.558115; 0.159194,0.482237,0.558073; 0.157729,0.485932,0.558013; 0.156270,0.489624,0.557936; 0.154815,0.493313,0.557840; 0.153364,0.497000,0.557724; 0.151918,0.500685,0.557587; 0.150476,0.504369,0.557430; 0.149039,0.508051,0.557250; 0.147607,0.511733,0.557049; 0.146180,0.515413,0.556823; 0.144759,0.519093,0.556572; 0.143343,0.522773,0.556295; 0.141935,0.526453,0.555991; 0.140536,0.530132,0.555659; 0.139147,0.533812,0.555298; 0.137770,0.537492,0.554906; 0.136408,0.541173,0.554483; 0.135066,0.544853,0.554029; 0.133743,0.548535,0.553541; 0.132444,0.552216,0.553018; 0.131172,0.555899,0.552459; 0.129933,0.559582,0.551864; 0.128729,0.563265,0.551229; 0.127568,0.566949,0.550556; 0.126453,0.570633,0.549841; 0.125394,0.574318,0.549086; 0.124395,0.578002,0.548287; 0.123463,0.581687,0.547445; 0.122606,0.585371,0.546557; 0.121831,0.589055,0.545623; 0.121148,0.592739,0.544641; 0.120565,0.596422,0.543611; 0.120092,0.600104,0.542530; 0.119738,0.603785,0.541400; 0.119512,0.607464,0.540218; 0.119423,0.611141,0.538982; 0.119483,0.614817,0.537692; 0.119699,0.618490,0.536347; 0.120081,0.622161,0.534946; 0.120638,0.625828,0.533488; 0.121380,0.629492,0.531973; 0.122312,0.633153,0.530398; 0.123444,0.636809,0.528763; 0.124780,0.640461,0.527068; 0.126326,0.644107,0.525311; 0.128087,0.647749,0.523491; 0.130067,0.651384,0.521608; 0.132268,0.655014,0.519661; 0.134692,0.658636,0.517649; 0.137339,0.662252,0.515571; 0.140210,0.665859,0.513427; 0.143303,0.669459,0.511215; 0.146616,0.673050,0.508936; 0.150148,0.676631,0.506589; 0.153894,0.680203,0.504172; 0.157851,0.683765,0.501686; 0.162016,0.687316,0.499129; 0.166383,0.690856,0.496502; 0.170948,0.694384,0.493803; 0.175707,0.697900,0.491033; 0.180653,0.701402,0.488189; 0.185783,0.704891,0.485273; 0.191090,0.708366,0.482284; 0.196571,0.711827,0.479221; 0.202219,0.715272,0.476084; 0.208030,0.718701,0.472873; 0.214000,0.722114,0.469588; 0.220124,0.725509,0.466226; 0.226397,0.728888,0.462789; 0.232815,0.732247,0.459277; 0.239374,0.735588,0.455688; 0.246070,0.738910,0.452024; 0.252899,0.742211,0.448284; 0.259857,0.745492,0.444467; 0.266941,0.748751,0.440573; 0.274149,0.751988,0.436601; 0.281477,0.755203,0.432552; 0.288921,0.758394,0.428426; 0.296479,0.761561,0.424223; 0.304148,0.764704,0.419943; 0.311925,0.767822,0.415586; 0.319809,0.770914,0.411152; 0.327796,0.773980,0.406640; 0.335885,0.777018,0.402049; 0.344074,0.780029,0.397381; 0.352360,0.783011,0.392636; 0.360741,0.785964,0.387814; 0.369214,0.788888,0.382914; 0.377779,0.791781,0.377939; 0.386433,0.794644,0.372886; 0.395174,0.797475,0.367757; 0.404001,0.800275,0.362552; 0.412913,0.803041,0.357269; 0.421908,0.805774,0.351910; 0.430983,0.808473,0.346476; 0.440137,0.811138,0.340967; 0.449368,0.813768,0.335384; 0.458674,0.816363,0.329727; 0.468053,0.818921,0.323998; 0.477504,0.821444,0.318195; 0.487026,0.823929,0.312321; 0.496615,0.826376,0.306377; 0.506271,0.828786,0.300362; 0.515992,0.831158,0.294279; 0.525776,0.833491,0.288127; 0.535621,0.835785,0.281908; 0.545524,0.838039,0.275626; 0.555484,0.840254,0.269281; 0.565498,0.842430,0.262877; 0.575563,0.844566,0.256415; 0.585678,0.846661,0.249897; 0.595839,0.848717,0.243329; 0.606045,0.850733,0.236712; 0.616293,0.852709,0.230052; 0.626579,0.854645,0.223353; 0.636902,0.856542,0.216620; 0.647257,0.858400,0.209861; 0.657642,0.860219,0.203082; 0.668054,0.861999,0.196293; 0.678489,0.863742,0.189503; 0.688944,0.865448,0.182725; 0.699415,0.867117,0.175971; 0.709898,0.868751,0.169257; 0.720391,0.870350,0.162603; 0.730889,0.871916,0.156029; 0.741388,0.873449,0.149561; 0.751884,0.874951,0.143228; 0.762373,0.876424,0.137064; 0.772852,0.877868,0.131109; 0.783315,0.879285,0.125405; 0.793760,0.880678,0.120005; 0.804182,0.882046,0.114965; 0.814576,0.883393,0.110347; 0.824940,0.884720,0.106217; 0.835270,0.886029,0.102646; 0.845561,0.887322,0.099702; 0.855810,0.888601,0.097452; 0.866013,0.889868,0.095953; 0.876168,0.891125,0.095250; 0.886271,0.892374,0.095374; 0.896320,0.893616,0.096335; 0.906311,0.894855,0.098125; 0.916242,0.896091,0.100717; 0.926106,0.897330,0.104071; 0.935904,0.898570,0.108131; 0.945636,0.899815,0.112838; 0.955300,0.901065,0.118128; 0.964894,0.902323,0.123941; 0.974417,0.903590,0.130215; 0.983868,0.904867,0.136897; 0.993248,0.906157,0.143936]; +% +num = size(raw,1); +% With small extrapolation when N>num: +vec = linspace(0,num+1,N+2); +map = interp1(1:num,raw,vec(2:N+1),'linear','extrap'); +% Interpolation only for all values of N: +%map = interp1(1:num,raw,linspace(1,num,N),'spline') +% Range limits: +map = max(0,min(1,map)); +% +end +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%viridis \ No newline at end of file diff --git a/analysis/MATLAB_functions/morph_stack_to_ref.m b/analysis/MATLAB_functions/morph_stack_to_ref.m new file mode 100644 index 0000000..7e32459 --- /dev/null +++ b/analysis/MATLAB_functions/morph_stack_to_ref.m @@ -0,0 +1,20 @@ +function [] = morph_stack_to_ref(str_ref, str_morph, str_final, affine_x, ref_cropping_box, float_cropping_box, affine_x_init) +% cropping_box: 'x0,y0,z0,x1,y1,z1' in pixels +path_to_cmtk='C:\cmtk_files\bin\'; +if nargin == 4 + command_str_affine=[path_to_cmtk 'registration --echo --initxlate --dofs 6,9 --auto-multi-levels 4 --match-histograms --exploration 150 --accuracy 0.1 --coarsest 8 --omit-original-data -o' ' ' affine_x ' ' str_ref ' ' str_morph]; +elseif nargin == 5 + command_str_affine=[path_to_cmtk 'registration --echo --crop-index-ref ' ref_cropping_box ' --initxlate --dofs 6,9 --auto-multi-levels 4 --match-histograms --exploration 150 --accuracy 0.1 --coarsest 8 --omit-original-data -o' ' ' affine_x ' ' str_ref ' ' str_morph]; +elseif nargin == 6 + command_str_affine=[path_to_cmtk 'registration --echo --crop-index-ref ' ref_cropping_box ' --crop-index-flt ' float_cropping_box ' --initxlate --dofs 6,9 --auto-multi-levels 4 --match-histograms --exploration 150 --accuracy 0.1 --coarsest 8 --omit-original-data -o' ' ' affine_x ' ' str_ref ' ' str_morph]; +else + command_str_affine=[path_to_cmtk 'registration --echo --crop-index-ref ' ref_cropping_box ' --crop-index-flt ' float_cropping_box ' --initial ' affine_x_init ' --initxlate --dofs 6,9 --auto-multi-levels 4 --match-histograms --exploration 150 --accuracy 0.1 --coarsest 8 --omit-original-data -o' ' ' affine_x ' ' str_ref ' ' str_morph]; + if isempty(ref_cropping_box) && isempty(float_cropping_box) + command_str_affine=[path_to_cmtk 'registration --echo --initial ' affine_x_init ' --initxlate --dofs 6,9 --auto-multi-levels 4 --match-histograms --exploration 150 --accuracy 0.1 --coarsest 8 --omit-original-data -o' ' ' affine_x ' ' str_ref ' ' str_morph]; + else + error('fix it!'); + end +end +command_str_reform=[path_to_cmtk 'reformatx --echo -o' ' ' str_final ' ' '--floating' ' ' str_morph ' ' str_ref ' ' affine_x]; +dos(command_str_affine,'-echo'); +dos(command_str_reform,'-echo'); \ No newline at end of file diff --git a/analysis/MATLAB_functions/nrrdread.m b/analysis/MATLAB_functions/nrrdread.m new file mode 100644 index 0000000..2011127 --- /dev/null +++ b/analysis/MATLAB_functions/nrrdread.m @@ -0,0 +1,188 @@ +function [X, meta] = nrrdread(filename) +%NRRDREAD Import NRRD imagery and metadata. +% [X, META] = NRRDREAD(FILENAME) reads the image volume and associated +% metadata from the NRRD-format file specified by FILENAME. +% +% Current limitations/caveats: +% * "Block" datatype is not supported. +% * Only tested with "gzip" and "raw" file encodings. +% * Very limited testing on actual files. +% * I only spent a couple minutes reading the NRRD spec. +% +% See the format specification online: +% http://teem.sourceforge.net/nrrd/format.html + +% Copyright 2012 The MathWorks, Inc. + + +% Open file. +fid = fopen(filename, 'rb'); +assert(fid > 0, 'Could not open file.'); +cleaner = onCleanup(@() fclose(fid)); + +% Magic line. +theLine = fgetl(fid); +assert(numel(theLine) >= 4, 'Bad signature in file.') +assert(isequal(theLine(1:4), 'NRRD'), 'Bad signature in file.') + +% The general format of a NRRD file (with attached header) is: +% +% NRRD000X +% : +% : +% # +% ... +% : +% := +% := +% := +% # +% +% ... + +meta = struct([]); + +% Parse the file a line at a time. +while (true) + + theLine = fgetl(fid); + + if (isempty(theLine) || feof(fid)) + % End of the header. + break; + end + + if (isequal(theLine(1), '#')) + % Comment line. + continue; + end + + % "fieldname:= value" or "fieldname: value" or "fieldname:value" + parsedLine = regexp(theLine, ':=?\s*', 'split','once'); + + assert(numel(parsedLine) == 2, 'Parsing error') + + field = lower(parsedLine{1}); + value = parsedLine{2}; + + field(isspace(field)) = ''; + meta(1).(field) = value; + +end + +datatype = getDatatype(meta.type); + +% Get the size of the data. +% DM wrote this: +meta.endian='little'; +% end of DM +assert(isfield(meta, 'sizes') && ... + isfield(meta, 'dimension') && ... + isfield(meta, 'encoding') && ... + isfield(meta, 'endian'), ... + 'Missing required metadata fields.') + +dims = sscanf(meta.sizes, '%d'); +ndims = sscanf(meta.dimension, '%d'); +assert(numel(dims) == ndims); + +data = readData(fid, meta, datatype); +data = adjustEndian(data, meta); + +% Reshape and get into MATLAB's order. +X = reshape(data, dims'); +X = permute(X, [2 1 3]); + + + +function datatype = getDatatype(metaType) + +% Determine the datatype +switch (metaType) + case {'signed char', 'int8', 'int8_t'} + datatype = 'int8'; + + case {'uchar', 'unsigned char', 'uint8', 'uint8_t'} + datatype = 'uint8'; + + case {'short', 'short int', 'signed short', 'signed short int', ... + 'int16', 'int16_t'} + datatype = 'int16'; + + case {'ushort', 'unsigned short', 'unsigned short int', 'uint16', ... + 'uint16_t'} + datatype = 'uint16'; + + case {'int', 'signed int', 'int32', 'int32_t'} + datatype = 'int32'; + + case {'uint', 'unsigned int', 'uint32', 'uint32_t'} + datatype = 'uint32'; + + case {'longlong', 'long long', 'long long int', 'signed long long', ... + 'signed long long int', 'int64', 'int64_t'} + datatype = 'int64'; + + case {'ulonglong', 'unsigned long long', 'unsigned long long int', ... + 'uint64', 'uint64_t'} + datatype = 'uint64'; + + case {'float'} + datatype = 'single'; + + case {'double'} + datatype = 'double'; + + otherwise + assert(false, 'Unknown datatype') +end + + + +function data = readData(fidIn, meta, datatype) + +switch (meta.encoding) + case {'raw'} + + data = fread(fidIn, inf, [datatype '=>' datatype]); + + case {'gzip', 'gz'} + + tmpBase = tempname(); + tmpFile = [tmpBase '.gz']; + fidTmp = fopen(tmpFile, 'wb'); + assert(fidTmp > 3, 'Could not open temporary file for GZIP decompression') + + tmp = fread(fidIn, inf, 'uint8=>uint8'); + fwrite(fidTmp, tmp, 'uint8'); + fclose(fidTmp); + + gunzip(tmpFile) + + fidTmp = fopen(tmpBase, 'rb'); + cleaner = onCleanup(@() fclose(fidTmp)); + + meta.encoding = 'raw'; + data = readData(fidTmp, meta, datatype); + + case {'txt', 'text', 'ascii'} + + data = fscanf(fidIn, '%f'); + data = cast(data, datatype); + + otherwise + assert(false, 'Unsupported encoding') +end + + + +function data = adjustEndian(data, meta) + +[~,~,endian] = computer(); + +needToSwap = (isequal(endian, 'B') && isequal(lower(meta.endian), 'little')) || ... + (isequal(endian, 'L') && isequal(lower(meta.endian), 'big')); + +if (needToSwap) + data = swapbytes(data); +end \ No newline at end of file diff --git a/analysis/MATLAB_functions/plotSpread/distinguishable_colors.m b/analysis/MATLAB_functions/plotSpread/distinguishable_colors.m new file mode 100644 index 0000000..4049d66 --- /dev/null +++ b/analysis/MATLAB_functions/plotSpread/distinguishable_colors.m @@ -0,0 +1,152 @@ +function colors = distinguishable_colors(n_colors,bg,func) +% DISTINGUISHABLE_COLORS: pick colors that are maximally perceptually distinct +% +% When plotting a set of lines, you may want to distinguish them by color. +% By default, Matlab chooses a small set of colors and cycles among them, +% and so if you have more than a few lines there will be confusion about +% which line is which. To fix this problem, one would want to be able to +% pick a much larger set of distinct colors, where the number of colors +% equals or exceeds the number of lines you want to plot. Because our +% ability to distinguish among colors has limits, one should choose these +% colors to be "maximally perceptually distinguishable." +% +% This function generates a set of colors which are distinguishable +% by reference to the "Lab" color space, which more closely matches +% human color perception than RGB. Given an initial large list of possible +% colors, it iteratively chooses the entry in the list that is farthest (in +% Lab space) from all previously-chosen entries. While this "greedy" +% algorithm does not yield a global maximum, it is simple and efficient. +% Moreover, the sequence of colors is consistent no matter how many you +% request, which facilitates the users' ability to learn the color order +% and avoids major changes in the appearance of plots when adding or +% removing lines. +% +% Syntax: +% colors = distinguishable_colors(n_colors) +% Specify the number of colors you want as a scalar, n_colors. This will +% generate an n_colors-by-3 matrix, each row representing an RGB +% color triple. If you don't precisely know how many you will need in +% advance, there is no harm (other than execution time) in specifying +% slightly more than you think you will need. +% +% colors = distinguishable_colors(n_colors,bg) +% This syntax allows you to specify the background color, to make sure that +% your colors are also distinguishable from the background. Default value +% is white. bg may be specified as an RGB triple or as one of the standard +% "ColorSpec" strings. You can even specify multiple colors: +% bg = {'w','k'} +% or +% bg = [1 1 1; 0 0 0] +% will only produce colors that are distinguishable from both white and +% black. +% +% colors = distinguishable_colors(n_colors,bg,rgb2labfunc) +% By default, distinguishable_colors uses the image processing toolbox's +% color conversion functions makecform and applycform. Alternatively, you +% can supply your own color conversion function. +% +% Example: +% c = distinguishable_colors(25); +% figure +% image(reshape(c,[1 size(c)])) +% +% Example using the file exchange's 'colorspace': +% func = @(x) colorspace('RGB->Lab',x); +% c = distinguishable_colors(25,'w',func); + +% Copyright 2010-2011 by Timothy E. Holy + + % Parse the inputs + if (nargin < 2) + bg = [1 1 1]; % default white background + else + if iscell(bg) + % User specified a list of colors as a cell aray + bgc = bg; + for i = 1:length(bgc) + bgc{i} = parsecolor(bgc{i}); + end + bg = cat(1,bgc{:}); + else + % User specified a numeric array of colors (n-by-3) + bg = parsecolor(bg); + end + end + + % Generate a sizable number of RGB triples. This represents our space of + % possible choices. By starting in RGB space, we ensure that all of the + % colors can be generated by the monitor. + n_grid = 30; % number of grid divisions along each axis in RGB space + x = linspace(0,1,n_grid); + [R,G,B] = ndgrid(x,x,x); + rgb = [R(:) G(:) B(:)]; + if (n_colors > size(rgb,1)/3) + error('You can''t readily distinguish that many colors'); + end + + % Convert to Lab color space, which more closely represents human + % perception + if (nargin > 2) + lab = func(rgb); + bglab = func(bg); + else + C = makecform('srgb2lab'); + lab = applycform(rgb,C); + bglab = applycform(bg,C); + end + + % If the user specified multiple background colors, compute distances + % from the candidate colors to the background colors + mindist2 = inf(size(rgb,1),1); + for i = 1:size(bglab,1)-1 + dX = bsxfun(@minus,lab,bglab(i,:)); % displacement all colors from bg + dist2 = sum(dX.^2,2); % square distance + mindist2 = min(dist2,mindist2); % dist2 to closest previously-chosen color + end + + % Iteratively pick the color that maximizes the distance to the nearest + % already-picked color + colors = zeros(n_colors,3); + lastlab = bglab(end,:); % initialize by making the "previous" color equal to background + for i = 1:n_colors + dX = bsxfun(@minus,lab,lastlab); % displacement of last from all colors on list + dist2 = sum(dX.^2,2); % square distance + mindist2 = min(dist2,mindist2); % dist2 to closest previously-chosen color + [dummy,index] = max(mindist2); % find the entry farthest from all previously-chosen colors + colors(i,:) = rgb(index,:); % save for output + lastlab = lab(index,:); % prepare for next iteration + end +end + +function c = parsecolor(s) + if ischar(s) + c = colorstr2rgb(s); + elseif isnumeric(s) && size(s,2) == 3 + c = s; + else + error('MATLAB:InvalidColorSpec','Color specification cannot be parsed.'); + end +end + +function c = colorstr2rgb(c) + % Convert a color string to an RGB value. + % This is cribbed from Matlab's whitebg function. + % Why don't they make this a stand-alone function? + rgbspec = [1 0 0;0 1 0;0 0 1;1 1 1;0 1 1;1 0 1;1 1 0;0 0 0]; + cspec = 'rgbwcmyk'; + k = find(cspec==c(1)); + if isempty(k) + error('MATLAB:InvalidColorString','Unknown color string.'); + end + if k~=3 || length(c)==1, + c = rgbspec(k,:); + elseif length(c)>2, + if strcmpi(c(1:3),'bla') + c = [0 0 0]; + elseif strcmpi(c(1:3),'blu') + c = [0 0 1]; + else + error('MATLAB:UnknownColorString', 'Unknown color string.'); + end + end +end diff --git a/analysis/MATLAB_functions/plotSpread/isEven.m b/analysis/MATLAB_functions/plotSpread/isEven.m new file mode 100644 index 0000000..5571842 --- /dev/null +++ b/analysis/MATLAB_functions/plotSpread/isEven.m @@ -0,0 +1,25 @@ +function out = isEven(in) +%ISEVEN checks whether a number is even +% +% SYNOPSIS out = isEven(in) +% +% INPUT in : input (array) of numbers to be tested. +% OUTPUT out: array of size(in) with +% 1 for even integers and zero +% 0 for odd integers +% NaN for non-integers +% out is a logical array as long as the input is all integers. +% +% c: jonas 5/05 +% Last modified 11/24/2009 - Jonas Dorn +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +out = mod(in+1, 2); +% Set NaN for non-integer data, because they are neither odd or even +out((out ~= 0) & (out ~= 1)) = NaN; + +% since doubles cannot be used for logical indexing, we should convert to +% logicals if possible. +if all(isfinite(out(:))) + out = logical(out); +end \ No newline at end of file diff --git a/analysis/MATLAB_functions/plotSpread/myErrorbar.m b/analysis/MATLAB_functions/plotSpread/myErrorbar.m new file mode 100644 index 0000000..b896dda --- /dev/null +++ b/analysis/MATLAB_functions/plotSpread/myErrorbar.m @@ -0,0 +1,264 @@ +function hh = myErrorbar(varargin) +%MYERRORBAR Adds errorbars to existing plot (unlike errorbar.m, which creates a new plot, and allows only bars for y values) +% MYERRORBAR(X,Y,L,U) adds error bars to the graph of vector X vs. vector Y with +% error bars specified by the vectors L and U. L and U contain the +% lower and upper error ranges for each point in Y. Each error bar +% is L(i) + U(i) long and is drawn a distance of U(i) above and L(i) +% below the points in (X,Y). If X,Y,L and U are matrices then each column +% produces a separate line. +% If L,U are the same size as X, Y, only error bars for Y will be plotted. +% If L,U are twice the size of X,Y (or have twice the number of columns for +% matrices), the first half of L, U specifies error bar lengths for X and the +% second half specifies error bars for Y +% +% MYERRORBAR(X,Y,E) or MYERRORBAR(Y,E) plots error bars [Y-E Y+E]. +% +% MYERRORBAR(AX,...), where AX is an axis handle, plots errorbars into +% axes AX +% +% H = MYERRORBAR(...) returns a vector of line handles. +% +% The tag of the errorbar-lines is: errorBar +% +% For example, +% x = 1:10; +% y = sin(x); +% e = std(y)*ones(size(x)); +% myErrorbar(x,y,e) +% draws symmetric error bars of unit standard deviation for y values. +% myErrorbar(x,y,[e,e]) +% draws symmetric error bars of unit standard deviation for x and y +% values. +% +% Based on the matlab-function errorbar as revised by Claude Berney +% c: jonas, 06-03 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%================== +% check input +%================== + +if nargin < 2 + error('not enough input arguments!') +end + +% check if the first input argument is a handle +if length(varargin{1}) == 1 && ishandle(varargin{1}) && strcmpi(get(varargin{1},'Type'),'axes') + axesH = varargin{1}; + % remove axis handle + varargin(1) = []; +else + axesH = gca; +end + +% there could be +% y,e +% x,y,e +% x,y,l,u + +switch length(varargin) + case 2 + % y, e + y = varargin{1}; + y = y(:); + lengthY = length(y); + x = [1:lengthY]'; + + e = varargin{2}; + % check for 2 dimension errorbars + e = e(:); + if length(e) == 2*lengthY + e = reshape(e,lengthY,2); + end + [l,u] = deal(e); + + case 3 + % x,y,e + x = varargin{1}; + x = x(:); + y = varargin{2}; + y = y(:); + lengthY = length(y); + + e = varargin{3}; + % check for 2 dimension errorbars + e = e(:); + if length(e) == 2*lengthY + e = reshape(e,lengthY,2); + end + [l,u] = deal(e); + + case 4 + % x,y,l,u + % x,y,e + x = varargin{1}; + x = x(:); + y = varargin{2}; + y = y(:); + lengthY = length(y); + + l = varargin{3}; + % check for 2 dimension errorbars + l = l(:); + if length(l) == 2*lengthY + l = reshape(l,lengthY,2); + end + u = varargin{4}; + % check for 2 dimension errorbars + u = u(:); + if length(u) == 2*lengthY + u = reshape(u,lengthY,2); + end + + if ~all(size(u)==size(l)) + error('l, u have to be the same size!') + end + +end % switch number of inputs + + +u = abs(u); +l = abs(l); + +if ischar(x) || ischar(y) || ischar(u) || ischar(l) + error('Arguments must be numeric.') +end + +if ~isequal(size(x),size(y)) + error('The sizes of X and Y must be the same.'); +end + +if isequal([1 2].*size(x),size(l)) && isequal([1 2].*size(x),size(u)) + xyBars = 1; +elseif isequal(size(x),size(l)) && isequal(size(x),size(u)) + xyBars = 0; +else + error('The sizes of L and U must be equal to or twice the size of X, Y') +end + +%======================= + + +% Plot graph and bars +hold_state = ishold; +hold on; + + +%find color of current plot +dataH = get(axesH,'Children'); +myLineH = dataH(1); +% support also bar plots +if strcmp(get(myLineH,'Type'),'hggroup') + latestColor = get(myLineH,'EdgeColor'); %new children are added on top! +else + latestColor = get(myLineH,'Color'); %new children are added on top! +end + +tee=0; +if ~strcmp('log',get(axesH,'XScale')) + tee = (max(x(:))-min(x(:)))/100; % make tee .02 x-distance for error bars + tee = min(tee,0.3*nanmedian(diff(unique(x(:))))); % or at most 0.3*deltaX + xl = x - tee; + xr = x + tee; +end +if strcmp('log',get(axesH,'XScale')) + tee = (max(log(x(:)))-min(log(x(:))))/100; % make tee .02 x-distance for error bars + tee = min(tee,0.3*nanmedian(diff(unique(log(x(:)))))); % or at most 0.3*deltaX + + xl = x *exp(tee); + xr = x *exp(-tee); +end + +if xyBars + if ~strcmp('log',get(axesH,'YScale')) + tee = (max(y(:))-min(y(:)))/100; % make tee .02 y-distance for error bars + tee = min(tee,0.3*nanmedian(diff(unique(y(:))))); % or at most 0.3*deltaY + + yl = y - tee; + yr = y + tee; + end + if strcmp('log',get(axesH,'YScale')) + tee = (max(log(y(:)))-min(log(y(:))))/100; % make tee .02 y-distance for error bars + tee = min(tee,0.3*nanmedian(diff(unique(log(y(:)))))); % or at most 0.3*deltaX + + yl = y *exp(tee); + yr = y *exp(-tee); + end +end + +%specify coordinates to plot error bars +if xyBars + xtop = x + u(:,1:size(x,2)); + xbot = x - l(:,1:size(x,2)); + ytop = y + u(:,size(x,2)+1:end); + ybot = y - l(:,size(x,2)+1:end); +else + ytop = y + u; + ybot = y - l; +end +n = size(y,2); + +% build up nan-separated vector for bars +xb = zeros(lengthY*9,n); +xb(1:9:end,:) = x; +xb(2:9:end,:) = x; +xb(3:9:end,:) = NaN; +xb(4:9:end,:) = xl; +xb(5:9:end,:) = xr; +xb(6:9:end,:) = NaN; +xb(7:9:end,:) = xl; +xb(8:9:end,:) = xr; +xb(9:9:end,:) = NaN; + +yb = zeros(lengthY*9,n); +yb(1:9:end,:) = ytop; +yb(2:9:end,:) = ybot; +yb(3:9:end,:) = NaN; +yb(4:9:end,:) = ytop; +yb(5:9:end,:) = ytop; +yb(6:9:end,:) = NaN; +yb(7:9:end,:) = ybot; +yb(8:9:end,:) = ybot; +yb(9:9:end,:) = NaN; + +h = [line(xb,yb,'parent',axesH,'Color',latestColor)]; + +if xyBars + + xb(1:9:end,:) = xtop; + xb(2:9:end,:) = xbot; + xb(3:9:end,:) = NaN; + xb(4:9:end,:) = xtop; + xb(5:9:end,:) = xtop; + xb(6:9:end,:) = NaN; + xb(7:9:end,:) = xbot; + xb(8:9:end,:) = xbot; + xb(9:9:end,:) = NaN; + + yb(1:9:end,:) = y; + yb(2:9:end,:) = y; + yb(3:9:end,:) = NaN; + yb(4:9:end,:) = yl; + yb(5:9:end,:) = yr; + yb(6:9:end,:) = NaN; + yb(7:9:end,:) = yl; + yb(8:9:end,:) = yr; + yb(9:9:end,:) = NaN; + + h = [h;line(xb,yb,'parent',axesH,'Color',latestColor)]; + +end + +%set the tag of all errorBar-objects to 'errorBar' +set(h,'Tag','errorBar'); + +% make sure errorbar doesn't produce a legend entry +for lineH = h' + set(get(get(lineH,'Annotation'),'LegendInformation'),... + 'IconDisplayStyle','off'); +end + + +if ~hold_state, hold off; end + +if nargout>0, hh = h; end diff --git a/analysis/MATLAB_functions/plotSpread/plotSpread.m b/analysis/MATLAB_functions/plotSpread/plotSpread.m new file mode 100644 index 0000000..53696fe --- /dev/null +++ b/analysis/MATLAB_functions/plotSpread/plotSpread.m @@ -0,0 +1,632 @@ +function handles = plotSpread(varargin) +%PLOTSPREAD plots distributions of points by spreading them around the y-axis +% +% SYNOPSIS: handles = plotSpread(data, propertyName, propertyValue, ...) +% handles = plotSpread(ah, ... +% deprecated: +% handles = plotSpread(data,binWidth,spreadFcn,xNames,showMM,xValues) +% +% INPUT data: cell array of distributions or nDatapoints-by-mDistributions +% array, or array with data that is indexed by either +% distributionIdx or categoryIdx, or both. +% distributionIdx: grouping variable that determines to which +% distribution a data point belongs. Grouping is +% resolved by calling grp2idx, and unless xNames have +% been supplied, group names determine the x-labels. +% If the grouping variable is numeric, group labels also +% determine x-values, unless the parameter xValues has +% been specified. +% distributionColors : color identifier (string, cell array of +% strings), or colormap, with a single color, or one color per +% distribution (or per entry in distributionIdx). Colors the +% distributions. Default: 'b' +% distributionMarkers : string, or cell array of strings, with either +% a single marker or one marker per distribution (or per entry in +% distributionIdx). See linespec for admissible markers. +% Default: '.' +% categoryIdx: grouping variable that determines group membership for data +% points across distributions. Grouping is resolved by calling +% grp2idx. +% categoryColors : color identifier (cell array of +% strings), or colormap, with one color per category. +% Colors the categories, and will override distributionColors. +% Default is generated using distinguishable_colors by Timothy E. +% Holy. +% categoryMarkers : cell array of strings, with one marker per +% category. See linespec for admissible markers. Will override +% distributionMarkers. Default: '' +% categoryLabels : cell array of strings with one label per category +% (categories sorted in ascending order). Default: unique +% category indices +% binWidth : width of bins (along y) that control which data +% points are considered close enough to be spread. Default: 0.1 +% spreadFcn : cell array of length 2 with {name,param} +% if name is 'lin', the spread goes linear with the number of +% points inside the bin, until it reaches the maximum of 0.9 at +% n==param. +% if name is 'xp', the spread increases as 1-exp(log(0.9)*x). +% param is empty +% Default {'xp',[]} +% spreadWidth : width, along the x-axis (y-axis if flipped) that can +% at most be covered by the points. Default: +% median(diff(sort(xValues))); 1 if no xValues have been supplied +% showMM : if 1, mean and median are shown as red crosses and +% green squares, respectively. Default: 0 +% 2: only mean +% 3: only median +% 4: mean +/- standard error of the mean (no median) +% 5: mean +/- standard deviation (no median) +% xNames : cell array of length nDistributions containing x-tick names +% (instead of the default '1,2,3') +% xValues : list of x-values at which the data should +% be plotted. Default: 1,2,3... +% xMode : if 'auto', x-ticks are spaced automatically. If 'manual', +% there is a tick for each distribution. If xNames is +% provided as input, xMode is forced to 'manual'. Default: +% 'manual'. +% xyOri : orientation of axes. Either 'normal' (=default), or +% 'flipped'. If 'flipped', the x-and y-axes are switched, so +% that violin plots are horizontal. Consequently, +% axes-specific properties, such as 'yLabel' are applied to +% the other axis. +% yLabel : string with label for y-axis. Default : '' +% ah : handles of axes into which to plot +% +% OUTPUT handles: 3-by-1 cell array with handles to distributions, +% mean/median etc, and the axes, respectively +% +% REMARKS: plotSpread is useful for distributions with a small number of +% data points. For larger amounts of data, distributionPlot is +% more suited. +% +% EXAMPLES: data = {randn(25,1),randn(100,1),randn(300,1)}; +% figure,plotSpread(data,[],[],{'25 pts','100 pts','300 pts'}) +% +% data = [randn(50,1);randn(50,1)+3.5]*[1 1]; +% catIdx = [ones(50,1);zeros(50,1);randi([0,1],[100,1])]; +% figure +% plotSpread(data,'categoryIdx',catIdx,... +% 'categoryMarkers',{'o','+'},'categoryColors',{'r','b'}) +% +% END +% +% created with MATLAB ver.: 7.9.0.3470 (R2009b) on Mac OS X Version: 10.5.7 Build: 9J61 +% +% created by: jonas +% DATE: 11-Jul-2009 +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +def.binWidth = 0.1; +def.spreadFcn = {'xp',[]}; +def.xNames = []; +def.showMM = false; +def.xValues = []; +def.distributionIdx = []; +def.distributionColors = 'b'; +def.distributionMarkers = '.'; +def.xMode = 'manual'; +def.xyOri = 'normal'; +def.categoryIdx = []; +def.categoryColors = []; +def.categoryMarkers = ''; +def.categoryLabels = ''; +def.yLabel = ''; +def.spreadWidth = []; + +% in development +def.individualLabels = false; % one category label across all distributions +% this should be smartly determined rather +% than hard-coded + +%% CHECK INPUT + +% check for axes handle +if ~iscell(varargin{1}) && length(varargin{1}) == 1 && ... + ishandle(varargin{1}) && strcmp(get(varargin{1},'Type'),'axes') + ah = varargin{1}; + data = varargin{2}; + varargin(1:2) = []; + newAx = false; +else + ah = gca; + data = varargin{1}; + varargin(1) = []; + % if the axes have children, it's not new (important for adjusting + % limits below) + newAx = isempty(get(ah,'Children')); +end + +% optional arguments +parserObj = inputParser; +parserObj.FunctionName = 'plotSpread'; +distributionIdx = [];distributionLabels = ''; +if ~isempty(varargin) && ~ischar(varargin{1}) && ~isstruct(varargin{1}) + % old syntax + parserObj.addOptional('binWidth',def.binWidth); + parserObj.addOptional('spreadFcn',def.spreadFcn); + parserObj.addOptional('xNames',def.xNames); + parserObj.addOptional('showMM',def.showMM); + parserObj.addOptional('xValues',def.xValues); + + parserObj.parse(varargin{:}); + opt = parserObj.Results; + + opt.distributionIdx = []; + opt.distributionColors = def.distributionColors; + opt.distributionMarkers = def.distributionMarkers; + opt.xMode = def.xMode; + opt.xyOri = def.xyOri; + opt.categoryIdx = []; + opt.categoryColors = def.distributionColors; + opt.categoryMarkers = def.distributionMarkers; + opt.yLabel = ''; + opt.spreadWidth = def.spreadWidth; + opt.individualLabels = false; + + for fn = fieldnames(def)' + if ~isfield(opt,fn{1}) + % Manually adding the new defaults means a lot fewer bugs + error('please add option %s to old syntax',fn{1}); + end + if isempty(opt.(fn{1})) + opt.(fn{1}) = def.(fn{1}); + end + end + +else + % new syntax + defNames = fieldnames(def); + for dn = defNames(:)' + parserObj.addParamValue(dn{1},def.(dn{1})); + end + + + parserObj.parse(varargin{:}); + opt = parserObj.Results; +end + +% We want data to be a vector, so that indexing with both groupIdx and +% distributionIdx becomes straightforward, and so that we can conveniently +% eliminate NaNs that otherwise could mess up grouping. +% Consequently, if data is a cell array, we convert it, and build a +% corresponding distributionIdx (allowing a user-supplied distributionIdx +% to override, though), and then we go and take care of groupIdx. Once all +% three indices have been built, NaN can be removed. + +if iscell(data) + % make sure data is all n-by-1 + data = cellfun(@(x)x(:),data,'UniformOutput',false); + nData = length(data); + nn = cellfun(@numel,data); + % make vector + data = cat(1,data{:}); + distributionIdx = repeatEntries((1:nData)',nn); +else + % distributions in columns + nData = size(data,2); + distributionIdx = repeatEntries((1:nData)',size(data,1)); + data = data(:); +end + + + +% distribution groups +if ~isempty(opt.distributionIdx) + [distributionIdx,distributionLabels,vals] = grp2idx(opt.distributionIdx); + % convert data to cell array + nData = length(distributionLabels); + % if not otherwise provided, use group labels for xnames + if isempty(opt.xNames) + opt.xNames = distributionLabels; + if ~iscell(opt.xNames) + opt.xNames = num2cell(opt.xNames); + end + end + if isnumeric(vals) && isempty(opt.xValues) + opt.xValues = vals; + end +end + +if ~isempty(opt.xNames) + opt.xMode = 'manual'; +end + + +% distribution colors&markers +if ischar(opt.distributionColors) + opt.distributionColors = {opt.distributionColors}; +end +if iscell(opt.distributionColors) + if length(opt.distributionColors) == 1 + % expand + opt.distributionColors = repmat(opt.distributionColors,nData,1); + elseif length(opt.distributionColors) ~= nData + error('please submit one color per distribution (%i dist, %i colors)',nData,length(opt.distributionColors)); + end + +else + if size(opt.distributionColors,2) ~= 3 + error('please specify colormap with three columns') + end + if size(opt.distributionColors,1) == 1 + opt.distributionColors = repmat(opt.distributionColors,nData,1); + elseif size(opt.distributionColors,1) ~= nData + error('please submit one color per distribution (%i dist, %i colors)',nData,size(opt.distributionColors,1)); + end + + % create a cell array + opt.distributionColors = mat2cell(opt.distributionColors,ones(nData,1),3); +end + +if ischar(opt.distributionMarkers) + opt.distributionMarkers = {opt.distributionMarkers}; +end +if length(opt.distributionMarkers) == 1 + % expand + opt.distributionMarkers = repmat(opt.distributionMarkers,nData,1); +elseif length(opt.distributionMarkers) ~= nData + error('please submit one color per distribution (%i dist, %i colors)',nData,length(opt.distributionMarkers)); +end + + +stdWidth = 1; +if isempty(opt.xValues) + opt.xValues = 1:nData; +end + + +if isempty(opt.spreadWidth) + % scale width + tmp = median(diff(sort(opt.xValues))); + if ~isnan(tmp) + stdWidth = tmp; + end +else + stdWidth = opt.spreadWidth; +end + +if ~ischar(opt.xyOri) || ~any(ismember(opt.xyOri,{'normal','flipped'})) + error('option xyOri must be either ''normal'' or ''flipped'' (is ''%s'')',opt.xyOri); +end + + +% check for categoryIdx/colors/markers +% If there are categories, check colors/markers individually first, +% then check whether any of them at all have been supplied, and +% if not, override distributionColors with default categoryColors + +if isempty(opt.categoryIdx) + categoryIdx = ones(size(distributionIdx)); + nCategories = 1; + categoryLabels = ''; +else + [categoryIdx,categoryLabels] = grp2idx(opt.categoryIdx(:)); + nCategories = max(categoryIdx); +end +if ~isempty(opt.categoryLabels) + categoryLabels = opt.categoryLabels; +elseif ~iscell(categoryLabels) + categoryLabels = num2cell(categoryLabels); +end + +% plotColors, plotMarkers, plotLabels: nDist-by-nCat arrays +plotColors = repmat(opt.distributionColors(:),1,nCategories); +plotMarkers= repmat(opt.distributionMarkers(:),1,nCategories); + +if isempty(distributionLabels) + distributionLabels = opt.xNames; + if isempty(distributionLabels) + distributionLabels = cellstr(num2str(opt.xValues(:))); + end +end + +if nCategories == 1 + plotLabels = distributionLabels(:); +else + plotLabels = cell(nData,nCategories); + for iData = 1:nData + for iCategory = 1:nCategories + if opt.individualLabels + plotLabels{iData,iCategory} = ... + sprintf('%s-%s',num2str(distributionLabels{iData}),... + num2str(categoryLabels{iCategory})); + else + plotLabels{iData,iCategory} = ... + sprintf('%s',... + num2str(categoryLabels{iCategory})); + end + end + end + +end + + + + +categoryIsLabeled = false; +if nCategories > 1 + % if not using defaults for categoryColors: apply them + if ~any(strcmp('categoryColors',parserObj.UsingDefaults)) + if iscell(opt.categoryColors) + if length(opt.categoryColors) ~= nCategories + error('please supply one category color per category') + end + plotColors = repmat(opt.categoryColors(:)',nData,1); + categoryIsLabeled = true; + else + if all(size(opt.categoryColors) ~= [nCategories,3]) + error('please supply a #-of-categories-by-3 color array') + end + plotColors = repmat( mat2cell(opt.categoryColors,ones(nCategories,1),3)', nData,1); + categoryIsLabeled = true; + end + end + + if ~any(strcmp('categoryMarkers',parserObj.UsingDefaults)) + if length(opt.categoryMarkers) ~= nCategories + error('please supply one category marker per category') + end + if ~iscell(opt.categoryMarkers) + error('please supply a list of markers as cell array') + end + plotMarkers = repmat(opt.categoryMarkers(:)',nData,1); + categoryIsLabeled = true; + end + + if ~categoryIsLabeled + % use distinguishable_colors to mark categories + + plotColors = repmat( mat2cell(... + distinguishable_colors(nCategories),... + ones(nCategories,1),3)', nData,1); + + end + +end + + +% remove NaNs from data +badData = ~isfinite(data) | ~isfinite(distributionIdx) | ~isfinite(categoryIdx); +data(badData) = []; +distributionIdx(badData) = []; +categoryIdx(badData) = []; + + + + +%% TRANSFORM DATA +% Here, I try to estimate what the aspect ratio of the data is going to be +fh = figure('Visible','off'); +if ~isempty(data) + minMax = [min(data);max(data)]; +else + minMax = [0 1]; +end +switch opt.xyOri + case 'normal' + plot([0.5;nData+0.5],minMax,'o'); + case 'flipped' + plot(minMax,[0.5;nData+0.5],'o'); + +end +aspectRatio = get(gca,'DataAspectRatio'); +close(fh); + +tFact = aspectRatio(2)/aspectRatio(1); +if strcmp(opt.xyOri,'flipped') + tFact = 1/tFact; +end + +%% SPREAD POINTS +% assign either nData, or xValues number of values, in case we're working +% with group-indices +[m,md,sem,sd] = deal(nan(max(nData,length(opt.xValues)),1)); +% make sure xValues are not something weird +opt.xValues = double(opt.xValues); + + +% augment data to make n-by-2 +data(:,2) = 0; +for iData = 1:nData + currentDataIdx = distributionIdx==iData; + currentData = data(currentDataIdx,1); + + if ~isempty(currentData) + + % transform and sort + currentData = currentData / tFact; + %currentData = sort(currentData); + + % add x + currentData = [ones(size(currentData))*opt.xValues(iData),currentData]; %#ok + + % step through the data in 0.1 increments. If there are multiple + % entries, spread along x + for y = min(currentData(:,2)):opt.binWidth:max(currentData(:,2)) + % find values + valIdx = find(currentData(:,2) >= y & currentData(:,2) < y+opt.binWidth); + nVal = length(valIdx); + if nVal > 1 + % spread + switch opt.spreadFcn{1} + case 'xp' + spreadWidth = stdWidth*0.9*(1-exp(log(0.9)*(nVal-1))); + case 'lin' + spreadWidth = stdWidth*0.9*min(nVal-1,opt.spreadFcn{2})/opt.spreadFcn{2}; + end + spreadDist = spreadWidth / (nVal - 1); + if isEven(nVal) + offset = spreadDist / 2; + else + offset = eps; + end + for v = 1:nVal + currentData(valIdx(v),1) = opt.xValues(iData) + offset; + % update offset + offset = offset - sign(offset) * spreadDist * v; + end + end + end + + % update data + currentData(:,2) = data(currentDataIdx,1); + data(currentDataIdx,:) = currentData; + + + if opt.showMM > 0 + m(iData) = nanmean(currentData(:,2)); + md(iData) = nanmedian(currentData(:,2)); + sd(iData) = nanstd(currentData(:,2)); + sem(iData) = sd(iData)/sqrt(sum(isfinite(currentData(:,2)))); + end + end % test isempty +end + + +%% plot +set(ah,'NextPlot','add') +ph = NaN(nData,nCategories); +for iData = 1:nData + for iCategory = 1:nCategories + currentIdx = distributionIdx == iData & categoryIdx == iCategory; + if any(currentIdx) + switch opt.xyOri + case 'normal' + ph(iData,iCategory) = plot(ah,data(currentIdx,1),... + data(currentIdx,2),... + 'marker',plotMarkers{iData,iCategory},... + 'color',plotColors{iData,iCategory},... + 'lineStyle','none',... + 'DisplayName',plotLabels{iData,iCategory}); + case 'flipped' + ph(iData,iCategory) = plot(ah,data(currentIdx,2),... + data(currentIdx,1),... + 'marker',plotMarkers{iData,iCategory},... + 'color',plotColors{iData,iCategory},... + 'lineStyle','none',... + 'DisplayName',plotLabels{iData,iCategory}); + end + end + end +end + + + +% if ~empty, use xNames +switch opt.xyOri + case 'normal' + switch opt.xMode + case 'manual' + set(ah,'XTick',opt.xValues); + if ~isempty(opt.xNames) + set(ah,'XTickLabel',opt.xNames) + end + case 'auto' + % no need to do anything + end + + % have plot start/end properly + minX = min(opt.xValues)-stdWidth; + maxX = max(opt.xValues)+stdWidth; + if ~newAx + oldLim = xlim; + minX = min(minX,oldLim(1)); + maxX = max(maxX,oldLim(2)); + end + xlim([minX,maxX]) + + ylabel(ah,opt.yLabel) + + case 'flipped' + switch opt.xMode + case 'manual' + set(ah,'YTick',opt.xValues); + if ~isempty(opt.xNames) + set(ah,'YTickLabel',opt.xNames) + end + case 'auto' + % no need to do anything + end + + % have plot start/end properly (for ease of copying, only switch + % xlim to ylim + minX = min(opt.xValues)-stdWidth; + maxX = max(opt.xValues)+stdWidth; + if ~newAx + oldLim = ylim; + minX = min(minX,oldLim(1)); + maxX = max(maxX,oldLim(2)); + end + ylim([minX,maxX]) + + xlabel(ah,opt.yLabel); + +end + +% ## in development +if ~opt.individualLabels + % hack: add legend entry only once per category + goodH = ishandle(ph); + for iCategory = 1:nCategories + for iData = find(goodH(:,iCategory),1,'first')+1:nData + if goodH(iData,iCategory) + set(get(get(ph(iData,iCategory),'Annotation'),'LegendInformation'),... + 'IconDisplayStyle','off'); + end + end + end + +end + + +% add mean/median +mh = [];mdh=[]; +if opt.showMM + % plot mean, median. Mean is filled red circle, median is green square + % I don't know of a very clever way to flip xy and keep everything + % readable, thus it'll be copy-paste + switch opt.xyOri + case 'normal' + if any(opt.showMM==[1,2]) + mh = plot(ah,opt.xValues,m,'+r','Color','r','MarkerSize',12); + end + if any(opt.showMM==[1,3]) + mdh = plot(ah,opt.xValues,md,'sg','MarkerSize',12); + end + if opt.showMM == 4 + mh = plot(ah,opt.xValues,m,'+r','Color','r','MarkerSize',12); + mdh = myErrorbar(ah,opt.xValues,m,sem); + end + if opt.showMM == 5 + mh = plot(ah,opt.xValues,m,'+r','Color','r','MarkerSize',12); + mdh = myErrorbar(ah,opt.xValues,m,sd); + end + case 'flipped' + if any(opt.showMM==[1,2]) + mh = plot(ah,m,opt.xValues,'+r','Color','r','MarkerSize',12); + end + if any(opt.showMM==[1,3]) + mdh = plot(ah,md,opt.xValues,'sg','MarkerSize',12); + end + if opt.showMM == 4 + mh = plot(ah,m,opt.xValues,'+r','Color','r','MarkerSize',12); + mdh = myErrorbar(ah,m,opt.xValues,[sem,NaN(size(sem))]); + end + if opt.showMM == 5 + mh = plot(ah,m,opt.xValues,'+r','Color','r','MarkerSize',12); + mdh = myErrorbar(ah,m,opt.xValues,[sd,NaN(size(sd))]); + end + end +end + +%========================== +%% CLEANUP & ASSIGN OUTPUT +%========================== + +if nargout > 0 + handles{1} = ph; + handles{2} = [mh;mdh]; + handles{3} = ah; +end + diff --git a/analysis/MATLAB_functions/plotSpread/repeatEntries.m b/analysis/MATLAB_functions/plotSpread/repeatEntries.m new file mode 100644 index 0000000..19dd526 --- /dev/null +++ b/analysis/MATLAB_functions/plotSpread/repeatEntries.m @@ -0,0 +1,140 @@ +function out = repeatEntries(val,kTimes) +%REPEATENTRIES fills a matrix with k repeats the rows of the input matrix +% +% SYNOPSIS out = repeatEntries(val,kTimes) +% +% INPUT val : matrix (or vectors) containing the rows to repeat (works for strings, too) +% kTimes : number of repeats of each row (scalar or vector of size(vlaues,1)) +% +% OUTPUT out : matrix of size [sum(kTimes) size(values,2)] containing +% repeated entries specified with k +% +% EXAMPLES repeatEntries([1;2;3;4],[2;3;1;1]) returns [1;1;2;2;2;3;4] +% +% repeatEntries([1;2;3;4],2) returns [1;1;2;2;3;3;4;4] +% +% c: jonas, 2/04 +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +% note: in case we need to speed this up: adapt the code below +% nn = cellfun(@numel,points); +% a = find(nn); +% index = zeros(sum(nn),1); +% index([1;cumsum(nn(a(1:end-1)))+1])=1; +% +% % get the indices +% ii = a(cumsum(index)); + +%=========== +% test input +%=========== + +% nargin +if nargin ~= 2 || isempty(val) || isempty(kTimes) + error('two non-empty input arguments are needed!') +end + +% size +valSize = size(val); +if length(valSize)>2 + error('only 2D arrays supported for val') +end + + + +% decide whether we have scalar k +numK = length(kTimes); +if numK == 1 + scalarK = 1; +elseif numK ~= valSize(1) + error('vector k must have the same length as the number of rows in val or be a scalar') +else + % check again whether we could use scalar k + if all(kTimes(1) == kTimes) + scalarK = 1; + kTimes = kTimes(1); + else + scalarK = 0; + end +end + +% do not care about size of k: we want to make a col vector out of it - and +% this vector should only contain nonzero positive integers +kTimes = round(kTimes(:)); +% if there are any negative values or zeros, remove the entry +if scalarK && kTimes < 1 + out = []; + return +end +if ~scalarK + badK = kTimes < 1; + kTimes(badK) = []; + val(badK,:) = []; + % update valSize + valSize = size(val); + if any(valSize==0) + out = []; + return + end +end +%kTimes = max(kTimes,ones(size(kTimes))); + + +%============ +% fill in out +%============ + +% first the elegant case: scalar k +if scalarK + + % build repeat index matrix idxMat + idxMat = meshgrid( 1:valSize(1), 1:kTimes(1) ); + idxMat = idxMat(:); % returns [1;1...2;2;... etc] + + out = val(idxMat,:); + + % second: the loop +else + + % init out, init counter + if iscell(val) + out = cell(sum(kTimes) , valSize(2)); + else + out = zeros( sum(kTimes), valSize(2) ); + end + endct = 0; + + if valSize(2) == 1 + + % vector: fill directly + + % loop and fill + for i = 1:valSize(1) + startct = endct + 1; + endct = endct + kTimes(i); + out(startct:endct,:) = val(i); + end % for i=1:valSize(1) + + else + + % matrix: fill via index list + + idxMat = zeros(sum(kTimes),1); + + for i = 1:valSize(1) + startct = endct + 1; + endct = endct + kTimes(i); + idxMat(startct:endct) = i; + end % for i=1:valSize(1) + out = val(idxMat,:); + + end + + % check for strings and transform if necessary + if ischar(val) + out = char(out); + end + +end % if doScalar + + diff --git a/analysis/MATLAB_functions/progressbar.m b/analysis/MATLAB_functions/progressbar.m new file mode 100644 index 0000000..a66bc39 --- /dev/null +++ b/analysis/MATLAB_functions/progressbar.m @@ -0,0 +1,359 @@ +function progressbar(varargin) +% Description: +% progressbar() provides an indication of the progress of some task using +% graphics and text. Calling progressbar repeatedly will update the figure and +% automatically estimate the amount of time remaining. +% This implementation of progressbar is intended to be extremely simple to use +% while providing a high quality user experience. +% +% Features: +% - Can add progressbar to existing m-files with a single line of code. +% - Supports multiple bars in one figure to show progress of nested loops. +% - Optional labels on bars. +% - Figure closes automatically when task is complete. +% - Only one figure can exist so old figures don't clutter the desktop. +% - Remaining time estimate is accurate even if the figure gets closed. +% - Minimal execution time. Won't slow down code. +% - Randomized color. When a programmer gets bored... +% +% Example Function Calls For Single Bar Usage: +% progressbar % Initialize/reset +% progressbar(0) % Initialize/reset +% progressbar('Label') % Initialize/reset and label the bar +% progressbar(0.5) % Update +% progressbar(1) % Close +% +% Example Function Calls For Multi Bar Usage: +% progressbar(0, 0) % Initialize/reset two bars +% progressbar('A', '') % Initialize/reset two bars with one label +% progressbar('', 'B') % Initialize/reset two bars with one label +% progressbar('A', 'B') % Initialize/reset two bars with two labels +% progressbar(0.3) % Update 1st bar +% progressbar(0.3, []) % Update 1st bar +% progressbar([], 0.3) % Update 2nd bar +% progressbar(0.7, 0.9) % Update both bars +% progressbar(1) % Close +% progressbar(1, []) % Close +% progressbar(1, 0.4) % Close +% +% Notes: +% For best results, call progressbar with all zero (or all string) inputs +% before any processing. This sets the proper starting time reference to +% calculate time remaining. +% Bar color is choosen randomly when the figure is created or reset. Clicking +% the bar will cause a random color change. +% +% Demos: +% % Single bar +% m = 500; +% progressbar % Init single bar +% for i = 1:m +% pause(0.01) % Do something important +% progressbar(i/m) % Update progress bar +% end +% +% % Simple multi bar (update one bar at a time) +% m = 4; +% n = 3; +% p = 100; +% progressbar(0,0,0) % Init 3 bars +% for i = 1:m +% progressbar([],0) % Reset 2nd bar +% for j = 1:n +% progressbar([],[],0) % Reset 3rd bar +% for k = 1:p +% pause(0.01) % Do something important +% progressbar([],[],k/p) % Update 3rd bar +% end +% progressbar([],j/n) % Update 2nd bar +% end +% progressbar(i/m) % Update 1st bar +% end +% +% % Fancy multi bar (use labels and update all bars at once) +% m = 4; +% n = 3; +% p = 100; +% progressbar('Monte Carlo Trials','Simulation','Component') % Init 3 bars +% for i = 1:m +% for j = 1:n +% for k = 1:p +% pause(0.01) % Do something important +% % Update all bars +% frac3 = k/p; +% frac2 = ((j-1) + frac3) / n; +% frac1 = ((i-1) + frac2) / m; +% progressbar(frac1, frac2, frac3) +% end +% end +% end +% +% Author: +% Steve Hoelzer +% +% Revisions: +% 2002-Feb-27 Created function +% 2002-Mar-19 Updated title text order +% 2002-Apr-11 Use floor instead of round for percentdone +% 2002-Jun-06 Updated for speed using patch (Thanks to waitbar.m) +% 2002-Jun-19 Choose random patch color when a new figure is created +% 2002-Jun-24 Click on bar or axes to choose new random color +% 2002-Jun-27 Calc time left, reset progress bar when fractiondone == 0 +% 2002-Jun-28 Remove extraText var, add position var +% 2002-Jul-18 fractiondone input is optional +% 2002-Jul-19 Allow position to specify screen coordinates +% 2002-Jul-22 Clear vars used in color change callback routine +% 2002-Jul-29 Position input is always specified in pixels +% 2002-Sep-09 Change order of title bar text +% 2003-Jun-13 Change 'min' to 'm' because of built in function 'min' +% 2003-Sep-08 Use callback for changing color instead of string +% 2003-Sep-10 Use persistent vars for speed, modify titlebarstr +% 2003-Sep-25 Correct titlebarstr for 0% case +% 2003-Nov-25 Clear all persistent vars when percentdone = 100 +% 2004-Jan-22 Cleaner reset process, don't create figure if percentdone = 100 +% 2004-Jan-27 Handle incorrect position input +% 2004-Feb-16 Minimum time interval between updates +% 2004-Apr-01 Cleaner process of enforcing minimum time interval +% 2004-Oct-08 Seperate function for timeleftstr, expand to include days +% 2004-Oct-20 Efficient if-else structure for sec2timestr +% 2006-Sep-11 Width is a multiple of height (don't stretch on widescreens) +% 2010-Sep-21 Major overhaul to support multiple bars and add labels +% + +persistent progfig progdata lastupdate + +% Get inputs +if nargin > 0 + input = varargin; + ninput = nargin; +else + % If no inputs, init with a single bar + input = {0}; + ninput = 1; +end + +% If task completed, close figure and clear vars, then exit +if input{1} == 1 + if ishandle(progfig) + delete(progfig) % Close progress bar + end + clear progfig progdata lastupdate % Clear persistent vars + drawnow + return +end + +% Init reset flag +resetflag = false; + +% Set reset flag if first input is a string +if ischar(input{1}) + resetflag = true; +end + +% Set reset flag if all inputs are zero +if input{1} == 0 + % If the quick check above passes, need to check all inputs + if all([input{:}] == 0) && (length([input{:}]) == ninput) + resetflag = true; + end +end + +% Set reset flag if more inputs than bars +if ninput > length(progdata) + resetflag = true; +end + +% If reset needed, close figure and forget old data +if resetflag + if ishandle(progfig) + delete(progfig) % Close progress bar + end + progfig = []; + progdata = []; % Forget obsolete data +end + +% Create new progress bar if needed +if ishandle(progfig) +else % This strange if-else works when progfig is empty (~ishandle() does not) + + % Define figure size and axes padding for the single bar case + height = 0.03; + width = height * 8; + hpad = 0.02; + vpad = 0.25; + + % Figure out how many bars to draw + nbars = max(ninput, length(progdata)); + + % Adjust figure size and axes padding for number of bars + heightfactor = (1 - vpad) * nbars + vpad; + height = height * heightfactor; + vpad = vpad / heightfactor; + + % Initialize progress bar figure + left = (1 - width) / 2; + bottom = (1 - height) / 2; + progfig = figure(... + 'Units', 'normalized',... + 'Position', [left bottom width height],... + 'NumberTitle', 'off',... + 'Resize', 'off',... + 'MenuBar', 'none' ); + + % Initialize axes, patch, and text for each bar + left = hpad; + width = 1 - 2*hpad; + vpadtotal = vpad * (nbars + 1); + height = (1 - vpadtotal) / nbars; + for ndx = 1:nbars + % Create axes, patch, and text + bottom = vpad + (vpad + height) * (nbars - ndx); + progdata(ndx).progaxes = axes( ... + 'Position', [left bottom width height], ... + 'XLim', [0 1], ... + 'YLim', [0 1], ... + 'Box', 'on', ... + 'ytick', [], ... + 'xtick', [] ); + progdata(ndx).progpatch = patch( ... + 'XData', [0 0 0 0], ... + 'YData', [0 0 1 1] ); + progdata(ndx).progtext = text(0.99, 0.5, '', ... + 'HorizontalAlignment', 'Right', ... + 'FontUnits', 'Normalized', ... + 'FontSize', 0.7 ); + progdata(ndx).proglabel = text(0.01, 0.5, '', ... + 'HorizontalAlignment', 'Left', ... + 'FontUnits', 'Normalized', ... + 'FontSize', 0.7 ); + if ischar(input{ndx}) + set(progdata(ndx).proglabel, 'String', input{ndx}) + input{ndx} = 0; + end + + % Set callbacks to change color on mouse click + set(progdata(ndx).progaxes, 'ButtonDownFcn', {@changecolor, progdata(ndx).progpatch}) + set(progdata(ndx).progpatch, 'ButtonDownFcn', {@changecolor, progdata(ndx).progpatch}) + set(progdata(ndx).progtext, 'ButtonDownFcn', {@changecolor, progdata(ndx).progpatch}) + set(progdata(ndx).proglabel, 'ButtonDownFcn', {@changecolor, progdata(ndx).progpatch}) + + % Pick a random color for this patch + changecolor([], [], progdata(ndx).progpatch) + + % Set starting time reference + if ~isfield(progdata(ndx), 'starttime') || isempty(progdata(ndx).starttime) + progdata(ndx).starttime = clock; + end + end + + % Set time of last update to ensure a redraw + lastupdate = clock - 1; + +end + +% Process inputs and update state of progdata +for ndx = 1:ninput + if ~isempty(input{ndx}) + progdata(ndx).fractiondone = input{ndx}; + progdata(ndx).clock = clock; + end +end + +% Enforce a minimum time interval between graphics updates +myclock = clock; +if abs(myclock(6) - lastupdate(6)) < 0.01 % Could use etime() but this is faster + return +end + +% Update progress patch +for ndx = 1:length(progdata) + set(progdata(ndx).progpatch, 'XData', ... + [0, progdata(ndx).fractiondone, progdata(ndx).fractiondone, 0]) +end + +% Update progress text if there is more than one bar +if length(progdata) > 1 + for ndx = 1:length(progdata) + set(progdata(ndx).progtext, 'String', ... + sprintf('%1d%%', floor(100*progdata(ndx).fractiondone))) + end +end + +% Update progress figure title bar +if progdata(1).fractiondone > 0 + runtime = etime(progdata(1).clock, progdata(1).starttime); + timeleft = runtime / progdata(1).fractiondone - runtime; + timeleftstr = sec2timestr(timeleft); + titlebarstr = sprintf('%2d%% %s remaining', ... + floor(100*progdata(1).fractiondone), timeleftstr); +else + titlebarstr = ' 0%'; +end +set(progfig, 'Name', titlebarstr) + +% Force redraw to show changes +drawnow + +% Record time of this update +lastupdate = clock; + + +% ------------------------------------------------------------------------------ +function changecolor(h, e, progpatch) %#ok +% Change the color of the progress bar patch + +% Prevent color from being too dark or too light +colormin = 1.5; +colormax = 2.8; + +thiscolor = rand(1, 3); +while (sum(thiscolor) < colormin) || (sum(thiscolor) > colormax) + thiscolor = rand(1, 3); +end + +set(progpatch, 'FaceColor', thiscolor) + + +% ------------------------------------------------------------------------------ +function timestr = sec2timestr(sec) +% Convert a time measurement from seconds into a human readable string. + +% Convert seconds to other units +w = floor(sec/604800); % Weeks +sec = sec - w*604800; +d = floor(sec/86400); % Days +sec = sec - d*86400; +h = floor(sec/3600); % Hours +sec = sec - h*3600; +m = floor(sec/60); % Minutes +sec = sec - m*60; +s = floor(sec); % Seconds + +% Create time string +if w > 0 + if w > 9 + timestr = sprintf('%d week', w); + else + timestr = sprintf('%d week, %d day', w, d); + end +elseif d > 0 + if d > 9 + timestr = sprintf('%d day', d); + else + timestr = sprintf('%d day, %d hr', d, h); + end +elseif h > 0 + if h > 9 + timestr = sprintf('%d hr', h); + else + timestr = sprintf('%d hr, %d min', h, m); + end +elseif m > 0 + if m > 9 + timestr = sprintf('%d min', m); + else + timestr = sprintf('%d min, %d sec', m, s); + end +else + timestr = sprintf('%d sec', s); +end diff --git a/analysis/MATLAB_functions/read_json.m b/analysis/MATLAB_functions/read_json.m new file mode 100644 index 0000000..28051d0 --- /dev/null +++ b/analysis/MATLAB_functions/read_json.m @@ -0,0 +1,6 @@ +function [data] = read_json(filename) +fid = fopen(filename); +raw = fread(fid,inf); +str = char(raw'); +fclose(fid); +data = jsondecode(str); \ No newline at end of file diff --git a/analysis/MATLAB_functions/read_nrrd_metadata.m b/analysis/MATLAB_functions/read_nrrd_metadata.m new file mode 100644 index 0000000..0ee3993 --- /dev/null +++ b/analysis/MATLAB_functions/read_nrrd_metadata.m @@ -0,0 +1,9 @@ +function [sz, rez] = read_nrrd_metadata (str_nrrd) +[~, rez]=nrrdread(str_nrrd); +sz=strread(rez.sizes); +sz=[sz(2) sz(1) sz(3)]; +rez=rez.spacedirections; +brackets=find(rez=='('); +commas=find(rez==','); +rez=[str2double(rez(brackets(1)+1:commas(1)-1)) str2double(rez(commas(3)+1:commas(4)-1)) str2double(rez(commas(6)+1:end-1))]; +rez=[rez(2) rez(1) rez(3)]; \ No newline at end of file diff --git a/analysis/MATLAB_functions/roundtowardvec.m b/analysis/MATLAB_functions/roundtowardvec.m new file mode 100644 index 0000000..4669649 --- /dev/null +++ b/analysis/MATLAB_functions/roundtowardvec.m @@ -0,0 +1,117 @@ +function X=roundtowardvec(X,roundvec,type) +%function newnums=roundtowardvec(X,[roundvec],[type]) +% +% This function rounds number(s) toward given values. If more than one +% number is given to round, it will return the matrix with each rounded +% value, otherwise it will return the single rounded value. It will ignore +% NaNs and return them back with NaNs. +% +% Inputs: X: the number(s) that you want rounded +% +% roundvec:(opt) the values to round X to. If none given, it will +% default to -inf:1:inf (and use the built in functions). +% +% type:(opt) specifies which kind of rounding you want +% the function to use. +% +% Choices are: 'round' - round to nearest value +% 'floor' - round toward -Inf +% 'ceil' - round toward Inf +% 'fix' - round toward 0 +% 'away' - round away from 0 (ceil if positive and floor if negative) +% (see help files for more clarity) +% +% If no type is given, the function will default to rounding to +% the nearest value. +% +% Outputs: newnums: rounded values, in same shape as X input matrix +% indices: indices of rounded values in roundvec + +if nargin==0 + help roundtowardvec; %if nothing given, tell what to give + return +elseif isempty(X) + %if given empty, return empty without going through whole script + return +end + +if nargout>1 + error('Too many output variables are given'); +end +if ~exist('type','var') || isempty(type) + type='round'; %%round to nearest value if not specified +end +if ~exist('roundvec','var') || isempty(roundvec) || all(isnan(roundvec)) + if strcmpi(type,'round') + %to nearest integer + X=round(X); + elseif strcmpi(type,'away') + %nearest integer away from 0 + X=ceil(abs(X)).*sign(X); + elseif strcmpi(type,'fix') + %nearest integer toward 0 + X=fix(X); + elseif strcmpi(type,'floor') + %nearest integer toward -inf + X=floor(X); + elseif strcmpi(type,'ceil') + %nearest integer toward inf + X=ceil(X); + else + error('%sRound type not recognized. Options are:\n''round'' - round to nearest value\n''floor'' - round toward -Inf\n''ceil'' - round toward Inf\n''fix'' - round toward 0\n''away'' - round away from 0','') + end +else + %Ignore nan in roundvec + roundvec(isnan(roundvec))=[]; + + %Record which values are nan to ignore + Xnan=isnan(X); + + %Hold onto size for returning value + sz=size(X); + + %Calculate differences + X=X(:); + roundvec=roundvec(:)'; + diffs=bsxfun(@minus,X,roundvec); + + if strcmpi(type,'round') %to nearest value + [~,inds]=min(abs(diffs),[],2); + X=roundvec(inds); + elseif strcmpi(type,'fix') %to nearest value toward 0 + + iless=X<0; + X(iless)=roundtowardvec(X(iless),roundvec,'ceil'); + X(~iless)=roundtowardvec(X(~iless),roundvec,'floor'); + elseif strcmpi(type,'ceil') %nearest value toward inf + diffs(diffs>0)=nan; + [~,inds]=min(abs(diffs),[],2); + + i_inf=X>max(roundvec); + X=roundvec(inds); + X(i_inf)=inf; + elseif strcmpi(type,'floor') %nearest value toward -inf + diffs(diffs<0)=nan; + [~,inds]=min(abs(diffs),[],2); + + i_inf=X1 + for plane=1:num_planes + mat_file(:,:,plane)=imread(fullfile(pathname, filename),plane); + end +elseif ndims(mat_file)==4 || (ndims(mat_file)==3 && num_planes==1) + for plane=1:num_planes + mat_file(:,:,:,plane)=imread(fullfile(pathname, filename),plane); + end +else + error('Strange number of dimensions'); +end + diff --git a/analysis/MATLAB_functions/trace2regressor.m b/analysis/MATLAB_functions/trace2regressor.m new file mode 100644 index 0000000..f94531f --- /dev/null +++ b/analysis/MATLAB_functions/trace2regressor.m @@ -0,0 +1,14 @@ +function regressor = trace2regressor(trace,my_kernel,time_be,time_im) +regressor=conv(trace,my_kernel); +regressor(length(trace)+1:end)=[]; +regressor=interp1(time_be,regressor,time_im); +% if any(regressor>0) +% regressor=regressor/max(regressor); +% end +temp2=find(isnan(regressor)); +regressor(temp2)=[]; +regressor=zscore(regressor); +for i2=1:length(temp2) + regressor=[regressor(1:temp2(i2)-1) nan regressor(temp2(i2):end)]; +end +regressor(temp2)=nan; \ No newline at end of file diff --git a/analysis/Markov_et_al_2021_Make_Figures.m b/analysis/Markov_et_al_2021_Make_Figures.m new file mode 100644 index 0000000..bc9cf03 --- /dev/null +++ b/analysis/Markov_et_al_2021_Make_Figures.m @@ -0,0 +1,2253 @@ +%% initial stuff +clc; close all; clear all; +addpath(genpath('C:\Markov_et_al_2021_Nat_Commun_data_code\analysis_code')); +% folders +pathname_MS_data = 'C:\Markov_et_al_2021_Nat_Commun_data_code\data\'; +pathname_behavior=[pathname_MS_data 'behavior\']; +pathname_model=[pathname_MS_data 'feedback_control_model\']; +pathname_PC_imaging=[pathname_MS_data 'PC_imaging_long_term_adaptation\']; +pathname_reference_brains = [pathname_MS_data 'reference_brain_stacks\']; +pathname_whole_brain_imaging_integrators = [pathname_MS_data 'whole_brain_imaging_inetgrators\']; +pathname_whole_brain_imaging_lta = [pathname_MS_data 'whole_brain_imaging_long_term_adaptation\']; + +% colors used in all figures +col_motor=[0 0.5828 0]; +col_sensory=[0.7 0 0.7]; +col_activity=[255 127 0]/255; +col_sensors = [0 0.3730 1]; +col_integrators = [0.8975 0 0.2390]; +temp_fig=figure; +aa=colormap(parula(37)); +col_lt_trials=[[0 0 0]; aa(1:21,:); [1 0.7 0.2]]; +close(temp_fig); clear temp_fig aa; +% colormap(col_lt_trials); +% colorbar; +col_pre=col_lt_trials(1,:); +col_post=col_lt_trials(end,:); +col_post_start=[255 220 100]/255; +col_post_end=[255 130 0]/255; +col_adapt_start=col_lt_trials(2,:); +col_adapt_end=col_lt_trials(end-1,:); +col_adapt=col_lt_trials(12,:); +col_norm_reaf=[0 0 0]; +col_lag_trained=[0.8 0 0]; +col_lag_trained_bad=[0.8 0.6 0.6]; +col_red_line=[0.8 0 0]; +col_model_fitting=[0 0.6 0.6]; +col_PC=[1 0.5 0]; +r=linspace(col_sensory(1),1,6)'; +g=linspace(col_sensory(2),0.7,6)'; +b=linspace(col_sensory(3),0,6)'; +cols_lags=[r g b]; +r=linspace(0, col_sensory(1),4)'; +g=linspace(0.7, col_sensory(2),4)'; +b=linspace(1, col_sensory(3),4)'; +r=[r(1:end-1); linspace(col_sensory(1),1,4)']; +g=[g(1:end-1); linspace(col_sensory(2),0.7,4)']; +b=[b(1:end-1); linspace(col_sensory(3),0,4)']; +cols_gains=flip([r g b],1); +r=linspace(col_sensory(1),0,4)'; +g=linspace(col_sensory(2),0.7,4)'; +b=linspace(col_sensory(3),1,4)'; +r=[linspace(col_sensory(1),1,5)'; r(2:end)]; +g=[linspace(col_sensory(2),0.7,5)'; g(2:end)]; +b=[linspace(col_sensory(3),0,5)'; b(2:end)]; +cols_gain_drops=[r g b]; +clear r g b; + + +%% Fig. 1: Closed-loop experimental assay to study optomotor behavior in larval zebrafish +% % Fig. 1a: Fish swimming with respect to observational and fish reference frames +% % created in allustrator +% +% % Fig. 1b: Tail movement, fish position and velocity with respect to observational and fish reference frames +% figure('name','Fig. 1b'); +% cartoon_pad_length=1; +% [cartoon_time, cartoon_bout, cartoon_vigor] = make_cartoon_bout(cartoon_pad_length); +% est_pos = cumsum(cartoon_vigor); +% axes('xlim',[0 2.4],'ycolor','none','xcolor','none'); hold on; +% fill_bout (gca,cartoon_pad_length+0.001,cartoon_pad_length+0.4,-1,0,0.3); +% plot(cartoon_time,cartoon_bout,'color',col_motor); +% plot(cartoon_time, cartoon_vigor,'color',col_sensory); +% plot(cartoon_time, est_pos/200,'color',col_sensory); +% dm_fix_fig_fonts; +% clear cartoon_bout cartoon_vigor est_pos cartoon_pad_length cartoon_time; +% +% % Fig. 1c: Experimental rig +% % created in illustrator +% +% % Fig. 1d: Example trial with all traces +% create_single_trial_axes('Fig. 1d'); +% acute_TL=load([pathname_behavior 'acute_reaction_experiment/WT_TL_group/pooled_data.mat'],'behavior'); +% acute_TL=acute_TL.behavior; +% fish_num=8; +% fish_id=acute_TL(fish_num).fish_id; +% [time_be, tail, grspeed]=get_example_fish(fish_id, pathname_behavior, 'acute_reaction_experiment/WT_TL_group/'); +% ex_trial_num=20; +% [this_time, this_tail, this_gr, bout_starts, bout_ends] = get_example_trial_data(ex_trial_num,time_be,tail,grspeed,acute_TL(fish_num)); +% for b=1:length(bout_starts) +% fill_bout (gca,bout_starts(b),bout_ends(b),-55,0,0.3); +% end +% base_gr=zeros(1,length(this_time)); +% base_gr(this_time>0 & this_time<15)=10; +% plot(this_time,base_gr,'color',col_sensory); +% plot(this_time,this_tail*3-4,'color',col_motor); +% fish_vel=this_gr; +% fish_vel(this_time<0.1 | this_time>14.9)=10; +% plot(this_time,-fish_vel-30,'color',col_motor); +% plot(this_time,this_gr-55,'color',col_sensory); +% dm_fix_fig_fonts; +% clear b acute_TL fish_num fish_id time_be tail grspeed ex_trial_num this_time this_tail this_gr bout_starts bout_ends base_gr fish_vel; + + +%% Fig. 2: Acute reaction to unexpected perturbations in visual feedback can be implemented by a feedback controller +% % Fig. 2a: All reafference conditions +% cartoon_pad_length = 0.5; +% [cartoon_time, cartoon_bout, cartoon_vigor, cartoon_swim] = make_cartoon_bout(cartoon_pad_length); +% cartoon_dt=cartoon_time(2)-cartoon_time(1); +% fig_names = {'Fig. 2ai','Fig. 2aii top','Fig. 2aii bottom','Fig. 2aiii top','Fig. 2aiii bottom'}; +% reaf_conds = {[[0;0;0;0;0],[0.33;0;0;0;0],[0.66;0;0;0;0],[1;0;0;0;0],[1.33;0;0;0;0],[1.66;0;0;0;0],[2;0;0;0;0]],... +% [[1;0;0;0;0],[1;0.075/cartoon_dt;0;0;0],[1;0.15/cartoon_dt;0;0;0],[1;0.225/cartoon_dt;0;0;0],[1;0.3/cartoon_dt;0;0;0],[0;0;0;0;0]],... +% [[1;0;0;0;0],[1;0.075/cartoon_dt;1;0;0],[1;0.15/cartoon_dt;1;0;0],[1;0.225/cartoon_dt;1;0;0],[1;0.3/cartoon_dt;1;0;0],[0;0;0;0;0]],... +% [[1;0;0;0;0],[1;0;0;0;0.075/cartoon_dt],[1;0;0;0;0.150/cartoon_dt],[1;0;0;0;0.225/cartoon_dt],[1;0;0;0;0.3/cartoon_dt]],... +% [[1;0;0;0;0],[1;0;0;0.225/cartoon_dt;0.3/cartoon_dt],[1;0;0;0.15/cartoon_dt;0.3/cartoon_dt],[1;0;0;0.075/cartoon_dt;0.3/cartoon_dt],[1;0;0;0;0.3/cartoon_dt]]}; +% for i=1:length(fig_names) +% figure('name',fig_names{i}); +% axes('ycolor','none','xcolor','none'); hold on; +% plot_reaf_cond(reaf_conds{i}, cartoon_time, cartoon_bout, cartoon_swim, cartoon_vigor, cartoon_pad_length, col_motor, col_sensory) +% dm_fix_fig_fonts; +% end +% clear cartoon_time cartoon_bout cartoon_swim cartoon_vigor cartoon_pad_length cartoon_dt reaf_conds +% +% % Fig. 2b: The model (short little circuits for insets) +% dt=0.005; +% par_schema=[0.27; 0.4; 1; 5; 0.6; 0.6; 0.5; 0.6]; +% par_schema(3)=dt/par_schema(3); +% par_schema(8)=dt/par_schema(8); +% [swim,grspeed,brain_state] = model_one_bout_trial_v3 (par_schema, dt); +% figure('name','Fig. 2b'); +% subplot(4,4,1,'xcolor','none','ycolor','none','ylim',[-10 10]); hold on +% plot(grspeed,'color',col_sensory,'linewidth',1.5) +% pbaspect([2 1 1]) +% subplot(4,4,2,'xcolor','none','ycolor','none','ylim',[-1 1]); hold on +% plot(swim,'color',col_motor,'linewidth',1.5) +% pbaspect([2 1 1]) +% y_lims=[-10 10; -10 10; -1 1; -0.6 0.6; -0.2 0.2]; +% for i=1:5 +% subplot(4,4,2+i,'xcolor','none','ycolor','none','ylim',y_lims(i,:)); hold on +% plot(brain_state(i,:),'color',col_activity,'linewidth',1.5); +% pbaspect([2 1 1]) +% end +% subplot(4,4,2+i+1,'xcolor','none','ycolor','none','ylim',[-1 1]); hold on +% plot(swim,'color',col_activity,'linewidth',1.5); +% pbaspect([2 1 1]) +% subplot(4,4,2+i+2,'xcolor','none','ycolor','none','ylim',[-10 10]); hold on; +% grspeed(grspeed<0)=10; +% plot(grspeed,'color',col_sensory,'linewidth',1.5); +% pbaspect([2 1 1]); +% dm_fix_fig_fonts; +% clear par_schema swim grspeed brain_state y_lims i; +% +% % Fig. 2c-d: bout and interbout duration in acute reaction experiment +% acute_TL=load([pathname_behavior 'acute_reaction_experiment/WT_TL_group/pooled_data.mat'],'behavior'); +% acute_TL=acute_TL.behavior; +% reaf=load([pathname_model 'gt.mat'],'reaf'); +% reaf=reaf.reaf'; +% for i=[2 4 5] +% reaf(:,i)=round(reaf(:,i)/dt); +% end +% reaf_cond_ids={[6 11 12 1 13 14 15];... % gain +% [1 2 3 4 5 6];... % lag +% [1 7 8 9 10 6];... % shunted lag +% [1 7 8 9 10 16 17 18]}; % gain drop +% best_par=load([pathname_model 'fitted_parameters.mat'],'best_par'); +% best_par=best_par.best_par; +% best_par(3,:)=dt./best_par(3,:); +% best_par(8,:)=dt./best_par(8,:); +% panel_names={'Fig. 2ci', 'Fig. 2cii', 'Fig. 2ciii', 'Fig. 2civ'; 'Fig. 2di', 'Fig. 2dii', 'Fig. 2diii', 'Fig. 2div'}; +% cond_names={'gain', 'lag', 'shunted_lag', 'gain_drop'}; +% par_names={'bout_duration';'next_interbout_duration'}; +% x_labels={'gain','lag [ms]','shunted lag [ms]','gain profile'}; +% y_labels={'mean bout duration [s]'; 'mean interbout duration [s]'}; +% y_lims=[0.25 0.55; 0.8 1.7]; +% for i=1:2 +% for c=1:4 +% prepare_acute_axes(panel_names{i,c},acute_TL,cond_names{c},x_labels{c}); +% data_exp=prepare_data_acute(acute_TL,cond_names{c},par_names{i}); +% data_mod=prepare_data_acute_model(reaf(reaf_cond_ids{c},:),best_par,dt,par_names{i}); +% plot_acute({data_exp,data_mod},[0 0 0; col_model_fitting],y_labels{i},y_lims(i,:)); +% dm_fix_fig_fonts; +% end +% end +% +% % Extended Data Fig. 1b: fitted model parameters +% best_par=load([pathname_model 'fitted_parameters.mat'],'best_par'); +% best_par=best_par.best_par; +% figure('name','Extended Data Fig. 1b'); +% titles = {'wf','wr','taus','wi','ws','t','wm','taum'}; +% my_edges = {0:1/10:1, 0:1/10:1, 0:1:10, 0:1:10, 0:1/10:1, 0:1/10:1, 0:4/10:4, 0:1:10}; +% for i=1:8 +% subplot(2,4,i,'xtick',my_edges{i},'ylim',[0 40]); hold on; +% title(titles{i}); +% a = best_par(i,:); +% [b, tf] = rmoutliers(a); +% disp([titles{i} ': outliers removed: ' num2str(a(tf))]); +% histogram(b,my_edges{i},'facecolor',[0.5 0.5 0.5]); +% drawnow; +% x_tick_label = get(gca,'xticklabel'); +% for j=2:5:length(my_edges{i}) +% x_tick_label{j}=''; +% x_tick_label{j+1}=''; +% x_tick_label{j+2}=''; +% x_tick_label{j+3}=''; +% end +% set(gca,'xticklabel',x_tick_label); +% end +% dm_fix_fig_fonts; +% +% % Fig. 2e: bout power under different reafference conditions +% time_power=-0.1:dt:1-dt; +% h_acute = find_ballistic_end_acyte(acute_TL,[4 18],time_power); +% panel_names={'Fig. 2ei','Fig. 2eii','Fig. 2eiii','Fig. 2eiv'}; +% cond_names={'gain', 'lag', 'shunted_lag', 'gain_drop'}; +% cols={cols_gains, cols_lags, cols_lags, cols_gain_drops}; +% for i=1:4 +% plot_bout_power_acute(panel_names{i},acute_TL,cond_names{i},cols{i},time_power,h_acute,[0 0 0],[0 2.5]); +% dm_fix_fig_fonts; +% end +% clear time_power dt fig_names data_mod data_exp panel_names cond_names cols i acute_TL h_acute ballistic_end_acute_gaindrop0000 ballistic_end_acute_gaindrop0001 ballistic_end_acute_gaindrop0011 ballistic_end_acute_gaindrop0111 ballistic_end_acute_gaindrop1000 ballistic_end_acute_gaindrop1100 ballistic_end_acute_gaindrop1110 acute_TL best_par i c reaf reaf_cond_ids panel_names cond_names par_names x_labels y_labels y_lims; + + +%% Fig. 3: Larval zebrafish are able to integrate the optic flow +% % load the data +% [sz, rez] = read_nrrd_metadata([pathname_reference_brains 'PortuguesLab_wholebrain_ref_gamma_masked.nrrd']); +% all_fish = dm_dir([pathname_whole_brain_imaging_integrators 'behavior\*_f*_behavior.mat']); +% all_fish = strrep(all_fish,'_behavior.mat',''); +% n_fish = length(all_fish); +% ROI_coord_all = cell(n_fish,1); +% n_ROIs_all = zeros(n_fish,1); +% sensmot_clust_all = cell(n_fish,1); +% traces_gr_trig_all = cell(n_fish,1); +% traces_bout_trig_all = cell(n_fish,1); +% traces_gr_trig_tau_all = cell(n_fish,1); +% time_constants_all = cell(n_fish,1); +% load([pathname_whole_brain_imaging_integrators 'triggered_traces\' all_fish{1} '_trig_traces.mat'],'time_trig','time_trig_tau') +% progressbar('Loading data for Fig. 3...'); +% for f = 1:n_fish +% fish_id = all_fish{f}; +% load([pathname_whole_brain_imaging_integrators 'ROIs\' fish_id '_ROIs.mat'],'ROI_coord'); +% ROI_coord_all{f} = ROI_coord; +% n_ROIs_all(f) = length(ROI_coord); +% load([pathname_whole_brain_imaging_integrators 'triggered_traces\' fish_id '_trig_traces.mat'],'traces_gr_trig_mean','traces_bout_trig_mean','traces_gr_trig_mean_tau'); +% traces_gr_trig_all{f} = traces_gr_trig_mean; +% traces_bout_trig_all{f} = traces_bout_trig_mean; +% traces_gr_trig_tau_all{f} = traces_gr_trig_mean_tau; +% load([pathname_whole_brain_imaging_integrators 'clustering\' fish_id '_clustering.mat'],'sensmot_clust'); +% sensmot_clust_all{f} = sensmot_clust; +% load([pathname_whole_brain_imaging_integrators 'time_constants\' fish_id '_time_constants.mat'],'time_constants'); +% time_constants_all{f} = time_constants; +% progressbar(f/n_fish); +% end +% my_colormap=hot(64); +% my_colormap=my_colormap(round(linspace(1,64,n_fish+1)),:); +% ex_fish_id = '190523_f0'; +% ex_fish_num = find(contains(all_fish,ex_fish_id)); +% ex_trial = 45; +% ex_sens_ROI_id = 21644; +% ex_mot_ROI_id = 26246; +% ex_trial_int = 43; +% ex_sensor_id = 21645; +% ex_integrator_id = 26774; +% clear all_fish fish_id ROI_coord traces_gr_trig_mean traces_gr_trig_mean_tau sensmot_clust time_constants +% % Fig. 3a: Schematics of the light-sheet setup +% % created in illustrator +% +% % Fig. 3b: colormap of all imaged ROIs with location of 4 example ROIs +% % compute stack with fraction of ROIs +% A = zeros(sz,'uint8'); +% for f = 1:n_fish +% for i = 1:n_ROIs_all(f) +% coord = ROI_coord_all{f}{i}; +% A(coord) = A(coord) + 1; +% end +% end +% % compute top and side views +% [top_view, side_view]=three_orthogonal_views(A,rez(1)); +% top_view=1-top_view/n_fish; +% side_view=1-round(side_view)/n_fish; +% % plot top and side views of the fractions of all ROIs +% figure('name','Fig. 3b top'); +% axes('xcolor','none','ycolor','none','ydir','reverse','clim',[0 1],'xlim',[1 sz(2)],'ylim',[1 sz(1)]); hold on; +% pbaspect([1 sz(1)/sz(2) 1]); +% imagesc(top_view); +% colormap(my_colormap); +% figure('name','Fig. 3b side'); +% axes('xcolor','none','ycolor','none','ydir','reverse','clim',[0 1],'xlim',[1 round(sz(3)/rez(2))],'ylim',[1 sz(1)]); hold on; +% pbaspect([1 sz(1)/round(sz(3)/rez(2)) 1]); +% imagesc(side_view); +% colormap(my_colormap); +% % make a colorbar for fish-fraction plots +% figure('name','Fig. 3b colormap'); +% axes('ycolor','none','xcolor','none'); +% colormap(flip(my_colormap,1)); +% clrbr=colorbar; +% clrbr.Ticks=1/(n_fish+1)/2:1/(n_fish+1):1-1/(n_fish+1)/2; +% clrbr.TickLabels=round((0:1/n_fish:1)'*100); +% ylabel(clrbr,{'percentage of fish';'with activity'}); +% dm_fix_fig_fonts; +% % plot top and side views of the reference brain mask (for outlines) +% ref_brain_mask = nrrdread([pathname_reference_brains 'PortuguesLab_wholebrain_ref_mask.nrrd']); +% [top_view,side_view] = three_orthogonal_views(ref_brain_mask,rez(2)); +% figure('name','Fig. 3b reference brain mask top'); +% imshow(1-top_view); +% figure('name','Fig. 3b reference brain mask side'); +% imshow(1-side_view); +% % plot 100 um scale bar +% a=ones(sz(1:2)); +% a(50:51,50:50+round(100/rez(1)))=0; +% figure('name','Fig. 3b 100 micron scale bar'); +% imshow(a); +% % plot top and side views of locations of example ROIs shown in other panels +% A_ex_locations = zeros([sz 3]); +% for i=1:3 +% temp = zeros(sz); +% temp(ROI_coord_all{ex_fish_num}{ex_sens_ROI_id}) = col_sensory(i); +% temp(ROI_coord_all{ex_fish_num}{ex_mot_ROI_id}) = col_motor(i); +% temp(ROI_coord_all{ex_fish_num}{ex_sensor_id}) = col_sensors(i); +% temp(ROI_coord_all{ex_fish_num}{ex_integrator_id}) = col_integrators(i); +% A_ex_locations(:,:,:,i) = temp; +% end +% top_view_ex_locations = squeeze(max(A_ex_locations,[],3)); +% figure('name','Fig. 3b example roi locations top'); +% imshow(top_view_ex_locations); +% side_view_ex_locations=squeeze(double(max(A_ex_locations,[],2))); +% side_view_ex_locations=imresize(side_view_ex_locations,[sz(1),round(sz(3)/rez(1))]); +% side_view_ex_locations=flip(side_view_ex_locations,2); +% figure('name','Fig. 3b example roi locations side'); +% imshow(side_view_ex_locations); +% % plot raw anatomy to show that these ROIs are cell bodies +% ex_anatomy = nrrdread([pathname_whole_brain_imaging_integrators 'anatomies\' ex_fish_id '_anatomy.nrrd']); +% figure('name','Fig. 3b example roi locations zoomed in'); +% subplot(2,2,1); +% imshow(small_anatomy_image(ex_anatomy,sz,ROI_coord_all,ex_fish_num,ex_sens_ROI_id,col_sensory)); +% subplot(2,2,2); +% imshow(small_anatomy_image(ex_anatomy,sz,ROI_coord_all,ex_fish_num,ex_mot_ROI_id,col_motor)); +% subplot(2,2,3); +% imshow(small_anatomy_image(ex_anatomy,sz,ROI_coord_all,ex_fish_num,ex_sensor_id,col_sensors)); +% subplot(2,2,4); +% imshow(small_anatomy_image(ex_anatomy,sz,ROI_coord_all,ex_fish_num,ex_integrator_id,col_integrators)); +% figure('name','Fig. 3b example roi locations zoomed in scale bar 50 um'); +% a = small_anatomy_image(ex_anatomy,sz,ROI_coord_all,ex_fish_num,ex_integrator_id,col_integrators); +% a(:,:,:)=0; +% a(4:5,5:5+round(10/rez(1)),:)=255; +% subplot(2,2,1); +% imshow(a); +% clear ex_anatomy A top_view side_view clrbr ref_brain_mask a A_ex_locations temp top_view_ex_locations side_view_ex_locations +% +% % Fig. 3c: activity of example sensory and motor ROIs in one example trial +% % load example fish data +% load([pathname_whole_brain_imaging_integrators 'behavior\' ex_fish_id '_behavior.mat'],'tail','bouts','time_be','meta'); +% load([pathname_whole_brain_imaging_integrators 'traces\' ex_fish_id '_traces.mat'],'traces','time_offsets'); +% % compute traces for the example trial +% dt = round((time_be(2)-time_be(1))*1000)/1000; +% trial_starts=120+7.5:30:time_be(end); +% this_trial_starts = trial_starts(ex_trial); +% this_tail = tail(time_be>=this_trial_starts-5 & time_be=0 & this_time_be<15)=10; +% bout_starts = bouts.start(bouts.trial==ex_trial)-this_trial_starts; +% bout_ends = bouts.end(bouts.trial==ex_trial)-this_trial_starts; +% dt_im = round(1/meta.fs*1000)/1000; +% time_im = dt_im:dt_im:dt_im*size(traces,2); +% this_trace_mot = traces(ex_mot_ROI_id,time_im+time_offsets(ex_mot_ROI_id)>=this_trial_starts-5 & time_im+time_offsets(ex_mot_ROI_id)=this_trial_starts-5 & time_im+time_offsets(ex_sens_ROI_id)=this_trial_starts-5 & time_be=this_trial_starts-5 & time_im+time_offsets(ex_sensor_id)=this_trial_starts-5 & time_im+time_offsets(ex_integrator_id)1.5,:); +% temp = temp(randperm(size(temp,1)),:); +% data_gr_trig_tau(data_time_constants>1.5,:) = temp; +% % plot +% figure('name','Fig. 3i'); +% axes('ydir','reverse','xlim',[-5 20],'ylim',0.5+[0,size(data_gr_trig_tau,1)],'ycolor','none','layer','top','xtick',-5:5:20); hold on; +% xlabel('time relative to trial onset [s]'); +% imagesc([time_trig_tau(1) time_trig_tau(end)],[1,size(data_gr_trig_tau,1)],data_gr_trig_tau); +% line([0 0],ylim,'color','k','linestyle',':'); +% colormap(flip(gray)); +% colorbar; +% line([-2 -2],[0 find(data_time_constants>=0 & data_time_constants<=1.5,1,'last')]+0.5,'color',col_sensors,'linewidth',4); +% line([-2 -2],[find(data_time_constants>=0 & data_time_constants<=1.5,1,'last') size(data_gr_trig_tau,1)]+0.5,'color',col_integrators,'linewidth',4); +% dm_fix_fig_fonts; +% clear temp ids_tau_sorted data_gr_trig_tau data_time_constants +% +% % Fig. 3j: location of sensors and integrators +% % compute stacks with fraction of ROIs +% A_sensors = zeros(sz,'uint8'); +% A_integrators = zeros(sz,'uint8'); +% for f = 1:n_fish +% for i = 1:n_ROIs_all(f) +% coord = ROI_coord_all{f}{i}; +% if time_constants_all{f}(i)>1.5 +% A_integrators(coord) = A_integrators(coord) + 1; +% elseif time_constants_all{f}(i)>0 +% A_sensors(coord) = A_sensors(coord) + 1; +% end +% end +% end +% % compute top and side views +% [top_view_sensors, side_view_sensors]=three_orthogonal_views(A_sensors,rez(1)); +% top_view_sensors=1-top_view_sensors/n_fish; +% side_view_sensors=1-round(side_view_sensors)/n_fish; +% [top_view_integrators, side_view_integrators]=three_orthogonal_views(A_integrators,rez(1)); +% top_view_integrators=1-top_view_integrators/n_fish; +% side_view_integrators=1-round(side_view_integrators)/n_fish; +% % plot top and side views of the fractions of sensory ROIs +% figure('name','Fig. 3j sensors top'); +% axes('xcolor','none','ycolor','none','ydir','reverse','clim',[0 1],'xlim',[1 sz(2)],'ylim',[1 sz(1)]); hold on; +% pbaspect([1 sz(1)/sz(2) 1]); +% imagesc(top_view_sensors); +% colormap(my_colormap); +% figure('name','Fig. 3j sensors side'); +% axes('xcolor','none','ycolor','none','ydir','reverse','clim',[0 1],'xlim',[1 round(sz(3)/rez(2))],'ylim',[1 sz(1)]); hold on; +% pbaspect([1 sz(1)/round(sz(3)/rez(2)) 1]); +% imagesc(side_view_sensors); +% colormap(my_colormap); +% figure('name','Fig. 3j integrators top'); +% axes('xcolor','none','ycolor','none','ydir','reverse','clim',[0 1],'xlim',[1 sz(2)],'ylim',[1 sz(1)]); hold on; +% pbaspect([1 sz(1)/sz(2) 1]); +% imagesc(top_view_integrators); +% colormap(my_colormap); +% figure('name','Fig. 3j integrators side'); +% axes('xcolor','none','ycolor','none','ydir','reverse','clim',[0 1],'xlim',[1 round(sz(3)/rez(2))],'ylim',[1 sz(1)]); hold on; +% pbaspect([1 sz(1)/round(sz(3)/rez(2)) 1]); +% imagesc(side_view_integrators); +% colormap(my_colormap); +% clear n_fish ROI_coord_all n_ROIs_all sensmot_clust_all traces_gr_trig_all traces_bout_trig_all traces_gr_trig_tau_all ... +% time_constants_all time_trig time_trig_tau f my_colormap ... +% ex_fish_id ex_fish_num ex_trial ex_sens_ROI_id ex_mot_ROI_id ex_trial_int ex_sensor_id ex_integrator_id... +% top_view_integrators side_view_integrators top_view_sensors side_view_sensors coord A_sensors A_integrators + +%% Fig. 4: Larval zebrafish adapt their behavior in response to a long-lasting perturbation in visual reafference +% % Fig. 4a: Experimental protocol (insets showing normal and lagged reafference) +% figure('name','Fig. 4a'); +% axes('ycolor','none','xcolor','none'); hold on; +% cartoon_pad_length = 0.5; +% [cartoon_time, cartoon_bout, cartoon_vigor, cartoon_swim] = make_cartoon_bout(cartoon_pad_length); +% reaf_cond=[[1;0;0;0;0], [1;0.225/0.001;0;0;0]]; +% plot_reaf_cond(reaf_cond, cartoon_time, cartoon_bout, cartoon_swim, cartoon_vigor, cartoon_pad_length, col_motor, col_sensory) +% line([0 0.5],[-20 -20],'color','k'); +% dm_fix_fig_fonts; +% clear i cartoon_pad_length cartoon_time cartoon_bout cartoon_vigor cartoon_swim cartoon_gr reaf_cond; +% +% % Fig. 4b: Example fish: individual trials +% lt_lag_TL=load([pathname_behavior 'long_term_adaptation_experiment/lag_trained/WT_TL_group/pooled_data.mat'],'behavior'); +% lt_lag_TL=lt_lag_TL.behavior; +% fish_num=40; +% fish_id=lt_lag_TL(fish_num).fish_id; +% [time_be, tail, grspeed]=get_example_fish(fish_id, pathname_behavior, 'long_term_adaptation_experiment/lag_trained/WT_TL_group/'); +% dt=time_be(2)-time_be(1); +% create_single_trial_axes('Fig. 4b'); +% ex_trial_num = [19:22 225:226 232:233]; +% set(gca,'ycolor','k','ytick',1:length(ex_trial_num),'yticklabel',flip(ex_trial_num),'ylim',[0.5 length(ex_trial_num)+0.5]); +% ylabel('trial #'); +% set(gcf,'position',[411 100 560 500]); +% c=0; +% for i=ex_trial_num +% c=c+1; +% [this_time, this_tail, ~, bout_starts, bout_ends] = get_example_trial_data(i,time_be,tail,grspeed,lt_lag_TL(fish_num)); +% this_tail=this_tail/5+length(ex_trial_num)+1-c; +% fill_bout (gca,bout_starts(1),bout_ends(1),-0.5+length(ex_trial_num)+1-c,0.5+length(ex_trial_num)+1-c,0.3); +% plot(this_time,this_tail,'color',col_motor,'linewidth',1); +% end +% show_lt_trials_lines(-7.4,-7.4,6.5,8.5,col_pre); +% show_lt_trials_lines(-7.4,-7.4,4.5,6.5,col_adapt_start); +% show_lt_trials_lines(-7.4,-7.4,2.5,4.5,col_adapt_end); +% show_lt_trials_lines(-7.4,-7.4,0.5,2.5,col_post); +% show_trial_start_and_end; +% dm_fix_fig_fonts; +% clear i fish_id c this_time this_tail bout_starts bout_ends time_be tail grspeed ex_trial_num; +% +% % Fig. 4c: All fish: first bout duration during all trials +% lt_norm_TL=load([pathname_behavior 'long_term_adaptation_experiment/normal_reafference_control/WT_TL_group/pooled_data.mat'],'behavior'); +% lt_norm_TL=lt_norm_TL.behavior; +% plot_long_term_adaptation('Fig. 4c',{lt_norm_TL, lt_lag_TL},'bout_duration','first',[col_norm_reaf; col_lag_trained],{'-', '-'},... +% col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post,[0.25 0.65]); +% dm_fix_fig_fonts; +% +% % Fig. 4d-f: Quantificication of acute reaction, back-to-baseline and after-effect +% p_value_lt_TL = nan(1,3); +% fig_names = {'Fig. 4d', 'Fig. 4e', 'Fig. 4f'}; +% temp_labels = {'(first 10 adaptation trials - pre) [s]','(last 10 adaptation trials - first 10 adaptation trials) [s]','(post - pre) [s]'}; +% temp_trial_num = {21:30, 221:230, 231:240}; +% temp_trial_num0 = {11:20, 21:30, 11:20}; +% for i=1:3 +% p_temp=make_lt_fbd_panel(fig_names{i},{'normalized first bout duration'; temp_labels{i}},{lt_norm_TL, lt_lag_TL},'bout_duration','first',temp_trial_num{i},[0 0 0],fish_num,temp_trial_num0{i}); +% dm_fix_fig_fonts; +% p_value_lt_TL(i) = p_temp(1,2); +% end +% clear temp_trial_num0 p_temp fish_num fig_names temp_labels temp_trial_num; +% +% % Fig. 4g: Bout power +% h=create_bout_power_axes('Fig. 4g',2); +% set(gcf,'position',[206 10 1034 420]); +% lt_norm_TL_bp=extract_bout_power(lt_norm_TL); +% lt_lag_TL_bp=extract_bout_power(lt_lag_TL); +% time_power=-0.1:dt:1-dt; +% h_bp_norm=plot_bout_power(h(1),time_power,lt_norm_TL_bp,[2 3 24],[col_pre; col_adapt_start; col_post]); +% h_bp_lag=plot_bout_power(h(2),time_power,lt_lag_TL_bp,[2 3 24],[col_pre; col_adapt_start; col_post]); +% y_lim=[0 4]; +% set(h,'ylim',y_lim,'ytick',0:4); +% y=[y_lim(2)-diff(y_lim)/10 y_lim(2)-diff(y_lim)/12]; +% h_bp=cat(3,h_bp_norm,h_bp_lag); +% cols=[col_adapt_start; col_post]; +% for k=1:2 % norm or lag +% for j=1:2 % acute or long-term +% for i=1:220 % time +% if h_bp(j,i,k) +% line(h(k),[time_power(i)-dt/2 time_power(i)+dt/2],[y(j) y(j)],'color',cols(j,:),'linewidth',3); +% end +% end +% end +% end +% ballistic_end=time_power(find(h_bp_lag(1,:),1)); +% ballistic_change_start=time_power(find(h_bp_lag(2,:),1)); +% ballistic_change_end=time_power(find(h_bp_lag(2,time_power<0.15),1,'last')); +% dm_fix_fig_fonts; +% clear lt_norm_TL lt_lag_TL y_lim y h_bp h_bp_norm h_bp_lag cols k j i h; +% +% % Fig. 4h: Quantification of acute reaction in ballistic power +% prepare_quantif_axes2('Fig. 4h'); +% data = prepare_data_for_bout_power_quantif({lt_norm_TL_bp, lt_lag_TL_bp},3,0.1/dt:(ballistic_end+0.1)/dt); +% p_value_lt_TL_acute_ballistic_power = plot_quantif(data,[0 0 0],{'normalized first bout ballistic power'; '(first 10 adaptation trials - pre) [au]'}); +% set(gca,'ylim',[-1 1]); +% dm_fix_fig_fonts; +% clear data; +% +% % Fig. 4i: Quantification of acute reaction in reactive power +% prepare_quantif_axes2('Fig. 4i'); +% data = prepare_data_for_bout_power_quantif({lt_norm_TL_bp, lt_lag_TL_bp},3,(ballistic_end+0.1)/dt+1:220); +% p_value_lt_TL_acute_reactive_power = plot_quantif(data,[0 0 0],{'normalized first bout reactive power'; '(first 10 adaptation trials - pre) [au]'}); +% dm_fix_fig_fonts; +% clear data; +% +% % Fig. 4j: Quantification of long-term adaptation of ballistic power +% prepare_quantif_axes2('Fig. 4j'); +% data = prepare_data_for_bout_power_quantif({lt_norm_TL_bp, lt_lag_TL_bp},24,(0.1+ballistic_change_start)/dt+1:(0.1+ballistic_change_end)/dt+1); +% p_value_lt_TL_aftereffect_ballistic_power = plot_quantif(data,[0 0 0],{'normalized first bout ballistic power'; '(post - pre) [au]'}); +% set(gca,'ylim',[-2 6]); +% dm_fix_fig_fonts; +% clear data lt_norm_TL_bp lt_lag_TL_bp; + + +%% Fig. 5: Long-term adaptation, but not acute reaction, is impaired after PC ablation +% % depends on Figure 4 +% % Fig. 5a: Experimental flow +% % created in illustrator +% +% % Fig. 5bi: All treatment control fish: first bout duration during all trials +% lt_norm_PC_neg=load([pathname_behavior 'long_term_adaptation_experiment/normal_reafference_control/treatment_control_group/pooled_data.mat'],'behavior'); +% lt_norm_PC_neg=lt_norm_PC_neg.behavior; +% lt_lag_PC_neg=load([pathname_behavior 'long_term_adaptation_experiment/lag_trained/treatment_control_group/pooled_data.mat'],'behavior'); +% lt_lag_PC_neg=lt_lag_PC_neg.behavior; +% plot_long_term_adaptation('Fig. 5bi',{lt_norm_PC_neg, lt_lag_PC_neg},'bout_duration','first',[col_norm_reaf; col_lag_trained],{'-', '-'},... +% col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post,[0.25 0.6]); +% dm_fix_fig_fonts; +% +% % Fig. 5bii: All PC-ablated fish: first bout duration during all trials +% lt_norm_PC_pos=load([pathname_behavior 'long_term_adaptation_experiment/normal_reafference_control/PC_ablated_group/pooled_data.mat'],'behavior'); +% lt_norm_PC_pos=lt_norm_PC_pos.behavior; +% lt_lag_PC_pos=load([pathname_behavior 'long_term_adaptation_experiment/lag_trained/PC_ablated_group/pooled_data.mat'],'behavior'); +% lt_lag_PC_pos=lt_lag_PC_pos.behavior; +% plot_long_term_adaptation('Fig. 5bii',{lt_norm_PC_pos, lt_lag_PC_pos},'bout_duration','first',[col_norm_reaf; col_lag_trained],{'-', '-'},... +% col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post,[0.25 0.6]); +% dm_fix_fig_fonts; +% +% % Fig. 5c: Quantification of acute reaction +% p_value_lt_PC_acute=make_lt_fbd_panel_PC('Fig. 5c',{'normalized first bout duration'; '(first 10 adaptation trials - pre) [s]'},{lt_norm_PC_neg, lt_lag_PC_neg, lt_norm_PC_pos, lt_lag_PC_pos},'bout_duration','first',21:30,[col_norm_reaf; col_lag_trained],'both'); +% dm_fix_fig_fonts; +% +% % Fig. 5d: Quantification of back to baseline effect +% p_value_lt_PC_back_to_baseline=make_lt_fbd_panel_PC('Fig. 5d',{'normalized first bout duration'; '(last 10 adaptation trials - first 10 adaptation trials) [s]'},{lt_norm_PC_neg, lt_lag_PC_neg, lt_norm_PC_pos, lt_lag_PC_pos},'bout_duration','first',221:230,[col_norm_reaf; col_lag_trained],'both',21:30); +% dm_fix_fig_fonts; +% +% % Fig. 5e: Quantification of after-effect +% p_value_lt_PC_after_effect=make_lt_fbd_panel_PC('Fig. 5e',{'normalized first bout duration'; '(post - pre) [s]'},{lt_norm_PC_neg, lt_lag_PC_neg, lt_norm_PC_pos, lt_lag_PC_pos},'bout_duration','first',231:240,[col_norm_reaf; col_lag_trained],'both'); +% dm_fix_fig_fonts; +% +% % Fig. 5f: Bout power +% h=create_bout_power_axes('Fig. 5f',2); +% set(gcf,'position',[206 10 1034 420]); +% y_lim=[0 4]; +% set(h,'ylim',y_lim); +% lt_norm_PC_neg_bp=extract_bout_power(lt_norm_PC_neg); +% lt_lag_PC_neg_bp=extract_bout_power(lt_lag_PC_neg); +% lt_PC_neg_bp=cat(3,lt_norm_PC_neg_bp,lt_lag_PC_neg_bp); +% lt_norm_PC_pos_bp=extract_bout_power(lt_norm_PC_pos); +% lt_lag_PC_pos_bp=extract_bout_power(lt_lag_PC_pos); +% lt_PC_pos_bp=cat(3,lt_norm_PC_pos_bp,lt_lag_PC_pos_bp); +% clear lt_norm_PC_neg_bp lt_lag_PC_neg_bp lt_norm_PC_pos_bp lt_lag_PC_pos_bp lt_lag_PC_neg lt_lag_PC_pos lt_norm_PC_neg lt_norm_PC_pos; +% h_lt_bp_PC_neg=plot_bout_power(h(1),time_power,lt_PC_neg_bp,[2 24],[col_pre; col_post]); +% h_lt_bp_PC_pos=plot_bout_power(h(2),time_power,lt_PC_pos_bp,[2 24],[col_pre; col_post]); +% y1=y_lim(2)-diff(y_lim)/10; +% y2=y_lim(2)-diff(y_lim)/12; +% for i=1:220 +% if h_lt_bp_PC_neg(i) +% line(h(1),[time_power(i)-dt/2 time_power(i)+dt/2],[y1 y1],'color',col_post,'linewidth',3); +% end +% if h_lt_bp_PC_pos(i) +% line(h(2),[time_power(i)-dt/2 time_power(i)+dt/2],[y2 y2],'color',col_post,'linewidth',3); +% end +% end +% dm_fix_fig_fonts; +% clear h_lt_bp_PC_neg h_lt_bp_PC_pos y_lim y1 y2 i h +% +% % Fig. 5g: Quantification of long-term adaptation of ballistic power +% prepare_quantif_axes2('Fig. 5g'); +% set(gca,'xticklabel',{'treatment control','PC-ablated'}); +% data = prepare_data_for_bout_power_quantif({lt_PC_neg_bp, lt_PC_pos_bp},24,(0.1+ballistic_change_start)/dt+1:(0.1+ballistic_change_end)/dt+1); +% p_value_lt_PC_aftereffect_ballistic_power = plot_quantif(data,[0 0 0],{'normalized first bout ballistic power'; '(post - pre) [au]'},[],'both'); +% set(gca,'ylim',[-2 6]); +% dm_fix_fig_fonts; +% clear data lt_PC_neg_bp lt_PC_pos_bp; + + +%% Fig. 6: Activity of a subpopulation of PCs can represent the output of an internal model +% % extract the data +% [all_fish, n_fish, n_control, n_good_lag, n_bad_lag,... +% tf_control_fish, tf_good_lag_fish, tf_bad_lag_fish,... +% tf_control_rois, tf_good_lag_rois, tf_bad_lag_rois, fish_id_rois,... +% Scores_be, Scores_im, ~,... +% Crit_im, Crit_im_signif,... +% Traces_bout_trig, ~, time_trig,... +% ROI_coord,sz_PC_ref,rez_PC_ref] = extract_PC_imaging_data(pathname_PC_imaging,pathname_reference_brains); +% fish_id_ex = '200303_f0'; +% fish_num_ex = find(strcmp(all_fish,fish_id_ex)); +% tf_mot_rois = Crit_im_signif(:,1)==1; +% tf_exp_rois = Crit_im_signif(:,1)==0 & Crit_im_signif(:,2)==-1 & Crit_im_signif(:,3)==0 & Crit_im_signif(:,4)==1; +% Data_temp_exp_rois = nan(n_fish,120); +% trig_data = compute_mean_trig_data(Traces_bout_trig); +% Trig_data_exp_rois = nan(n_fish,size(trig_data,2),size(trig_data,3)); +% for i=1:n_fish +% Data_temp_exp_rois(i,:)=nanmean(Scores_im(fish_id_rois==i & tf_exp_rois,:),1); +% Trig_data_exp_rois(i,:,:) = nanmean(trig_data(fish_id_rois==i & tf_exp_rois,:,:),1); +% end +% exp_roi_ids=find(tf_exp_rois & fish_id_rois==fish_num_ex); +% mot_roi_ids=find(tf_mot_rois & fish_id_rois==fish_num_ex); +% ex_roi_ids = [exp_roi_ids(16) mot_roi_ids(13)]; +% clear exp_roi_ids mot_roi_ids fish_num_ex all_fish +% +% % Fig. 6a: Schematics of the light-sheet setup +% % created in illustrator +% % inset with location of example ROIs +% tf_roi1=false(sz_PC_ref); +% tf_roi1(ROI_coord{ex_roi_ids(1)})=true; +% tf_roi1 = max(tf_roi1,[],3); +% tf_roi2=false(sz_PC_ref); +% tf_roi2(ROI_coord{ex_roi_ids(2)})=true; +% tf_roi2 = max(tf_roi2,[],3); +% r=255*ones(sz_PC_ref(1:2),'uint8'); +% g=r; b=r; +% g(tf_roi1)=0; +% b(tf_roi1)=0; +% r(tf_roi2)=0; +% g(tf_roi2)=0; +% A = cat(3,r,g,b); +% figure('name','Fig. 6a location of example ROIs'); +% imshow(A); +% dm_fix_fig_fonts; +% clear A tf_roi1 tf_roi2 r g b z_mm z1 z2 anat; +% +% % Fig. 6b: Experimental protocol +% % created in illustrator +% +% % Fig. 6c: Behavioral plots, divided into three groups +% p=plot_long_term_adaptation_PC_im('Fig. 6c',{Scores_be(tf_control_fish,:), Scores_be(tf_bad_lag_fish,:), Scores_be(tf_good_lag_fish,:)},[col_norm_reaf; col_lag_trained_bad; col_lag_trained],{'-','-','-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[0.2 0.8]); +% legend(p(1:3),{['control, N = ' num2str(sum(tf_control_fish))],['lag-trained non-adapting, N = ' num2str(sum(tf_bad_lag_fish))],['lag-trained adapting, N = ' num2str(sum(tf_good_lag_fish))]},'box','off','color','none'); +% dm_fix_fig_fonts; +% clear p Scores_be; +% +% % Fig. 6d: Computing criteria on two example ROIs +% % extract the data +% trials_to_show=[19 22 70 75 113]; +% load([pathname_PC_imaging 'behavior\' fish_id_ex '_behavior.mat'],'time_be','grspeed','tail','bouts','meta'); +% temp_struct.bouts=bouts; +% load([pathname_PC_imaging 'traces\' fish_id_ex '_traces.mat'],'traces','time_offsets'); +% time_im=(1/meta.F:1/meta.F:size(traces,2)/meta.F)+1/meta.F; +% time_im_roi1=time_im + time_offsets(ex_roi_ids(1)); +% time_im_roi2=time_im + time_offsets(ex_roi_ids(2)); +% clear time_im; +% % Fig. 6di: Two raw ROIs with tail and grating speed +% create_single_trial_axes('Fig. 6di'); +% set(gca,'ycolor','k','ytick',1:5,'yticklabel',flip(trials_to_show),'ylim',[0 length(trials_to_show)+1]); +% ylabel('trial #'); +% set(gcf,'position',[411 10 560 853]); +% c=0; +% for i=trials_to_show +% c=c+1; +% [this_time, this_tail, this_grspeed, bout_starts, bout_ends] = get_example_trial_data(i,time_be,tail,grspeed,temp_struct); +% this_tail=this_tail/20+length(trials_to_show)+1-c; +% this_grspeed=this_grspeed/120+length(trials_to_show)+1.1-c; +% fill_bout (gca,bout_starts(1),bout_ends(1),-0.5+length(trials_to_show)+1-c,0.5+length(trials_to_show)+1-c,0.3); +% plot(this_time,this_tail,'color',col_motor,'linewidth',1); +% plot(this_time,this_grspeed,'color',col_sensory,'linewidth',0.5); +% +% tf=time_im_roi1>(i-1)*30 & time_im_roi1<=i*30; +% this_trace = traces(ex_roi_ids(1),tf); +% this_trace = this_trace/10+length(trials_to_show)+0.9-c; +% this_time = time_im_roi1(tf); +% this_time=this_time-this_time(1)-7.5-1/meta.F/2; +% plot(this_time,this_trace,'color','r','linewidth',1); +% tf=time_im_roi2>(i-1)*30 & time_im_roi2<=i*30; +% this_trace = traces(ex_roi_ids(2),tf); +% this_trace = this_trace/10+length(trials_to_show)+0.7-c; +% this_time = time_im_roi2(tf); +% this_time=this_time-this_time(1)-7.5-1/meta.F/2; +% plot(this_time,this_trace,'color','b','linewidth',1); +% end +% show_lt_trials_lines(-7.4,-7.4,4.5,5.5,col_pre); +% show_lt_trials_lines(-7.4,-7.4,3.5,4.5,col_adapt_start); +% show_lt_trials_lines(-7.4,-7.4,2.5,3.5,col_adapt_end); +% show_lt_trials_lines(-7.4,-7.4,1.5,2.5,col_post_start); +% show_lt_trials_lines(-7.4,-7.4,0.5,1.5,col_post_end); +% line([-6 -6],[0 10]/120+length(trials_to_show)+1.1-c,'color','k'); +% line([-5 -5],[0 1]/10+length(trials_to_show)+0.7-c,'color','k'); +% show_trial_start_and_end; +% dm_fix_fig_fonts; +% clear this_trace tf this_time this_tail this_gr bout_starts bout_ends time_im_roi1 time_im_roi2 temp_struct; +% % Fig. 6dii: Triggered activity of these two ROIs +% figure('name','Fig. 6dii'); axes; hold on; +% set(gcf,'position',[411 10 300 853]); +% ylabel('trial #'); +% xlabel('time relative to first bout onset [s]'); +% set(gca,'xlim',[-0.8 1.2],'xtick',-0.8:0.4:1.2,'ycolor','k','ytick',1:5,'yticklabel',flip(trials_to_show),'ylim',[0 length(trials_to_show)+1]); +% c=0; +% for i=trials_to_show +% c=c+1; +% this_trace = Traces_bout_trig(ex_roi_ids(1),:,i); +% this_trace = this_trace/4+length(trials_to_show)+0.6-c; +% plot(time_trig,this_trace,'color','r','linewidth',1); +% this_trace = Traces_bout_trig(ex_roi_ids(2),:,i); +% this_trace = this_trace/4+length(trials_to_show)+0.6-c; +% plot(time_trig,this_trace,'color','b','linewidth',1); +% line([-0.8 1.2],[0 0]+length(trials_to_show)+0.6-c,'color','k','linestyle',':'); +% end +% show_lt_trials_lines(-0.95,-0.95,4.5,5.5,col_pre); +% show_lt_trials_lines(-0.95,-0.95,3.5,4.5,col_adapt_start); +% show_lt_trials_lines(-0.95,-0.95,2.5,3.5,col_adapt_end); +% show_lt_trials_lines(-0.95,-0.95,1.5,2.5,col_post_start); +% show_lt_trials_lines(-0.95,-0.95,0.5,1.5,col_post_end); +% line([-0.5 -0.5],[0 1]/4+length(trials_to_show)+0.6-c,'color','k'); +% show_trial_start_and_end; +% dm_fix_fig_fonts; +% clear this_trace trials_to_show Traces_bout_trig; +% % Fig. 6diii: Scores of these two ROIs +% cols=['r';'b']; +% plot_long_term_adaptation_PC_im('Fig. 6diii',{Scores_im(ex_roi_ids(1),:), Scores_im(ex_roi_ids(2),:)},cols,{'-','-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[0 4]); +% ylabel('bout-triggered response [sd]'); +% set(gca,'ytick',0:4); +% temp_filt=[Scores_im(ex_roi_ids(1),:); Scores_im(ex_roi_ids(2),:)]; +% for j=1:2 +% for i=5:length(temp_filt)-4 +% temp_filt(j,i)=nanmean(Scores_im(ex_roi_ids(j),i-4:i+4)); +% end +% plot(1:120,temp_filt(j,:),'color',cols(j),'linewidth',2); +% end +% dm_fix_fig_fonts; +% clear j temp_filt cols; +% % Fig. 6div: Criteria of these two ROIs +% figure('name','Fig. 6div'); +% axes('xlim',[0 4]+0.5,'xtick',1:4,'ylim',[0 2]+0.5,'ytick',1:2,'yticklabel',{'ROI 1','ROI 2'},'ydir','reverse'); hold on; +% xlabel('criterion #'); +% dm_imagesc(1:4,[Crit_im(ex_roi_ids(1),:); Crit_im(ex_roi_ids(2),:)]); +% line(xlim,[1.5 1.5],'color','k','linewidth',2); +% ylabel(colorbar,{'difference in responses [sd]'}); +% dm_fix_fig_fonts; +% clear Crit_im; +% % Fig. 6dv: Significant criteria of these two ROIs +% figure('name','Fig. 6dv'); +% axes('xlim',[0 4]+0.5,'xtick',1:4,'ylim',[0 2]+0.5,'ytick',1:2,'yticklabel',{'ROI 1','ROI 2'},'ydir','reverse'); hold on; +% xlabel('criterion #'); +% dm_imagesc(1:4,[Crit_im_signif(ex_roi_ids(1),:); Crit_im_signif(ex_roi_ids(2),:)]); +% line(xlim,[1.5 1.5],'color','k','linewidth',2); +% cl1=colormap; +% cl1=[cl1(1,:); cl1(32,:); cl1(end,:)]; +% colormap(gca,cl1); +% colorbar('ytick',[-0.6 0 0.6],'yticklabel',{'decrease','no change','increase'}); +% dm_fix_fig_fonts; +% clear cl1; +% % Fig. 6dvi: triggered responses of ROI1 +% plot_trigaver_PC('Fig. 6dvi',time_trig,trig_data(ex_roi_ids(1),:,:),col_pre, col_adapt_start, col_adapt_end, col_post_start, col_post_end,[-0.5 2]); +% dm_fix_fig_fonts; +% % Fig. 6dvii: triggered responses of ROI2 +% plot_trigaver_PC('Fig. 6dvii',time_trig,trig_data(ex_roi_ids(2),:,:),col_pre, col_adapt_start, col_adapt_end, col_post_start, col_post_end,[-0.5 4]); +% dm_fix_fig_fonts; +% +% % Fig. 6e: Clustering of ROIs +% % extract data +% clust_code='+-0'; +% signif_code=[1 -1 0]; +% clust_data=cell(81,7); +% % 1 - cluster code +% % 2 - ids of control ROIs +% % 3 - ids of bad lag ROIs +% % 4 - ids of good lag ROIs +% % 5 - fractions in control fish +% % 6 - fractions in bad lag fish +% % 7 - fractions in good lag fish +% data_fraction=nan(n_fish,81); +% p_values_PC_fraction = nan(81,1); +% c=0; +% for c1=1:3 +% for c2=1:3 +% for c3=1:3 +% for c4=1:3 +% c=c+1; +% clust_data{c,1}=[clust_code(c1) clust_code(c2) clust_code(c3) clust_code(c4)]; +% temp = ... +% Crit_im_signif(:,1)==signif_code(c1) & ... +% Crit_im_signif(:,2)==signif_code(c2) & ... +% Crit_im_signif(:,3)==signif_code(c3) & ... +% Crit_im_signif(:,4)==signif_code(c4); +% clust_data{c,2} = find(temp & tf_control_rois); +% clust_data{c,3} = find(temp & tf_bad_lag_rois); +% clust_data{c,4} = find(temp & tf_good_lag_rois); +% for f=1:n_fish +% temp2 = temp & fish_id_rois==f; +% if tf_control_fish(f) +% id = 5; +% elseif tf_bad_lag_fish(f) +% id = 6; +% elseif tf_good_lag_fish(f) +% id = 7; +% end +% clust_data{c,id} = [clust_data{c,id} sum(temp2)/sum(fish_id_rois==f)*100]; +% end +% data_fraction(:,c)=[clust_data{c,5}'; clust_data{c,6}'; clust_data{c,7}']; +% p_values_PC_fraction(c,1) = kruskalwallis(data_fraction(:,c),[ones(n_control,1);2*ones(n_bad_lag,1);3*ones(n_good_lag,1)],'off'); +% end +% end +% end +% end +% Crit_im_signif_sorted=[]; +% Scores_im_sorted=[]; +% interesting_cluster_id = find(strcmp(clust_data(:,1),'0-0+')); +% line_start = []; +% line_end = []; +% cc=0; +% n=zeros(3,1); +% for g=2:4 +% cc=cc+1; +% for c=1:81 +% n(cc)=n(cc)+length(clust_data{c,g}); +% if c==interesting_cluster_id +% line_start = [line_start size(Crit_im_signif_sorted,1)]; %#ok +% end +% Crit_im_signif_sorted=[Crit_im_signif_sorted; Crit_im_signif(clust_data{c,g},:)]; %#ok +% Scores_im_sorted=[Scores_im_sorted; Scores_im(clust_data{c,g},:)]; %#ok +% if c==interesting_cluster_id +% line_end = [line_end size(Crit_im_signif_sorted,1)]; %#ok +% end +% end +% end +% n=[1; n]; +% clear g cc interesting_cluster_id id temp2 temp c1 c2 c3 c4 signif_code clust_code Crit_im_signif; +% +% % Fig. 6ei: Clustering of all ROIs within 3 groups of fish (plot crit signif) +% figure('name','Fig. 6ei'); +% set(gcf,'position',[680 20 159 420]); +% for i=1:3 +% subplot(3,1,i,'xlim',[0 4]+0.5,'xtick',1:4,'xticklabel',[],'ytick',[],'ydir','reverse'); hold on; +% ylabel('ROIs'); +% dm_imagesc(1:4,Crit_im_signif_sorted(sum(n(1:i)):sum(n(2:i+1)),:)); +% end +% xlabel('criterion #'); +% line([0 4]+0.5,[line_start(3) line_start(3)]-(n(2)+n(3))+0.5,'color','k','linewidth',1); +% line([0 4]+0.5,[line_end(3) line_end(3)]-(n(2)+n(3))+0.5,'color','k','linewidth',1); +% dm_fix_fig_fonts; +% % Fig. 6eii: Fraction of ROIs in individual fish +% c_lim=[0 10]; +% useless_clust = max([mean(data_fraction(1:n_control,:),1); mean(data_fraction(n_control+1:n_control+n_bad_lag,:),1); mean(data_fraction(n_control+n_bad_lag+1:n_fish,:),1)],[],1)<2; +% data_fraction(:,useless_clust)=[]; +% clust_data(useless_clust,:)=[]; +% p_values_PC_fraction(useless_clust)=[]; +% good_cluster_id=find(p_values_PC_fraction<0.05); +% figure('name','Fig. 6eii'); +% set(gcf,'position',[990 20 290 420]); +% n_temp = [1 n_control n_bad_lag n_good_lag]; +% for i=1:3 +% subplot(3,1,i,'xlim',[0 size(data_fraction,2)]+0.5,'ylim',[0 n_temp(i)]+0.5,'ydir','reverse','xtick',1:size(data_fraction,2),'xticklabel',[],'ytick',[]); hold on; +% ylabel('fish'); +% dm_imagesc(1:size(data_fraction,2),data_fraction(sum(n_temp(1:i)):sum(n_temp(2:i+1)),:)); +% line([good_cluster_id good_cluster_id]-0.5,ylim,'color','k'); +% line([good_cluster_id good_cluster_id]+0.5,ylim,'color','k'); +% colormap(flip(bone)); +% set(gca,'clim',c_lim); +% colorbar; +% end +% set(gca,'xticklabel',clust_data(:,1)); +% xtickangle(45); +% dm_fix_fig_fonts; +% clear good_cluster_id useless_clust line_start line_end Crit_im_signif_sorted Scores_im_sorted data_fraction clust_data; +% +% % Fig. 6f: Responses of 0-0+ ROIs +% % Fig. 6fi top: Scores of individual ROIs +% c_lim=[-1 3]; +% data_temp = Scores_im(tf_exp_rois,:); +% data_temp(isnan(data_temp))=nanmean(data_temp(:)); +% data_temp=data_temp(randperm(size(data_temp,1)),:); +% figure('name','Figure 6fi top'); +% imagesc_scores(1:2,data_temp,c_lim,col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end); +% xlabel('trial #'); +% set(gca,'xticklabelmode','auto'); +% dm_fix_fig_fonts; +% % Fig. 6fi bottom: Scores averaged across fish +% plot_long_term_adaptation_PC_im('Fig. 6fi bottom',{Data_temp_exp_rois(tf_good_lag_fish,:)},'k',{'-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[0 1.5]); +% ylabel('bout-triggered response [sd]'); +% dm_fix_fig_fonts; +% clear data_temp c_lim Data_temp_exp_rois Scores_im tf_control tf_bad_lag_fish; +% % Fig. 6fii: Triggered avearges, mean across good lag fish +% plot_trigaver_PC('Fig. 6fii',time_trig,Trig_data_exp_rois(tf_good_lag_fish,:,:),col_pre, col_adapt_start, col_adapt_end, col_post_start, col_post_end,[-0.5 2]); +% dm_fix_fig_fonts; +% clear ex_roi_ids Trig_data_exp_rois trig_data tf_good_lag_fish time_trig; +% +% % Fig. 6g: Spatial organisation of 0-0+ ROIs +% % control fish +% A=build_PC_map(sz_PC_ref,rez_PC_ref,n_fish,n_control,tf_control_rois,tf_exp_rois,fish_id_rois,ROI_coord,1); +% show_PC_map('Fig. 6g control',A,rez_PC_ref,50); +% dm_fix_fig_fonts; +% % bad lag fish (nonadapting) +% A=build_PC_map(sz_PC_ref,rez_PC_ref,n_fish,n_bad_lag,tf_bad_lag_rois,tf_exp_rois,fish_id_rois,ROI_coord,1); +% show_PC_map('Fig. 6g bad lag',A,rez_PC_ref,50); +% dm_fix_fig_fonts; +% % good lag fish (adapting) +% A=build_PC_map(sz_PC_ref,rez_PC_ref,n_fish,n_good_lag,tf_good_lag_rois,tf_exp_rois,fish_id_rois,ROI_coord,1); +% show_PC_map('Fig. 6g good lag',A,rez_PC_ref,50); +% dm_fix_fig_fonts; + + +%% Fig. 7: A cerebellar internal model calibrates a feedback controller involved in sensorimotor control +% load the data +[sz, rez] = read_nrrd_metadata([pathname_reference_brains 'PortuguesLab_wholebrain_ref_gamma_masked.nrrd']); +all_fish = dm_dir([pathname_whole_brain_imaging_lta 'processed_data\*_f*_processed_data.mat']); +all_fish = strrep(all_fish,'_processed_data.mat',''); +n_fish = length(all_fish); +ROI_coord_all = cell(n_fish,1); +n_ROIs_all = zeros(n_fish,1); +sensmot_clust_all = cell(n_fish,1); +traces_gr_trig_all = cell(n_fish,1); +traces_bout_trig_all = cell(n_fish,1); +time_constants_all = cell(n_fish,1); +time_constants_trials_all = cell(n_fish,1); +group = nan(n_fish,1); +load([pathname_whole_brain_imaging_lta 'processed_data\' all_fish{1} '_processed_data.mat'],'time_trig') +progressbar('Loading data for Fig. 7...'); +for f = 1:n_fish + fish_id = all_fish{f}; + load([pathname_whole_brain_imaging_lta 'ROIs\' fish_id '_ROIs.mat'],'ROI_coord'); + ROI_coord_all{f} = ROI_coord; + n_ROIs_all(f) = length(ROI_coord); + load([pathname_whole_brain_imaging_lta 'processed_data\' fish_id '_processed_data.mat'],'traces_gr_trig_mean','traces_bout_trig_mean','sensmot_clust','time_constants'); + traces_gr_trig_all{f} = traces_gr_trig_mean; + traces_bout_trig_all{f} = traces_bout_trig_mean; + sensmot_clust_all{f} = sensmot_clust; + time_constants_all{f} = nanmean(time_constants,2); + time_constants_trials_all{f} = time_constants; + load([pathname_whole_brain_imaging_lta 'behavior\' fish_id '_behavior.mat'],'meta') + switch meta.group + case 'control' + group(f) = 1; + case 'lag-trained non-adapting' + group(f) = 2; + case 'lag-trained adapting' + group(f) = 3; + end + progressbar(f/n_fish); +end +my_colormap=hot(64); +my_colormap=my_colormap(round(linspace(1,64,sum(group==3)+1)),:); + +% Fig. 7a: change in taus +tau_change1 = []; +tau_change2 = []; +tau_change3 = []; +x = -10:0.01:10; +for f=1:n_fish + tau_change = time_constants_trials_all{f}(:,7) - time_constants_trials_all{f}(:,3); + pd = fitdist(tau_change,'kernel','width',0.1); + tau_change = pdf(pd,x); + tau_change = tau_change/sum(tau_change); + switch group(f) + case 1 + tau_change1 = [tau_change1; tau_change]; + case 2 + tau_change2 = [tau_change2; tau_change]; + case 3 + tau_change3 = [tau_change3; tau_change]; + end +end +figure('name','Fig. 7a'); +axes; hold on; +fill([x flip(x)], [nanmean(tau_change1,1) - nanstd(tau_change1,[],1)/sqrt(size(tau_change1,1)) flip(nanmean(tau_change1,1) + nanstd(tau_change1,[],1)/sqrt(size(tau_change1,1)))],col_norm_reaf,'edgecolor','none','facealpha',0.3); +plot(x,nanmean(tau_change1,1),'color',col_norm_reaf,'linewidth',2,'linestyle',':'); +fill([x flip(x)], [nanmean(tau_change2,1) - nanstd(tau_change2,[],1)/sqrt(size(tau_change2,1)) flip(nanmean(tau_change2,1) + nanstd(tau_change2,[],1)/sqrt(size(tau_change2,1)))],col_lag_trained_bad,'edgecolor','none','facealpha',0.3); +plot(x,nanmean(tau_change2,1),'color',col_lag_trained_bad,'linewidth',2,'linestyle',':'); +fill([x flip(x)], [nanmean(tau_change3,1) - nanstd(tau_change3,[],1)/sqrt(size(tau_change3,1)) flip(nanmean(tau_change3,1) + nanstd(tau_change3,[],1)/sqrt(size(tau_change3,1)))],col_lag_trained,'edgecolor','none','facealpha',0.3); +plot(x,nanmean(tau_change3,1),'color',col_lag_trained,'linewidth',2,'linestyle',':'); +xlabel('change in tau (criterion 2) [s]'); +ylabel('probability'); +set(gca,'xlim',[-4 4]); +dm_fix_fig_fonts; + +% maps of cells with crit 2<-0.4 +for gg=1:3 + % Fig. 7b: map of all sensors + % compute stacks with fraction of ROIs + A_sens = zeros(sz,'uint8'); + for f = 1:n_fish + if group(f)==gg + tau_change = time_constants_trials_all{f}; + crit2 = tau_change(:,7) - tau_change(:,3); + for i = 1:n_ROIs_all(f) + coord = ROI_coord_all{f}{i}; + if crit2(i)<-0.4 + A_sens(coord) = A_sens(coord) + 1; + end + end + end + end + % compute top and side views + [top_view_sens, side_view_sens]=three_orthogonal_views(A_sens,rez(1)); + top_view_sens=1-top_view_sens/sum(group==gg); + side_view_sens=1-round(side_view_sens)/sum(group==gg); + % plot top and side views of the fractions of sensory ROIs + figure('name',['Fig. 7b top g' num2str(gg)]); + axes('xcolor','none','ycolor','none','ydir','reverse','clim',[0 1],'xlim',[1 sz(2)],'ylim',[1 sz(1)]); hold on; + pbaspect([1 sz(1)/sz(2) 1]); + imagesc(top_view_sens); + colormap(my_colormap); + figure('name',['Fig. 7b side g' num2str(gg)]); + axes('xcolor','none','ycolor','none','ydir','reverse','clim',[0 1],'xlim',[1 round(sz(3)/rez(2))],'ylim',[1 sz(1)]); hold on; + pbaspect([1 sz(1)/round(sz(3)/rez(2)) 1]); + imagesc(side_view_sens); + colormap(my_colormap); +end +figure('name','Fig. 7b colormap'); +axes('ycolor','none','xcolor','none'); +colormap(flip(hot(64),1)); +clrbr=colorbar; +clrbr.Ticks=0:0.2:1; +ylabel(clrbr,{'percentage of fish';'with activity'}); +dm_fix_fig_fonts; + + +%% Extended Data Fig. 1: Behavior of the feedback control model of acute reaction +% figure('name','Extended Data Fig. 1'); +% set(gcf,'position',[188 20 1547 365]); +% par_trial=[0.161, 0.15, 2.8, 2.5, 0.8, 0.9, 0.5, 0.6]; +% dt=0.005; +% par_trial(3)=dt/par_trial(3); +% par_trial(8)=dt/par_trial(8); +% reaf_trial=ones(7,5).*[1 0 0 0 0]; % all bouts with normal reafference +% [swim,grspeed,brain_state]=model_v3_real_trial (par_trial, dt, reaf_trial, 3); +% int_gr=zeros(1,length(swim)); +% int_gr(3/dt:18/dt)=10; +% axes('ycolor','none','xlim',[1 length(swim)],'xtick',[1 3/dt:5/dt:(3+15)/dt length(swim)],'xticklabel',[-3 0 5 10 15 15+3]); hold on +% +% plot(int_gr/10*2,'color',col_sensory); +% plot(swim*2-4,'color',col_motor); +% plot(brain_state(1,:)/10*2 - 8,'color',col_activity) +% plot(brain_state(2,:)/20*2 - 12,'color',col_activity) +% for i=3:5 +% plot(brain_state(i,:)*5 - 4*(i+1),'color',col_activity) +% end +% plot(grspeed/10*2-4*(i+2),'color',col_sensory); +% drawnow; +% bs=find(diff([0 swim])==1); +% be=find(diff([swim 0])==-1); +% for i=1:length(bs) +% fill([bs(i) be(i) be(i) bs(i)],[-1 -1 1 1],'k'); +% end +% dm_fix_fig_fonts; + + +%% Extended Data Fig. 2: Anatomical location of sensory- and motor-related ROIs is consistent across fish +% % load the data +% load([pathname_whole_brain_imaging_integrators 'significant_ROIs.mat'],'signif_ROIs'); +% [sz, rez] = read_nrrd_metadata([pathname_reference_brains 'PortuguesLab_wholebrain_ref_gamma_masked.nrrd']); +% all_fish = dm_dir([pathname_whole_brain_imaging_integrators 'behavior\*_f*_behavior.mat']); +% all_fish = strrep(all_fish,'_behavior.mat',''); +% n_fish = length(all_fish); +% ROI_coord_all = []; +% sensmot_clust_all = []; +% time_constants_all = []; +% progressbar('Loading data for Extended Data Fig. 2...'); +% for f = 1:n_fish +% fish_id = all_fish{f}; +% load([pathname_whole_brain_imaging_integrators 'ROIs\' fish_id '_ROIs.mat'],'ROI_coord'); +% ROI_coord_all = [ROI_coord_all; ROI_coord]; +% load([pathname_whole_brain_imaging_integrators 'clustering\' fish_id '_clustering.mat'],'sensmot_clust'); +% sensmot_clust_all = [sensmot_clust_all; sensmot_clust]; +% load([pathname_whole_brain_imaging_integrators 'time_constants\' fish_id '_time_constants.mat'],'time_constants'); +% time_constants_all = [time_constants_all; time_constants]; +% progressbar(f/n_fish); +% end +% tf_clust = false(length(ROI_coord_all),1); +% tf_clust(sensmot_clust_all==1 & time_constants_all>1.5,1)=true; +% tf_clust(sensmot_clust_all==2,2)=true; +% tf_clust(sensmot_clust_all==1 & time_constants_all<=1.5,3)=true; +% clear time_constants_all sensmot_clust_all time_constants sensmot_clust ROI_coord fish_id n_fish all_fish +% +% % Extended Data Fig. 2a: Anatomical reference +% % morphing anatomical regions from the Z-brain atlas +% all_regions=dm_dir([pathname_reference_brains 'morphed_regions_from_ZBrain_atlas\*.mat']); +% ref_brain_mask = nrrdread([pathname_reference_brains 'PortuguesLab_wholebrain_ref_mask.nrrd']); +% temp_tf=ref_brain_mask==0; +% for i=1:length(all_regions) +% load([pathname_reference_brains 'morphed_regions_from_ZBrain_atlas\' all_regions{i}],'A'); +% A(temp_tf)=false; +% [top_view,side_view]=three_orthogonal_views(A,rez(2)); +% top_view=255-uint8(top_view*255); +% side_view=255-uint8(side_view*255); +% panel_name=strrep(all_regions{i},'.mat',''); +% figure('name',['Extended Data Fig. 2a ' strrep(all_regions{i},'.mat','') ' top']); +% imshow(top_view); +% figure('name',['Extended Data Fig. 2a ' strrep(all_regions{i},'.mat','') ' side']); +% imshow(side_view); +% end +% clear A temp_tf ref_brain_mask all_regions A coord top_view side_view; +% +% % Extended Data Fig. 2b: Consistent anatomical regions +% r=ones(sz); +% g=ones(sz); +% b=ones(sz); +% cols=[col_integrators;col_motor;col_sensors]; +% for i=1:3 +% coord=ROI_coord_all(tf_clust(:,i) & signif_ROIs); +% for ii=1:length(coord) +% this_coord=coord{ii}; +% r(this_coord)=cols(i,1); +% g(this_coord)=cols(i,2); +% b(this_coord)=cols(i,3); +% end +% end +% top_view = cat(3,sum(r,3),sum(g,3),sum(b,3)); +% top_view = top_view/max(top_view(:)); +% HSV = rgb2hsv(top_view); +% HSV(:,:,2) = min(HSV(:,:,2)*1.7,1); +% top_view = hsv2rgb(HSV); +% side_view = cat(3,squeeze(sum(r,2)),squeeze(sum(g,2)),squeeze(sum(b,2))); +% side_view=imresize3(side_view,[sz(1),round(sz(3)/rez(1)),3]); +% side_view=flip(side_view,2); +% side_view = side_view/max(side_view(:)); +% HSV = rgb2hsv(side_view); +% HSV(:,:,2) = min(HSV(:,:,2)*1.5,1); +% side_view = hsv2rgb(HSV); +% figure('name','Extended Data Fig. 2b top'); +% imshow(top_view); +% figure('name','Extended Data Fig. 2b side'); +% imshow(side_view); +% clear HSV this_coord coord cols r g b side_view top_view tf_clust ROI_coord_all sz rez; + + +%% Extended Data Fig. 3: Treatment of Tg(PC:epNtr-tagRFP) larvae with metronidazole ablates the PCs +% % Extended Data Fig. 3a-c: confocal images +% % created in illustrator +% % Extended Data Fig. 3d: entropy +% A = readmatrix([pathname_MS_data 'PC_ablation_quantification\PC_ablation_quantification_entropy_x.csv'],'range','E2:F13'); +% g = readmatrix([pathname_MS_data 'PC_ablation_quantification\PC_ablation_quantification_entropy_x.csv'],'range','B2:B13','output','string'); +% A(8,:) = []; % discarded due to unstable acquisition that affects entropy computations +% g(8) = []; +% g = g=='-'; +% figure('name','Extended Data Fig. 3d'); +% axes('xlim',[0.6 2.4],'xtick',[1 2],'xticklabel',{'before treatment','after treatment'}); hold on; +% ylabel('entropy [bits]'); +% ids = find(g)'; +% scatter(ones(length(ids),1)-0.05,A(ids,1),10,'markerfacecolor',[0 0 0],'markeredgecolor','none'); +% scatter(2*ones(length(ids),1)-0.05,A(ids,2),10,'markerfacecolor',[0 0 0],'markeredgecolor','none'); +% for i=ids +% line([1 2]-0.05,[A(i,1) A(i,2)],'color','k','linestyle',':'); +% end +% line([-0.05 0.05]+1-0.05,[1 1]*median(A(ids,1)),'color','k'); +% line([0 0]+1-0.05,[prctile(A(ids,1),25) prctile(A(ids,1),75)],'color','k'); +% line([-0.05 0.05]+2-0.05,[1 1]*median(A(ids,2)),'color','k'); +% line([0 0]+2-0.05,[prctile(A(ids,2),25) prctile(A(ids,2),75)],'color','k'); +% +% ids = find(~g)'; +% scatter(ones(length(ids),1)+0.05,A(ids,1),10,'markerfacecolor',col_PC,'markeredgecolor','none'); +% scatter(2*ones(length(ids),1)+0.05,A(ids,2),10,'markerfacecolor',col_PC,'markeredgecolor','none'); +% for i=ids +% line([1 2]+0.05,[A(i,1) A(i,2)],'color',col_PC,'linestyle',':'); +% end +% line([-0.05 0.05]+1+0.05,[1 1]*median(A(ids,1)),'color',col_PC); +% line([0 0]+1+0.05,[prctile(A(ids,1),25) prctile(A(ids,1),75)],'color',col_PC); +% line([-0.05 0.05]+2+0.05,[1 1]*median(A(ids,2)),'color',col_PC); +% line([0 0]+2+0.05,[prctile(A(ids,2),25) prctile(A(ids,2),75)],'color',col_PC); +% dm_fix_fig_fonts; + +%% Extended Data Fig. 4: Acute reaction is not impaired after PC ablation +acute_PC_neg=load([pathname_behavior 'acute_reaction_experiment/treatment_control_group/pooled_data.mat'],'behavior'); +acute_PC_neg=acute_PC_neg.behavior; +acute_PC_pos=load([pathname_behavior 'acute_reaction_experiment/PC_ablated_group/pooled_data.mat'],'behavior'); +acute_PC_pos=acute_PC_pos.behavior; +data={acute_PC_neg acute_PC_pos}; +panel_names={'Extended Data Fig. 4i', 'Extended Data Fig. 4ii', 'Extended Data Fig. 4iii', 'Extended Data Fig. 4iv'; 'Extended Data Fig. 4v', 'Extended Data Fig. 4vi', 'Extended Data Fig. 4vii', 'Extended Data Fig. 4viii'}; +cond_names={'gain', 'lag', 'shunted_lag', 'gain_drop'}; +par_names={'bout_duration';'next_interbout_duration'}; +x_labels={'gain','lag [ms]','shunted lag [ms]','gain profile'}; +y_labels={'mean bout duration [s]'; 'mean interbout duration [s]'}; +y_lims=[0.3 0.6; 0.8 2]; +for i=1:2 + for c=1:4 + plot_acute_complete_PC(panel_names{i,c},data,cond_names{c},par_names{i},[0 0 0; col_PC],x_labels{c},y_labels{i},y_lims(i,:)); + dm_fix_fig_fonts; + end +end +clear acute_PC_neg acute_PC_pos i c panel_names cond_names par_names x_labels y_labels; + + +%% Extended Data Fig. 5: Long-term adaptation effects are detectable in the light-sheet functional imaging experiment +% % extract the data +% [~, n_fish, n_control, n_good_lag, n_bad_lag,... +% tf_control_fish, tf_good_lag_fish, tf_bad_lag_fish,... +% ~, ~, ~, ~,... +% Scores_be] = extract_PC_imaging_data(pathname_PC_imaging,pathname_reference_brains); +% Scores_be_blocks = nan(n_fish,12); +% c=0; +% for i=1:10:111 +% c=c+1; +% Scores_be_blocks(:,c)=nanmean(Scores_be(:,i:i+9),2); +% end +% +% % Extended Data Fig. 5a: experimental protocol +% % taken from Fig. 6b +% +% % Extended Data Fig. 5b: First bout duration in all trials +% fig_names = {'Extended Data Fig. 5bi','Extended Data Fig. 5bii','Extended Data Fig. 5biii'}; +% temp = {Scores_be(tf_control_fish,:),Scores_be(tf_bad_lag_fish,:),Scores_be(tf_good_lag_fish,:)}; +% temp_cols = [col_norm_reaf;col_lag_trained_bad;col_lag_trained]; +% for i=1:3 +% plot_long_term_adaptation_PC_im(fig_names{i},temp(i),temp_cols(i,:),{'-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[0.2 0.9]); +% set(gca,'ytick',0.2:0.1:0.9); +% dm_fix_fig_fonts; +% end +% +% % Extended Data Fig. 5c: First bout duration in all trials +% % Extended Data Fig. 5ci: Acute reaction +% figure('name','Extended Data Fig. 5ci'); +% axes('ylim',[-0.5 0.5],'ytick',-0.5:0.25:0.5,'xlim',[0 4],'xtick',1:3,'xticklabel',{'control','lag-trained non adapting','lag-trained adapting'}); hold on; +% xtickangle(45); +% p_value_PC_LS_acute = plot_quantif({Scores_be_blocks(tf_control_fish,3)-Scores_be_blocks(tf_control_fish,2),Scores_be_blocks(tf_bad_lag_fish,3)-Scores_be_blocks(tf_bad_lag_fish,2),Scores_be_blocks(tf_good_lag_fish,3)-Scores_be_blocks(tf_good_lag_fish,2)},'k','normalized mean bout duration [s]',[],'right'); +% dm_fix_fig_fonts; +% % Extended Data Fig. 5cii: Back-to-baseline affect +% figure('name','Extended Data Fig. 5cii'); +% axes('ylim',[-0.5 0.5],'ytick',-0.5:0.25:0.5,'xlim',[0 4],'xtick',1:3,'xticklabel',{'control','lag-trained non adapting','lag-trained adapting'}); hold on; +% xtickangle(45); +% p_value_PC_LS_back_to_base = plot_quantif({Scores_be_blocks(tf_control_fish,7)-Scores_be_blocks(tf_control_fish,3),Scores_be_blocks(tf_bad_lag_fish,7)-Scores_be_blocks(tf_bad_lag_fish,3),Scores_be_blocks(tf_good_lag_fish,7)-Scores_be_blocks(tf_good_lag_fish,3)},'k','normalized mean bout duration [s]',[],'right'); +% dm_fix_fig_fonts; +% % Extended Data Fig. 5ciii: After-effect +% figure('name','Extended Data Fig. 5ciii'); +% axes('ylim',[-0.5 0.5],'ytick',-0.5:0.25:0.5,'xlim',[0 4],'xtick',1:3,'xticklabel',{'control','lag-trained non adapting','lag-trained adapting'}); hold on; +% xtickangle(45); +% p_value_PC_LS_aftereffect = plot_quantif({Scores_be_blocks(tf_control_fish,8)-Scores_be_blocks(tf_control_fish,2),Scores_be_blocks(tf_bad_lag_fish,8)-Scores_be_blocks(tf_bad_lag_fish,2),Scores_be_blocks(tf_good_lag_fish,8)-Scores_be_blocks(tf_good_lag_fish,2)},'k','normalized mean bout duration [s]',[],'right'); +% dm_fix_fig_fonts; +% clear fig_names temp temp_cols n_fish n_control n_good_lag n_bad_lag tf_control_fish tf_good_lag_fish tf_bad_lag_fish Scores_be Scores_be_blocks c + + +%% Extended Data Fig. 6: Activity of 0-0+ ROIs cannot be explained by behavior +% % extract the data +% [all_fish, n_fish, ~, ~, ~,... +% ~, tf_good_lag_fish, ~,... +% ~, ~, ~, fish_id_rois,... +% Scores_be, Scores_im, Scores_mr,... +% ~, Crit_taus_signif,... +% Traces_bout_trig, Traces_mr_bout_trig, time_trig] = extract_PC_imaging_data(pathname_PC_imaging,pathname_reference_brains); +% fish_id_ex = '200303_f0'; +% fish_num_ex = find(strcmp(all_fish,fish_id_ex)); +% load([pathname_PC_imaging 'behavior\' fish_id_ex '_behavior.mat'],'time_be','grspeed','tail','bouts','meta'); +% tf_exp_rois = Crit_taus_signif(:,1)==0 & Crit_taus_signif(:,2)==-1 & Crit_taus_signif(:,3)==0 & Crit_taus_signif(:,4)==1; +% tf_mot_rois = Crit_taus_signif(:,1)==1; +% Data_temp_exp_rois = nan(n_fish,120); +% Data_temp_mot_rois = nan(n_fish,120); +% trig_data = compute_mean_trig_data(Traces_bout_trig); +% Trig_data_mot_rois = nan(n_fish,size(trig_data,2),size(trig_data,3)); +% Trig_data_exp_rois = nan(n_fish,size(trig_data,2),size(trig_data,3)); +% for i=1:n_fish +% Data_temp_mot_rois(i,:)=nanmean(Scores_im(fish_id_rois==i & tf_mot_rois,:),1); +% Data_temp_exp_rois(i,:)=nanmean(Scores_im(fish_id_rois==i & tf_exp_rois,:),1); +% Trig_data_mot_rois(i,:,:) = nanmean(trig_data(fish_id_rois==i & tf_mot_rois,:,:),1); +% Trig_data_exp_rois(i,:,:) = nanmean(trig_data(fish_id_rois==i & tf_exp_rois,:,:),1); +% end +% Trig_data_mr = compute_mean_trig_data(Traces_mr_bout_trig); +% clear trig_data n_fish all_fish fish_id_rois Scores_im Crit_im_signif Traces_bout_trig Traces_mr_bout_trig tf_exp_rois tf_mot_rois +% +% % Extended Data Fig. 6a: Motor regressor in some example trials +% trials_to_show = 19:22; +% tf=time_be>(trials_to_show(1)-1)*30 & time_be<=trials_to_show(end)*30; +% dt=time_be(2)-time_be(1); +% this_tail=tail(tf); +% this_grspeed=grspeed(tf); +% this_grspeed(1:10)=0; +% this_grspeed(end-9:end)=0; +% this_grspeed(end/2-10:end/2+10)=0; +% this_time=time_be(tf); +% bout_starts = nan(length(trials_to_show),1); +% bout_ends=bout_starts; +% c=0; +% for i=trials_to_show +% c=c+1; +% id=find(bouts.trial==i,1); +% bout_starts(c)=bouts.start(id); +% bout_ends(c)=bouts.end(id); +% end +% load([pathname_PC_imaging 'traces\' fish_id_ex '_traces.mat'],'trace_motor_regr'); +% time_im=1/meta.F:1/meta.F:length(trace_motor_regr)/meta.F; +% tf=time_im>(trials_to_show(1)-1)*30 & time_im<=trials_to_show(end)*30; +% trace_motor_regr=trace_motor_regr(tf); +% time_im=time_im(tf); +% figure('name','Extended Data Fig. 6a'); +% set(gcf,'position',[109 20 1647 420]); +% axes('ycolor','none','xlim',[this_time(1)-dt this_time(end)]/60); hold on; +% xlabel('time in experiment [min]'); +% plot(this_time/60,this_tail,'color',col_motor,'linewidth',1); +% plot(this_time/60,this_grspeed/7-5,'color',col_sensory,'linewidth',0.5); +% plot(time_im/60,trace_motor_regr*2-10,'color','k','linewidth',0.5); +% line([9.1 9.1],[-7 -5]*2,'color','k'); +% drawnow; y_lim=get(gca,'ylim'); +% show_lt_trials_lines(9,10,y_lim(2),y_lim(2),col_pre); +% show_lt_trials_lines(10,11,y_lim(2),y_lim(2),col_adapt_start); +% for i=1:length(trials_to_show) +% fill_bout (gca,bout_starts(i)/60,bout_ends(i)/60,y_lim(1),y_lim(2),0.3); +% end +% dm_fix_fig_fonts; +% clear y_lim tail id grspeed fish_id_ex tf meta time_im trace_motor_regr bouts bout_ends bout_starts time_be this_time this_gr this_tail trials_to_show tf dt +% +% % Extended Data Fig. 6b: Behavior +% plot_long_term_adaptation_PC_im('Extended Data Fig. 6 top',{Scores_be(fish_num_ex,:)},'k',{'-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[0.2 1.2]); +% set(gca,'ytick',0.2:0.2:1.2); +% dm_fix_fig_fonts; +% plot_long_term_adaptation_PC_im('Extended Data Fig. 6 bottom',{Scores_be(tf_good_lag_fish,:)},'k',{'-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[0 1.2],true); +% set(gca,'ytick',0:0.2:1.2); +% dm_fix_fig_fonts; +% clear Scores_be; +% +% % Extended Data Fig. 6c: Responses of motor regressors +% plot_long_term_adaptation_PC_im('Extended Data Fig. 6c top left',{Scores_mr(fish_num_ex,:)},'k',{'-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[0.4 1.6]); +% set(gca,'ytick',0.4:0.2:1.6); +% ylabel('bout-triggered response [sd]'); +% dm_fix_fig_fonts; +% plot_trigaver_PC('Extended Data Fig. 6c top right',time_trig,Trig_data_mr(fish_num_ex,:,:),col_pre, col_adapt_start, col_adapt_end, col_post_start, col_post_end,[-0.5 2]) +% dm_fix_fig_fonts; +% plot_long_term_adaptation_PC_im('Extended Data Fig. 6c bottom left',{Scores_mr(tf_good_lag_fish,:)},'k',{'-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[0 2],true); +% ylabel('bout-triggered response [sd]'); +% set(gca,'ytick',0:0.5:2); +% dm_fix_fig_fonts; +% plot_trigaver_PC('Extended Data Fig. 6c bottom right',time_trig,Trig_data_mr(tf_good_lag_fish,:,:),col_pre, col_adapt_start, col_adapt_end, col_post_start, col_post_end,[-0.5 2]) +% dm_fix_fig_fonts; +% +% % Extended Data Fig. 6d: Responses of 0-0+ ROIs +% plot_long_term_adaptation_PC_im('Extended Data Fig. 6d top left',{Data_temp_exp_rois(fish_num_ex,:)},'k',{'-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[0 2]); +% ylabel('bout-triggered response [sd]'); +% set(gca,'ytick',0:0.4:2); +% dm_fix_fig_fonts; +% plot_trigaver_PC('Extended Data Fig. 6d top right',time_trig,Trig_data_exp_rois(fish_num_ex,:,:),col_pre, col_adapt_start, col_adapt_end, col_post_start, col_post_end,[-0.5 2]) +% dm_fix_fig_fonts; +% plot_long_term_adaptation_PC_im('Extended Data Fig. 6d bottom left',{Data_temp_exp_rois(tf_good_lag_fish,:)},'k',{'-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[-0.5 2],true); +% ylabel('bout-triggered response [sd]'); +% dm_fix_fig_fonts; +% plot_trigaver_PC('Extended Data Fig. 6d bottom right',time_trig,Trig_data_exp_rois(tf_good_lag_fish,:,:),col_pre, col_adapt_start, col_adapt_end, col_post_start, col_post_end,[-0.5 2]) +% dm_fix_fig_fonts; +% +% % Extended Data Fig. 6e: Responses of motor ROIs +% plot_long_term_adaptation_PC_im('Extended Data Fig. 6e top left',{Data_temp_mot_rois(fish_num_ex,:)},'k',{'-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[0.2 2.2]); +% ylabel('bout-triggered response [sd]'); +% set(gca,'ytick',0.2:0.4:2.2); +% dm_fix_fig_fonts; +% plot_trigaver_PC('Extended Data Fig. 6e top right',time_trig,Trig_data_mot_rois(fish_num_ex,:,:),col_pre, col_adapt_start, col_adapt_end, col_post_start, col_post_end,[-0.5 2.5]) +% dm_fix_fig_fonts; +% plot_long_term_adaptation_PC_im('Extended Data Fig. 6e bottom left',{Data_temp_mot_rois(tf_good_lag_fish,:)},'k',{'-'},col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,[-0.5 2.5],true); +% ylabel('bout-triggered response [sd]'); +% dm_fix_fig_fonts; +% plot_trigaver_PC('Extended Data Fig. 6e bottom right',time_trig,Trig_data_mot_rois(tf_good_lag_fish,:,:),col_pre, col_adapt_start, col_adapt_end, col_post_start, col_post_end,[-0.5 2]) +% dm_fix_fig_fonts; +% clear c Trig_data_mr Scores_mr Trig_data_mot_rois Data_temp_mot_rois ans time_trig tf_good_lag_fish Trig_data_exp_rois fish_num_ex Data_temp_exp_rois; + + +%% Extended Data Fig. 7: 0-0+ ROIs represent a spatially distributed subpopulation of PCs +% % extract the data +% [~, n_fish, n_control, n_good_lag, n_bad_lag,... +% ~, ~, ~,... +% tf_control_rois, tf_good_lag_rois, tf_bad_lag_rois, fish_id_rois,... +% ~, ~, ~,... +% ~, Crit_taus_signif,... +% ~, ~, ~,... +% ROI_coord,sz_PC_ref,rez_PC_ref] = extract_PC_imaging_data(pathname_PC_imaging,pathname_reference_brains); +% tf_exp_rois = Crit_taus_signif(:,1)==0 & Crit_taus_signif(:,2)==-1 & Crit_taus_signif(:,3)==0 & Crit_taus_signif(:,4)==1; +% tf_mot_rois = Crit_taus_signif(:,1)==1; +% +% % shuffle ROI labels 100 times and build shuffled maps +% % n_boots=100; +% % tf_exp_rois_shuf = false(length(tf_exp_rois),n_boots); +% % tf_mot_rois_shuf = tf_exp_rois_shuf; +% % for f=1:n_fish +% % ids_this_fish_rois = find(fish_id_rois==f); +% % for i=1:n_boots +% % tf_exp_rois_shuf(ids_this_fish_rois,i)=tf_exp_rois(ids_this_fish_rois(randperm(length(ids_this_fish_rois)))); +% % tf_mot_rois_shuf(ids_this_fish_rois,i)=tf_mot_rois(ids_this_fish_rois(randperm(length(ids_this_fish_rois)))); +% % end +% % end +% % A_exp_control = zeros(sz_PC_ref); +% % A_exp_bad_lag = zeros(sz_PC_ref); +% % A_exp_good_lag = zeros(sz_PC_ref); +% % A_mot_good_lag = zeros(sz_PC_ref); +% % progressbar('Building shuffled maps...'); +% % for i=1:n_boots +% % a=build_PC_map(sz_PC_ref,rez_PC_ref,n_fish,n_control,tf_control_rois,tf_exp_rois_shuf(:,i),fish_id_rois,ROI_coord,1,false); +% % A_exp_control=A_exp_control+a; +% % a=build_PC_map(sz_PC_ref,rez_PC_ref,n_fish,n_bad_lag,tf_bad_lag_rois,tf_exp_rois_shuf(:,i),fish_id_rois,ROI_coord,1,false); +% % A_exp_bad_lag=A_exp_bad_lag+a; +% % a=build_PC_map(sz_PC_ref,rez_PC_ref,n_fish,n_good_lag,tf_good_lag_rois,tf_exp_rois_shuf(:,i),fish_id_rois,ROI_coord,1,false); +% % A_exp_good_lag=A_exp_good_lag+a; +% % a=build_PC_map(sz_PC_ref,rez_PC_ref,n_fish,n_good_lag,tf_good_lag_rois,tf_mot_rois_shuf(:,i),fish_id_rois,ROI_coord,1,false); +% % A_mot_good_lag=A_mot_good_lag+a; +% % progressbar(i/n_boots); +% % end +% % A_exp_control = A_exp_control/n_boots; +% % A_exp_bad_lag = A_exp_bad_lag/n_boots; +% % A_exp_good_lag = A_exp_good_lag/n_boots; +% % A_mot_good_lag = A_mot_good_lag/n_boots; +% % save([path_to_data_PC_imaging 'shuffled_maps.mat'],'A_exp_control','A_exp_bad_lag','A_exp_good_lag','A_mot_good_lag'); +% load([pathname_PC_imaging 'shuffled_maps.mat'],'A_exp_control','A_exp_bad_lag','A_exp_good_lag','A_mot_good_lag'); +% +% % plot the maps +% show_PC_map('Extended Data Fig. 7 control',A_exp_control,rez_PC_ref,50); +% dm_fix_fig_fonts; +% show_PC_map('Extended Data Fig. 7 bad lag',A_exp_bad_lag,rez_PC_ref,50); +% dm_fix_fig_fonts; +% show_PC_map('Extended Data Fig. 7 good lag',A_exp_good_lag,rez_PC_ref,50); +% dm_fix_fig_fonts; +% clear tf_mot_rois tf_exp_rois A_exp_control A_exp_bad_lag A_exp_good_lag A_mot_good_lag n_fish n_control n_good_lag n_bad_lag tf_control_rois tf_good_lag_rois tf_bad_lag_rois fish_id_rois Crit_im_signif ROI_coord sz_PC_ref rez_PC_ref +% + +%% Functions related to bout power +function [h, ballistic_end] = find_ballistic_end_acyte(data_struct,ids,time_power) +data_gain = extract_bout_power_acute(data_struct,'gain'); +data_lag = extract_bout_power_acute(data_struct,'lag'); +data_gain_drop = extract_bout_power_acute(data_struct,'gain_drop'); +data = [data_gain;data_lag;data_gain_drop]; +data=data(ids,:,:); +data = permute(data,[3,1,2]); +[~,N,T]=size(data); +p=nan(1,T); +if N>2 + for i=1:T + p(i)=kruskalwallis(data(:,:,i),[],'off'); + end +else + for i=1:T + p(i)=signrank(data(:,1,i),data(:,2,i)); + end +end +h=p<0.05/T; +ballistic_end=time_power(find(h,1)-1); +end +function [h] = create_bout_power_axes(str,num_subplots) +figure('name',str); +for i=1:num_subplots + h(i)=subplot(1,num_subplots,i,'xlim',[-0.1 1],'xtick',-0.1:0.1:1); hold on; + xlabel('time relative to bout onset [s]'); + ylabel('mean bout power [au]') +end +end +function [data] = prepare_data_for_bout_power_quantif(cell_struct,trial_num,ids) +num_struct=length(cell_struct); +data=cell(num_struct,1); +for s=1:num_struct + this_struct=cell_struct{s}; + data_temp=squeeze(this_struct(trial_num,:,:)-this_struct(2,:,:)); + data{s}=nanmean(data_temp(ids,:),1); +end +end +function [h] = plot_bout_power(h,time,data,ids,cols) +[m, p25, p75] = compute_median_and_quartilles (data); +num_plots=length(ids); +N=size(data,2); +x=nan(N,size(data,3),num_plots); +for i=1:num_plots + fill(h,[time flip(time)],[p25(ids(i),:) flip(p75(ids(i),:))],cols(i,:),'edgecolor','none','facealpha',0.3); + plot(h,time,m(ids(i),:),'color',cols(i,:)); + drawnow; + line(h,[0 0],get(h,'ylim'),'color','k','linestyle',':'); + x(:,:,i)=squeeze(data(ids(i),:,:)); +end +p=nan(num_plots-1,N); +for i=2:num_plots + for j=1:N + p(i-1,j)=signrank(x(j,:,1),x(j,:,i)); + end +end +h=p<0.05/N;%(N*(num_plots-1)); +end +function [data]=extract_bout_power(data_struct) +N=length(data_struct); +[M,T]=size(data_struct(1).trials.power.first); +data=nan(M,T,N); +for i=1:N + data(:,:,i)=data_struct(i).trials.power.first; +end +for i=1:M/10 + data(i,:,:)=nanmean(data((i-1)*10+1:i*10,:,:),1); +end +data=data(1:M/10,:,:); +end +function plot_bout_power_acute(panel_name,data_struct,par_name,cols,time_power,h,col_line,y_lim) +create_bout_power_axes(panel_name,1); +set(gca,'ylim',y_lim); +y=y_lim(2)-diff(y_lim)/10; +data=extract_bout_power_acute(data_struct,par_name); +data=nanmedian(data,3); +[M,T]=size(data); +for i=1:M + plot(time_power,data(i,:),'color',cols(i,:),'linewidth',2); +end +dt=time_power(2)-time_power(1); +for i=1:T + if h(i) + line([time_power(i)-dt/2 time_power(i)+dt/2],[y y],'color',col_line,'linewidth',3); + end +end +end +function [data] = extract_bout_power_acute(data_struct,par_name) +N=length(data_struct); +[M,T]=size(data_struct(1).bouts.condition_mean.(par_name).power.mean); +data=nan(M,T,N); +for i=1:N + data(:,:,i)=data_struct(i).bouts.condition_mean.(par_name).power.mean; +end +end + +%% other functions +function [anat_im] = small_anatomy_image(anatomy_stack,sz,ROI_coord_all,ex_fish_num,ROI_num,col) +temp = false(sz); +temp(ROI_coord_all{ex_fish_num}{ROI_num}) = true; +temp = max(temp,[],3); +temp = imfill(temp,'holes'); +[x,y,z]=ind2sub(sz,ROI_coord_all{ex_fish_num}{ROI_num}); +main_z = mode(z); +c = [round(mean(x(z==main_z))) round(mean(y(z==main_z)))]; +anat_im = uint8(nanmean(anatomy_stack(:,:,unique(z)),3)); +B = cell2mat(bwboundaries(temp)); +anat_im = cat(3,anat_im,anat_im,anat_im); +for i=1:3 + for j=1:size(B,1) + anat_im(B(j,1):B(j,1),B(j,2):B(j,2),i)=col(i)*255; + end +end +anat_im = anat_im(c(1)-25:c(1)+25,c(2)-25:c(2)+25,:); +end +function [A] = build_PC_map(sz,rez,n_fish,n_group,tf_group_rois,tf_type_rois,fish_id_rois,ROI_coord,sigma,show_progressbar) +if nargin==9 + show_progressbar=true; +end +A=zeros(sz); +if show_progressbar + progressbar('Building functional map...'); +end +for f=1:n_fish + ids=find(tf_group_rois & tf_type_rois & fish_id_rois==f)'; + if ~isempty(ids) + A2=zeros(sz,'uint8'); + for i=ids + A2(ROI_coord{i})=255; + end + A2=imgaussfilt3(A2,sigma./rez); + A2=A2>0; + A=A+A2; + end + if show_progressbar + progressbar(f/n_fish); + end +end +A=A/n_group*100; +end +function show_PC_map(str,A,rez_PC_ref,c_max) +un_vals=unique(A(:)); +A=imresize3(A,[size(A,1),size(A,2),round(size(A,3)/rez_PC_ref(1))]); +if length(un_vals)<10 + A=roundtowardvec(A,un_vals); +end +figure('name',str,'position',[148 88 1462 866]); +subplot(2,2,1,'xcolor','none','ycolor','none','clim',[0 c_max],'ydir','reverse'); hold on; +im_top = max(A,[],3); +imagesc(im_top); +pbaspect([flip(size(im_top)) 1]); +line([10 10+100/rez_PC_ref(1)],[10 10],'color','k') +subplot(2,2,2,'xcolor','none','ycolor','none','clim',[0 c_max],'xdir','reverse','ydir','reverse'); hold on; +im_side = squeeze(max(A,[],2)); +imagesc(im_side); +pbaspect([flip(size(im_side)) 1]); +subplot(2,2,3,'xcolor','none','ycolor','none','clim',[0 c_max]); hold on; +im_front = rot90(squeeze(max(A,[],1))); +imagesc(im_front); +pbaspect([flip(size(im_front)) 1]); +subplot(2,2,4,'xcolor','none','ycolor','none','clim',[0 c_max]); +clbr=colorbar; +ylabel(clbr,'percentage of fish with ROIs'); +colormap(flip(hot)); +end + +function [all_fish, n_fish, n_control, n_good_lag, n_bad_lag,... + tf_control_fish, tf_good_lag_fish, tf_bad_lag_fish,... + tf_control_rois, tf_good_lag_rois, tf_bad_lag_rois, fish_id_rois,... + Scores_be, Scores_im, Scores_mr,... + Crit_im, Crit_im_signif,... + Traces_bout_trig, Traces_mr_bout_trig, time_trig,... + ROI_coord,sz_PC_ref,rez_PC_ref] = extract_PC_imaging_data(path_to_data_PC_imaging,path_to_reference_brain_stacks) %#ok +good_lag_fish_thresh = -0.04; +all_fish = dm_dir([path_to_data_PC_imaging 'behavior\' '*_f*_behavior.mat']); +all_fish=strrep(all_fish,'_behavior.mat',''); +n_fish = length(all_fish); +tf_control_fish = false(n_fish,1); +tf_control_rois = false(0,1); +tf_good_lag_rois = false(0,1); +Scores_be=nan(n_fish,120); +Scores_im=[]; +Scores_mr=nan(n_fish,120); +Crit_be=nan(n_fish,4); +Crit_im=[]; +Crit_im_signif=[]; +Traces_bout_trig=[]; +Traces_mr_bout_trig=[]; +fish_id_rois=[]; +ROI_coord2={}; +progressbar('Loading data for PC imaging experiment...'); +for f=1:length(all_fish) + fish_id = all_fish{f}; + load([path_to_data_PC_imaging 'behavior\' fish_id '_behavior.mat'],'meta','trials'); + tf_control_fish(f) = meta.lag_condition==0; + load([path_to_data_PC_imaging 'criteria\' fish_id '_criteria.mat']); %#ok + Crit_be(f,:)=crit_be; + Crit_im=[Crit_im; crit_im]; %#ok + Crit_im_signif = [Crit_im_signif; crit_im_signif]; %#ok + n_rois_this_fish = size(crit_im_signif,1); + tf_control_rois = [tf_control_rois; ones(n_rois_this_fish,1)*tf_control_fish(f)]; %#ok + good_lag_fish=false; + if ~tf_control_fish(f) && Crit_be(f,2) + load([path_to_data_PC_imaging 'scores\' fish_id '_scores.mat']); %#ok + Scores_be(f,:)=scores_be; + Scores_im = [Scores_im; scores_im]; %#ok + Scores_mr(f,:) = scores_motor_regr; + load([path_to_data_PC_imaging 'triggered_traces\' fish_id '_trig_traces.mat']); %#ok + Traces_bout_trig = [Traces_bout_trig; traces_bout_trig]; %#ok + Traces_mr_bout_trig = [Traces_mr_bout_trig; trace_motor_regr_bout_trig]; %#ok + fish_id_rois=[fish_id_rois; f*ones(size(traces_bout_trig,1),1)]; %#ok + load([path_to_data_PC_imaging 'ROIs\' fish_id '_ROIs.mat'],'ROI_coord'); + ROI_coord2=[ROI_coord2; ROI_coord]; %#ok + progressbar(f/length(all_fish)); +end +tf_good_lag_fish = ~tf_control_fish & Crit_be(:,2)=8 + p = plot_quantif(data,col,y_label,fish_num); +else + p = plot_quantif(data,col,y_label); +end +end + +function [p] = make_lt_fbd_panel_PC(str,y_label,cell_struct,str1,str2,trials_num,col,tail,trials_num0) +if nargin <= 8 + trials_num0 = 11:20; +end +prepare_quantif_axes_PC(str); +data = prepare_data_for_quantif(cell_struct,str1,str2,trials_num,trials_num0); +p = plot_quantif_PC(data,col,y_label,tail); +end + +function [] = prepare_quantif_axes2(str) +figure('name',str); +axes('xlim',[0 3],'xtick',1:2,'xticklabel',{'normal reafference control','lag-trained'}); hold on; +end + +function [] = prepare_quantif_axes_PC(str) +figure('name',str); +axes('xlim',[0 6],'xtick',[1.5 4.5],'xticklabel',{'treatment control','PC-ablated'}); hold on; +end + +function [data] = prepare_data_for_quantif(cell_struct,str1,str2,trials_num,trials_num0) +if nargin == 4 + trials_num0 = 11:20; +end +num_struct=length(cell_struct); +data=cell(num_struct,1); +for s=1:num_struct + this_struct=cell_struct{s}; + N=length(this_struct); + data_temp=nan(N,1); + for i=1:N + temp=this_struct(i).trials.(str1).(str2); + data_temp(i)=nanmean(temp(trials_num)) - nanmean(temp(trials_num0)); + end + data{s}=data_temp; +end +end + +function [p, p0] = plot_quantif(data,col,y_label,fish_num,tail) +all_datasets=1:length(data); +h=plotSpread(data,'spreadWidth',0.7,'yLabel',y_label); +h1=h{1}; +set(h1,'marker','o','markerfacecolor',[0.7 0.7 0.7],'markeredgecolor','none','markersize',4); +if nargin==4 + if ~isempty(fish_num) + a=get(h1(2)); + plot(a.XData(fish_num),a.YData(fish_num),'marker','o','markerfacecolor','none','markeredgecolor',[0.7 0 0],'markersize',6,'linewidth',2) + end +end +p=nan(length(data)); +p0=nan(length(data),1); +if nargin<5 + tail='both'; +end +for s=all_datasets + data_temp=data{s}; + [m, p25, p75] = compute_median_and_quartilles (data_temp); + line([s-0.2 s+0.2],[m m],'color',col,'linewidth',2); + line([s s],[p25 p75],'color',col,'linewidth',2); + other_datasets=all_datasets; + other_datasets(s)=[]; + for ss=other_datasets + data_temp2=data{ss}; + p(s,ss)=ranksum(data_temp,data_temp2,'tail',tail); + end + p0(s)=signrank(data_temp); +end +end + +function [p, p0] = plot_quantif_PC(data,col,y_label,tail) +% there must be 4 datasets: +% 1. Treatment control: normal reafference control +% 2. Treatment control: lag-trained +% 3. PC-ablated: normal reafference control +% 4. PC-ablated control: lag-trained +all_datasets=1:length(data); +x_pos=[1 2 4 5]; +cols_pos=[1 2 1 2]; +h=plotSpread(data,'spreadWidth',0.7,'yLabel',y_label,'xValues',x_pos,'xMode','auto'); +h1=h{1}; +set(h1,'marker','o','markerfacecolor',[0.7 0.7 0.7],'markeredgecolor','none','markersize',4); +p=nan(length(data)); +p0=nan(length(data),1); +for s=all_datasets + data_temp=data{s}; + [m, p25, p75] = compute_median_and_quartilles (data_temp); + line([x_pos(s)-0.2 x_pos(s)+0.2],[m m],'color',col(cols_pos(s),:),'linewidth',2); + line([x_pos(s) x_pos(s)],[p25 p75],'color',col(cols_pos(s),:),'linewidth',2); + p0(s)=signrank(data_temp); +end +for i=1:4 + for j=1:4 + p(i,j) = ranksum(data{i},data{j},'tail',tail); + end +end +end + +function [cartoon_time, cartoon_bout, cartoon_vigor, cartoon_swim] = make_cartoon_bout(cartoon_pad_length) +cartoon_dt=0.001; +cartoon_bd=0.4; +F=20; % Hz +l=cartoon_bd/cartoon_dt; +cartoon_bout=sin(F*2*pi*cartoon_dt*(1:l)); +bout_shape=zeros(1,l); +k=0.01; +t=0.98; +for i=2:l + bout_shape(i)=t*k+t*bout_shape(i-1); +end +bout_shape(bout_shape>1)=1; +bout_shape(end/2+1:end)=flip(bout_shape(1:end/2)); +bout_shape=bout_shape/max(bout_shape); +cartoon_bout=cartoon_bout.*bout_shape; +cartoon_bout=padarray(cartoon_bout,[0 cartoon_pad_length/cartoon_dt],0,'both'); +cartoon_time=cartoon_dt:cartoon_dt:cartoon_bd+2*cartoon_pad_length; +cartoon_vigor=zeros(1,length(cartoon_time)); +nn=0.04; +for i=round(nn/0.001):length(cartoon_time) + cartoon_vigor(i)=std(cartoon_bout(i-(round(nn/0.001)-1):i)); +end +[b,a] = butter(3,0.04,'low'); +cartoon_vigor=filtfilt(b,a,cartoon_vigor); +cartoon_vigor(cartoon_vigor<0)=0; +cartoon_swim=false(1,length(cartoon_time)); +cartoon_swim(cartoon_vigor>0.05)=true; +end + +function [] = fill_bout (h,x1,x2,y1,y2,alpha) +fill(h,[x1 x2 x2 x1],[y1 y1 y2 y2],[0 0 0],'edgecolor','none','facealpha',alpha); +end + +function [this_time, this_tail, this_gr, bout_starts, bout_ends] = get_example_trial_data(trial_num,time_be,tail,grspeed,this_struct) +tf=time_be>(trial_num-1)*30 & time_be<=trial_num*30; +dt=time_be(2)-time_be(1); +this_tail=tail(tf); +this_gr=grspeed(tf); +this_gr(1:10)=0; +this_gr(end-9:end)=0; +this_time=time_be(tf); +tf=this_struct.bouts.trial==trial_num; +bout_starts=this_struct.bouts.start(tf)-this_time(1)-7.5+dt; +bout_ends=this_struct.bouts.end(tf)-this_time(1)-7.5+dt; +this_time=this_time-this_time(1)-7.5+dt; +end + +function [time_be, tail, grspeed] = get_example_fish(fish_id, path_to_data, path_str) +time_be=load([path_to_data 'time_array_behavior.mat'],'time_be'); +time_be=time_be.time_be; +data=load([path_to_data path_str fish_id '_data.mat'],'tail','time_tail','swim','time_stim','grspeed'); +tail=interp1(data.time_tail,data.tail,time_be); +swim=interp1(data.time_stim,double(data.swim),time_be)>0.5; +grspeed=interp1(data.time_stim,data.grspeed,time_be); +tail=tail-nanmedian(tail(~swim)); +tail=tail/nanstd(tail(swim)); +end + +function [] = show_trial_start_and_end +line([0 0],ylim,'color','k','linestyle','--'); +line([15 15],ylim,'color','k','linestyle','--'); +end + +function [] = create_single_trial_axes(str) +figure('name',str); +axes('xlim',[-7.5 22.5],'ycolor','none','xtick',[-7.5 0 5 10 15 22.5]); hold on; +xlabel('time relative to trial onset [s]'); +end + + +function [] = plot_long_term_adaptation(str,cell_struct,str1,str2,col,str_line,col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post,y_lim) +figure('name',str); +axes('xlim',[10.5 240.5],'xtick',[11 20 30:10:220 230 240]); hold on; +xlabel('trial #'); +ylabel('first bout duration [s]'); +xtickangle(45); +num_struct=length(cell_struct); +M=length(cell_struct{1}(1).trials.(str1).(str2)); +X=1:M; +N=zeros(1,num_struct); +for s=1:num_struct + this_struct=cell_struct{s}; + N(s)=length(this_struct); + data_temp=nan(N(s),M); + for i=1:N(s) + data_temp(i,:)=this_struct(i).trials.(str1).(str2); + end +% data_temp=data_temp-nanmean(data_temp(:,11:20),2); + % [m, p25, p75] = compute_median_and_quartilles (data_temp); + m = nanmean(data_temp,1); + er=nanstd(data_temp,[],1)./sqrt(sum(~isnan(data_temp),1)); + p25=m-er; p75=m+er; + fill([X flip(X)],[p25 flip(p75)],col(s,:),'edgecolor','none','facealpha',0.2); + plot(X,m,'color',col(s,:),'linewidth',1.5,'linestyle',str_line{s}); +end +show_lt_trials_lines(10.5,20.5,y_lim(2),y_lim(2),col_pre); +show_lt_trials_lines(20.5,30.5,y_lim(2),y_lim(2),col_adapt_start); +show_lt_trials_lines(30.5,220.5,y_lim(2),y_lim(2),col_adapt); +show_lt_trials_lines(220.5,230.5,y_lim(2),y_lim(2),col_adapt_end); +show_lt_trials_lines(230.5,240.5,y_lim(2),y_lim(2),col_post); +set(gca,'ylim',y_lim); +end + +function plot_trigaver_PC(str,time_trig,trig_data,col_pre, col_adapt_start, col_adapt_end, col_post_start, col_post_end,y_lim) +cols = [col_pre; col_adapt_start; col_adapt_end; col_post_start; col_post_end]; +figure('name',str); +axes('xlim',[-0.8 1.2],'ylim',y_lim,'xtick',-0.8:0.4:1.2); hold on; +xlabel('time relative to first bout onset [s]'); +ylabel({'mean z-scored fluorescence'; '(baseline subtracted) [sd]'}); +for i=1:5 + m = nanmean(trig_data(:,:,i),1); + if size(trig_data,1)>1 + er = nanstd(trig_data(:,:,i),[],1)./sqrt(sum(~isnan(trig_data(:,:,i)),1)); + p25=m-er; p75=m+er; + fill([time_trig flip(time_trig)],[p25 flip(p75)],cols(i,:),'edgecolor','none','facealpha',0.2); + end + plot(time_trig,m,'color',cols(i,:),'linewidth',2); +end +line([0 0],ylim,'color','k','linestyle',':'); +end + +function [p] = plot_long_term_adaptation_PC_im(str,cell_data,col,str_line,col_pre,col_adapt_start,col_adapt,col_adapt_end,col_post_start,col_post,col_post_end,y_lim,plot_individual) +if nargin==12 + plot_individual=false; +end +figure('name',str); +axes('xlim',[10.5 120.5],'xtick',[11 20 30:10:120],'ylim',y_lim); hold on; +xtickangle(45); +xlabel('trial #'); +ylabel('first bout duration [s]'); +xtickangle(45); +num_datasets=length(cell_data); +M=size(cell_data{1},2); +X=1:M; +N=zeros(1,num_datasets); +for s=1:num_datasets + data_temp=cell_data{s}; + N(s)=size(data_temp,1); + m = nanmean(data_temp,1); + if N(s)>1 + if plot_individual + for i=1:N(s) + plot(X,data_temp(i,:),'linewidth',1,'linestyle',str_line{s},'color',[0.75 0.75 0.75]); + end + end + er=nanstd(data_temp,[],1)./sqrt(sum(~isnan(data_temp),1)); + p25=m-er; p75=m+er; + fill([X flip(X)],[p25 flip(p75)],col(s,:),'edgecolor','none','facealpha',0.2); + end + p(s)=plot(X,m,'color',col(s,:),'linewidth',1.5,'linestyle',str_line{s}); %#ok +end +show_lt_trials_lines(10.5,20.5,y_lim(2),y_lim(2),col_pre); +show_lt_trials_lines(20.5,30.5,y_lim(2),y_lim(2),col_adapt_start); +show_lt_trials_lines(30.5,60.5,y_lim(2),y_lim(2),col_adapt); +show_lt_trials_lines(60.5,70.5,y_lim(2),y_lim(2),col_adapt_end); +show_lt_trials_lines(70.5,80.5,y_lim(2),y_lim(2),col_post_start); +show_lt_trials_lines(80.5,110.5,y_lim(2),y_lim(2),col_post); +show_lt_trials_lines(110.5,120.5,y_lim(2),y_lim(2),col_post_end); +end + +function [] = show_lt_trials_lines(x1,x2,y1,y2,col,show_fill) +if nargin==5 + show_fill=true; +end +if x1==x2 + line([x1 x1],[y1 y2],'color',col,'linewidth',2); + x_lim=get(gca,'xlim'); + if show_fill + h=fill([x_lim flip(x_lim)],[y1 y1 y2 y2],col,'edgecolor','none','facealpha',0.2); + uistack(h,'bottom'); + end + line(x_lim,[y2 y2],'color','k','linestyle',':','linewidth',0.5); +elseif y1==y2 + line([x1 x2],[y1 y1],'color',col,'linewidth',2); + y_lim=get(gca,'ylim'); + if show_fill + h=fill([x1 x1 x2 x2],[y_lim flip(y_lim)],col,'edgecolor','none','facealpha',0.2); + uistack(h,'bottom'); + end + line([x2 x2],y_lim,'color','k','linestyle',':','linewidth',0.5); +end +end + +function [top_view,side_view,front_view] = three_orthogonal_views(stack,xy_rez) +sz=size(stack); +top_view=double(max(stack,[],3)); + +side_view=squeeze(double(max(stack,[],2))); +side_view=imresize(side_view,[sz(1),round(sz(3)/xy_rez)]); +side_view=flip(side_view,2); + +% front_view = squeeze(double(max(stack,[],1))); +% +% front_view=imresize(front_view,[sz(2),round(sz(3)/xy_rez)]); +% front_view=flip(imrotate(front_view,-90),2); +end \ No newline at end of file diff --git a/analysis/behavioral_analysis/behavioral_analysis.m b/analysis/behavioral_analysis/behavioral_analysis.m new file mode 100644 index 0000000..61c988b --- /dev/null +++ b/analysis/behavioral_analysis/behavioral_analysis.m @@ -0,0 +1,276 @@ +% this program analyzes the raw data (detects individual bouts and computes stuff used in the figures) +clc; close all; clear all; +addpath('...\MATLAB_functions'); + +%% pathnames +pathname_MS_data = '...\data\'; +pathname_behavior=[pathname_MS_data 'behavior\']; +exp_names={'acute_reaction_experiment\',... + 'long_term_adaptation_experiment\normal_reafference_control\',... + 'long_term_adaptation_experiment\lag_trained\'}; +exp_groups={'WT_TL_group','treatment_control_group','PC_ablated_group'}; + +%% timing +dt=0.005; % [s] +num_trials=240; +trial_dur=30; % [s] +time_be=dt:dt:num_trials*trial_dur; +num_frames=length(time_be); +vigor_window_frames=round(0.05/dt); +gr_starts=7.5:30:7.5+239*30; +gr_ends=gr_starts+15; +t_main_start=20*trial_dur; +t_post_start=230*trial_dur; + +%% variables with parameter and reafference condition names +bout_par_names={'bout_duration','next_interbout_duration','power'}; +cond.names={'lag';'shunted_lag';'gain';'gain_drop'}; +cond.xlabel=[{{'0','75','150','225','300','Inf'}};... + {{'0','75','150','225','300','Inf'}};... + {{'0', '0.33','0.66','1','1.33','1.66','2'}};... + {{'1111','0111','0011','0001','0000','1110','1100','1000'}}]; +cond.vals=[{[0 0.075 0.15 0.225 0.3 0; 1 1 1 1 1 0; 0 0 0 0 0 0; 0 0 0 0 0 0]};... + {[0 0 0 0 0 0; 1 1 1 1 1 0; 0 0 0 0 0 0; 0 0.075 0.15 0.225 0.3 0]};... + {[0 0 0 0 0 0 0; 0 0.33 0.66 1 1.33 1.66 2; 0 0 0 0 0 0 0; 0 0 0 0 0 0 0]};... + {[0 0 0 0 0 0 0 0; 1 1 1 1 1 1 1 1; 0 0 0 0 0 0.225 0.15 0.075; 0 0.075 0.15 0.225 0.3 0.3 0.3 0.3]}]; + +%% main loop +progressbar('Experiment...','Genotype...','Fish...'); +for exp=1:length(exp_names) + for gen=1:length(exp_groups) + behavior=struct; + pathname=[pathname_behavior exp_names{exp} exp_groups{gen}]; + cd(pathname); + all_fish=dm_dir('*_f*_data.mat'); + for f=1:length(all_fish) + + %% load data from this fish + load(all_fish{f},'tail','time_tail','time_stim','swim','metadata'); + if contains(exp_names{exp},'acute_adaptation') + load(all_fish{f},'lag','gain','gd_starts','gd_ends'); + end + + %% find bout starts and ends (detected online during the experiment) + swim(1)=false; swim(end)=false; + bout_starts_ids=find(diff([false swim])==1); + bout_ends_ids=find(diff([false swim false])==-1); + num_bouts=length(bout_starts_ids); + bouts=[]; + + %% find reafference of all these bouts + % (if this is acute adaptation experiment) + if contains(exp_names{exp},'acute_adaptation') + bouts.gain=gain(bout_starts_ids)'; + bouts.lag=lag(bout_starts_ids)'; + bouts.gain_drop_start=gd_starts(bout_starts_ids)'; + bouts.gain_drop_start(isnan(bouts.gain_drop_start))=0; + bouts.gain_drop_end=gd_ends(bout_starts_ids)'; + bouts.gain_drop_end(isnan(bouts.gain_drop_end))=0; + end + + %% work with behavioral traces + % interpolate tail and swim to time_be + tail=interp1(time_tail,tail,time_be); + swim=interp1(time_stim,double(swim),time_be)>0; + % scale the tail trace + tail=tail-nanmean(tail(~swim)); + tail=tail/nanstd(tail(swim)); + tail(isnan(tail))=0; + % build vigor trace + vigor=nan(1,num_frames); + for i=vigor_window_frames:num_frames + vigor(i)=std(tail(i-(vigor_window_frames-1):i)); + end + + %% detect bouts accurately by identifying individual tail flicks + bouts.start=nan(num_bouts,1,'single'); + bouts.end=nan(num_bouts,1,'single'); + bouts.bad_bouts=false(num_bouts,1); + mm_time_array=nan(num_bouts,1000); + mm_val_array=mm_time_array; + max_tf_array=false(num_bouts,1000); + for b=1:num_bouts + bst0=round((time_stim(bout_starts_ids(b))-0.1)/dt); + bet0=round(time_stim(bout_ends_ids(b))/dt); + bouts.start(b)=time_stim(bout_starts_ids(b)); + bouts.end(b)=time_stim(bout_ends_ids(b)); + + % find individual flicks + this_mm_time_array=[]; + this_mm_val_array=[]; + this_max_tf_array=[]; + c=0; + if bst0<2 + bst0=2; + end + if bet0>240*30/dt-1 + bet0=240*30/dt-1; + end + for i=bst0:bet0 + if tail(i)>=tail(i-1) && tail(i)>tail(i+1) + c=c+1; + this_mm_time_array(c)=time_be(i); + this_mm_val_array(c)=tail(i); + this_max_tf_array(c)=true; + elseif tail(i)<=tail(i-1) && tail(i)=2 + bad_flicks=[abs(diff(this_mm_val_array))<0.14 false] & [false flip(abs(diff(flip(this_mm_val_array)))<0.14)]; + if abs(this_mm_val_array(2)-this_mm_val_array(1))<0.14 + bad_flicks(1)=true; + end + if abs(this_mm_val_array(end)-this_mm_val_array(end-1))<0.14 + bad_flicks(end)=true; + end + bad_flicks=bad_flicks | [false flip(abs(diff(flip(this_mm_time_array)))>0.1)]; + this_mm_time_array(bad_flicks)=[]; + this_mm_val_array(bad_flicks)=[]; + this_max_tf_array(bad_flicks)=[]; + bad_flicks=diff(this_max_tf_array)==0; + this_mm_time_array(bad_flicks)=[]; + this_mm_val_array(bad_flicks)=[]; + this_max_tf_array(bad_flicks)=[]; + if length(this_mm_time_array)>=2 + bouts.start(b)=this_mm_time_array(1); + bouts.end(b)=this_mm_time_array(end); + else + bouts.bad_bouts(b)=true; + end + else + bouts.bad_bouts(b)=true; + end + n=length(this_mm_time_array); + if n>1000 + n=1000; + end + mm_time_array(b,1:n)=this_mm_time_array(1:n); + mm_val_array(b,1:n)=this_mm_val_array(1:n); + max_tf_array(b,1:n)=this_max_tf_array(1:n); + end + % shorten the flicks arrays + mm_n=find(all(isnan(mm_time_array),1),1)-1; + if ~isempty(mm_n) + if mm_n>=50 + mm_n=50; + end + mm_time_array=mm_time_array(:,1:mm_n); + mm_val_array=mm_val_array(:,1:mm_n); + max_tf_array=max_tf_array(:,1:mm_n); + end + % create array of bad bouts + bouts.long_bouts=bouts.end-bouts.start>=0.3; + bouts.short_bouts=bouts.end-bouts.start<0.1; + bouts.bad_bouts=bouts.bad_bouts | ... % bouts that are already bad (failed to detect them properly) + bouts.short_bouts |... % bouts which are shorter than 100 ms + [false; bouts.start(2:end)-bouts.end(1:end-1)<0.1] | [bouts.start(2:end)-bouts.end(1:end-1)<0.1; false] |... % bouts with interbouts shorter than 100 ms (tipically, these are bouts which were detected as 2 bouts) + all(isnan(mm_time_array),2) |... % wierd bouts with no flicks + max(diff(mm_time_array,1,2),[],2)>0.1; % bouts with max delta flick time > 100 ms (this happens during some wierd ugly bouts) + + % find spontaneous bouts (i.e. bouts which started after trial start and finished before trial end) + bouts.spont_bouts=true(num_bouts,1); + for g=1:num_trials + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end=t_main_start; + bouts.main_bouts=bouts.main_bouts'; + % good bouts: i.e. they are not bad, not spontaneous and happened during main part + bouts.good_bouts=bouts.main_bouts & ~bouts.bad_bouts & ~bouts.spont_bouts; + + %% find bout parameters + bouts.trial=zeros(num_bouts,1,'uint8'); + bouts.bout_duration=bouts.end-bouts.start; + bouts.next_interbout_duration=nan(num_bouts,1,'single'); + for g=1:num_trials + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end=1.1/dt + be=bs+1.1/dt-1; + end + bouts.power(b,:)=zeros(1,1.1/dt,'single'); + temp_tail=tail(bs:be); + temp_tail=temp_tail-nanmedian(temp_tail(1:0.1/dt)); + bouts.power(b,1:be-bs+1)=temp_tail.^2; + end + end + for p=1:length(bout_par_names) + bouts.(bout_par_names{p})(bouts.bad_bouts | bouts.spont_bouts,:)=nan; + end + + %% find trial averages + trials=[]; + for g=1:num_trials + trial_start=round((gr_starts(g)-7.5)/dt)+1; + trial_end=round((gr_ends(g)+7.5)/dt); + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end0 + trials.(this_par).first(g,:)=these_bouts(1,:); + trials.(this_par).mean(g,:)=nanmean(these_bouts,1); + else + trials.(this_par).first(g,:)=nan(1,size(bouts.(this_par),2)); + trials.(this_par).mean(g,:)=nan(1,size(bouts.(this_par),2)); + end + end + end + + %% find condition averages (for acute reaction experiment) + if contains(exp_names{exp},'acute_adaptation') + for c=1:length(cond.names) + this_cond_name=cond.names{c}; + this_cond_vals=single(cond.vals{c}); + bouts.condition_mean.(this_cond_name).conditions=cond.xlabel{c}; + for i=1:length(bouts.condition_mean.(this_cond_name).conditions) + tf=bouts.good_bouts & bouts.lag==this_cond_vals(1,i) & bouts.gain==this_cond_vals(2,i) & bouts.gain_drop_start==this_cond_vals(3,i) & bouts.gain_drop_end==this_cond_vals(4,i); + for p=1:length(bout_par_names) + this_par=bout_par_names{p}; + these_bouts=bouts.(this_par)(tf,:); + these_bouts=these_bouts(~all(isnan(these_bouts),2),:); + bouts.condition_mean.(this_cond_name).(this_par).n(i)=size(these_bouts,1); + if bouts.condition_mean.(this_cond_name).(this_par).n(i)>0 + bouts.condition_mean.(this_cond_name).(this_par).mean(i,:)=nanmean(these_bouts,1); + else + bouts.condition_mean.(this_cond_name).(this_par).mean(i,:)=nan(1,size(bouts.(this_par),2)); + end + end + end + end + end + + %% save pooled data into the final structure + behavior(f).fish_id=strrep(all_fish{f},'_data.mat',''); + behavior(f).metadata=metadata; + behavior(f).bouts=bouts; + behavior(f).trials=trials; + progressbar([],[],f/length(all_fish)); + end + save('pooled_data.mat','behavior'); + progressbar([],gen/length(exp_groups),[]); + end + progressbar(exp/length(exp_names),[],[]); +end + \ No newline at end of file diff --git a/analysis/feedback_control_model/brain_iteration_v3.m b/analysis/feedback_control_model/brain_iteration_v3.m new file mode 100644 index 0000000..a5fd093 --- /dev/null +++ b/analysis/feedback_control_model/brain_iteration_v3.m @@ -0,0 +1,49 @@ +function [swim, brain_state] = brain_iteration_v3(swim, brain_state, grspeed, par) +% +% Inputs: +% +% 1. swim - a binary variable that tells if fish swam before this iteration +% +% 2. brain_state - previous state of the brain +% brain_state(1) - activity of forward motion sensor +% brain_state(2) - activity of reverse motion sensor +% brain_state(3) - activity of sensory integrator +% brain_state(4) - activity of motor output generator +% brain_state(5) - activity of motor integrator +% +% 3. grspeed - current grating speed +% +% 4. par - parameters of the model +% par(1) - wf - weight between forward motion sensor and sensory integrator +% par(2) - wr - weight between reverse motion sensor and sensory integrator +% par(3) - dt/taus - time constant of sensory integrator +% par(4) - wi - weight between motor integrator and motor output generator +% par(5) - ws - weight of feed-forward self-excitation of motor output command cell +% par(6) - t - threshold of motor output command +% par(7) - wm - weight between motor output command cell and motor integrator +% par(8) - dt/taum - time constant of motor integrator +% +% +% Outputs: +% +% 1. swim - a binary variable that tells if fish swims after this iteration +% +% 2. brain_state - state of the brain after this iteration + +% forward motion sensor (positively rectified grating speed) +brain_state(1)=max(grspeed,0); + +% reverse motion sensor (negatively rectified grating speed) +brain_state(2)=-min(grspeed,0); + +% sensory integrator (leaky integrator with saturation at 1) +brain_state(3)=max(min(par(3)*par(1)*brain_state(1)-par(3)*par(2)*brain_state(2)-(par(3)-1)*brain_state(3),1),0); + +% motor output generator (activated by sensory integrator and inhibited by motor integrator) +brain_state(4)=max(brain_state(3)-par(4)*brain_state(5),0); + +% swim (fish swims if motor output generator + self-excitation is greater than swimming threshold) +swim=brain_state(4)+par(5)*swim>par(6); + +% motor integrator (leaky integrator with saturation at 1) +brain_state(5)=min(par(8)*par(7)*swim-(par(8)-1)*brain_state(5),1); \ No newline at end of file diff --git a/analysis/feedback_control_model/compute_max_wr_v3.m b/analysis/feedback_control_model/compute_max_wr_v3.m new file mode 100644 index 0000000..e708a7d --- /dev/null +++ b/analysis/feedback_control_model/compute_max_wr_v3.m @@ -0,0 +1,3 @@ +function [wr] = compute_max_wr_v3 (taus, lat) + +wr=(-exp(-lat./taus))./(3.2.*(exp(-lat./taus)-1)); \ No newline at end of file diff --git a/analysis/feedback_control_model/compute_par_ranges_v3.m b/analysis/feedback_control_model/compute_par_ranges_v3.m new file mode 100644 index 0000000..85b39b1 --- /dev/null +++ b/analysis/feedback_control_model/compute_par_ranges_v3.m @@ -0,0 +1,50 @@ +function [par_ranges] = compute_par_ranges_v3 (max_taus, max_taum, max_wi, lat_ranges, tlat, tmot, par_ranges) +% computes the most conservative parameter ranges +% see labfolder entry as of 08.05.2019 and 09.05.2019 in Daniil LabBook for details + +% function inputs: +% max_taus - maximal time constant of the sensory integrator [s] +% max_taum - maximal time constant of the motor integrator [s] +% max_wi - maximal weight between motor integrator and motor output generator +% lat_ranges - range of allowed latency to initiate swimming after grating onset [s] +% tlat = 0.01 - minimal allowed time for comlete discharge of the sensory integrator (from 1 to 0) during a bout at gain 0.66 +% tmot = 0.01 - minimal allowed time of complete saturation of the motor integrator (from 0 to 1) during a bout [s] +% par_ranges - optional ranges (useful for the fitting algorythm). If this is defined, the function will only set dependent ranges + +% output is n x 2 array, where n - is number of model parameters, +% 1st column is the min limit, 2nd column is the max limit +% par(1) - wf - weight between forward motion sensor and sensory integrator +% par(2) - wr - weight between reverse motion sensor and sensory integrator +% par(3) - taus - time constant of sensory integrator [s] +% par(4) - wi - weight between motor integrator and motor output generator +% par(5) - ws - weight of feed-forward self-excitation of motor output command cell +% par(6) - t - threshold of motor output command +% par(7) - wm - weight between motor output command cell and motor integrator +% par(8) - taum - time constant of motor integrator [s] + +% create an array and write down independent ranges (if it wasn't defined) +if nargin == 6 + par_ranges=[... + nan nan;... % wf + 0 nan;... % wr + 0 max_taus;...% taus + 0 max_wi;... % wi + 0 nan;... % ws + 0 1;... % t + 0 nan;... % wm + 0 max_taum;...% taum + ]; +end + +% define ranges for wf +par_ranges(1,1)=compute_wf_v3(par_ranges(6,2), par_ranges(3,2), lat_ranges(2)); +par_ranges(1,2)=compute_wf_v3(par_ranges(6,2), par_ranges(3,2), lat_ranges(1)); + +% define upper limit for wr +par_ranges(2,2)=compute_max_wr_v3(par_ranges(3,2), tlat); + +% define upper limit for ws +par_ranges(5,2)=par_ranges(6,2); + +% define upper limit for wm +par_ranges(7,2)=compute_wm_v3(par_ranges(8,2), tmot); \ No newline at end of file diff --git a/analysis/feedback_control_model/compute_wf_v3.m b/analysis/feedback_control_model/compute_wf_v3.m new file mode 100644 index 0000000..66bbe85 --- /dev/null +++ b/analysis/feedback_control_model/compute_wf_v3.m @@ -0,0 +1,4 @@ +function [wf] = compute_wf_v3 (t, taus, lat) + +wf=t./(10.*(1-exp(-(lat-0.22)./taus))); + diff --git a/analysis/feedback_control_model/compute_wm_v3.m b/analysis/feedback_control_model/compute_wm_v3.m new file mode 100644 index 0000000..63afabf --- /dev/null +++ b/analysis/feedback_control_model/compute_wm_v3.m @@ -0,0 +1,3 @@ +function [wm] = compute_wm_v3 (taus, lat) + +wm=1./(1-exp(-lat./taus)); \ No newline at end of file diff --git a/analysis/feedback_control_model/exp_iteration_v3.m b/analysis/feedback_control_model/exp_iteration_v3.m new file mode 100644 index 0000000..6a568fe --- /dev/null +++ b/analysis/feedback_control_model/exp_iteration_v3.m @@ -0,0 +1,20 @@ +function [grspeed, frames_since_bout_start, frames_since_bout_end] = exp_iteration_v3 (grspeed, swim, frames_since_bout_start, frames_since_bout_end, reaf) +% dt = 0.005 +% reaf = [gain, lag(frames), shunted(1/0), gain drop start, gain drop end] +if swim + frames_since_bout_start=frames_since_bout_start+1; + frames_since_bout_end=0; + if frames_since_bout_start>reaf(2) % if bout is longer than lag + if frames_since_bout_startreaf(5) % if gain is not "dropped" + grspeed=grspeed-reaf(1)*20; + end + end +else + frames_since_bout_end=frames_since_bout_end+1; + frames_since_bout_start=0; + if reaf(3)==0 + if frames_since_bout_end<=reaf(2) + grspeed=grspeed-reaf(1)*20; + end + end +end diff --git a/analysis/feedback_control_model/model_compute_parameters_v3.m b/analysis/feedback_control_model/model_compute_parameters_v3.m new file mode 100644 index 0000000..074d1d0 --- /dev/null +++ b/analysis/feedback_control_model/model_compute_parameters_v3.m @@ -0,0 +1,10 @@ +function [bd, id] = model_compute_parameters_v3 (swim,dt) +bout_starts_ids=find(diff([0 swim])==1); +bout_ends_ids=find(diff([0 swim 0])==-1); +if length(bout_starts_ids)==3 && length(bout_ends_ids)==3 + bd=(bout_ends_ids(2)-bout_starts_ids(2))*dt; + id=(bout_starts_ids(3)-bout_ends_ids(2))*dt; +else + bd=nan; + id=nan; +end \ No newline at end of file diff --git a/analysis/feedback_control_model/model_protocols/model_long_trial_v3.m b/analysis/feedback_control_model/model_protocols/model_long_trial_v3.m new file mode 100644 index 0000000..c01f695 --- /dev/null +++ b/analysis/feedback_control_model/model_protocols/model_long_trial_v3.m @@ -0,0 +1,16 @@ +function [swim,grspeed,brain_state] = model_long_trial_v3(par, dt, reaf) +% sensory processing delay = 0.22 s +num_frames=round(20/dt); % 20 sec +gr_starts=round(2.5/dt); % 2.5 sec +gr_ends=round(17.5/dt); % 17.5 sec +grspeed=zeros(1,num_frames); +grspeed(gr_starts:gr_ends)=10; +brain_state=zeros(5,num_frames); +swim=false(1,num_frames); +frames_since_bout_start=0; +frames_since_bout_end=inf; +sens_delay=round(0.22/dt); +for t=sens_delay+1:num_frames + [grspeed(t), frames_since_bout_start, frames_since_bout_end] = exp_iteration_v3 (grspeed(t), swim(t-1), frames_since_bout_start, frames_since_bout_end, reaf); + [swim(t), brain_state(:,t)] = brain_iteration_v3(swim(t-1), brain_state(:,t-1), grspeed(t-sens_delay), par); +end \ No newline at end of file diff --git a/analysis/feedback_control_model/model_protocols/model_one_bout_trial_v3.m b/analysis/feedback_control_model/model_protocols/model_one_bout_trial_v3.m new file mode 100644 index 0000000..0bcc0a9 --- /dev/null +++ b/analysis/feedback_control_model/model_protocols/model_one_bout_trial_v3.m @@ -0,0 +1,31 @@ +function [swim,grspeed,brain_state] = model_one_bout_trial_v3 (par, dt) +running=true; +sens_delay=round(0.22/dt); +t=sens_delay; +t_from_start_to_gr=0.7/dt; +t_from_bout_end_to_gr_end=0.4/dt; +reaf0 = [1 0 0 0 0]; +brain_state=zeros(5,t); +swim=false(1,t); +frames_since_bout_start=0; +frames_since_bout_end=0; +fish_swam=false; +while running + t=t+1; + if t>t_from_start_to_gr && (frames_since_bout_end t_from_bout_end_to_gr_end + t_from_start_to_gr && fish_swam + running=false; + end + if t>=10/dt + running=false; + end +end \ No newline at end of file diff --git a/analysis/feedback_control_model/model_protocols/model_short_trial_v3.m b/analysis/feedback_control_model/model_protocols/model_short_trial_v3.m new file mode 100644 index 0000000..b36097b --- /dev/null +++ b/analysis/feedback_control_model/model_protocols/model_short_trial_v3.m @@ -0,0 +1,31 @@ +function [swim,grspeed,brain_state] = model_short_trial_v3 (par, dt, reaf) +% sensory processing delay = 0.22 s +running=true; +sens_delay=round(0.22/dt); +gr_starts_frame=round(0.3/dt); +t=sens_delay; +reaf0 = [1 0 0 0 0; 1 0 0 0 0; reaf; 1 0 0 0 0]; +num_frames=round(10/dt); +brain_state=zeros(5,num_frames); +swim=false(1,num_frames); +frames_since_bout_start=0; +frames_since_bout_end=inf; +bout_counter=0; +grspeed=zeros(1,num_frames); +grspeed(gr_starts_frame:end)=10; +while running + t=t+1; + [grspeed(t), frames_since_bout_start, frames_since_bout_end] = exp_iteration_v3 (grspeed(t), swim(t-1), frames_since_bout_start, frames_since_bout_end, reaf0(bout_counter+1,:)); + [swim(t), brain_state(:,t)] = brain_iteration_v3(swim(t-1), brain_state(:,t-1), grspeed(t-sens_delay), par); + if swim(t) + if ~swim(t-1) + bout_counter=bout_counter+1; + if bout_counter==3 + running=false; + end + end + end + if t>=num_frames + running=false; + end +end \ No newline at end of file diff --git a/analysis/feedback_control_model/model_protocols/model_v3_real_trial.m b/analysis/feedback_control_model/model_protocols/model_v3_real_trial.m new file mode 100644 index 0000000..603b0a1 --- /dev/null +++ b/analysis/feedback_control_model/model_protocols/model_v3_real_trial.m @@ -0,0 +1,31 @@ +function [swim,grspeed,brain_state] = model_v3_real_trial (par, dt, reaf, rest_dur) +% sensory processing delay = 0.22 s +trial_dur=15; +num_frames=round((trial_dur+2*rest_dur)/dt); +grspeed=zeros(1,num_frames); +gr_starts=round(rest_dur/dt); +gr_ends=round((rest_dur+trial_dur)/dt); +grspeed(gr_starts:gr_ends)=10; +swim=false(1,num_frames); +brain_state=zeros(5,num_frames); +bout_counter=0; +frames_since_bout_start=0; +frames_since_bout_end=inf; +reaf0 = [1 0 0 0 0]; +nob = size(reaf,1); +reaf=[reaf0; reaf]; +sens_delay=round(0.22/dt); +for t=sens_delay+1:num_frames + if bout_counter<=nob + this_reaf=reaf(bout_counter+1,:); + else + this_reaf=reaf0; + end + [grspeed(t), frames_since_bout_start, frames_since_bout_end] = exp_iteration_v3 (grspeed(t), swim(t-1), frames_since_bout_start, frames_since_bout_end, this_reaf); + [swim(t), brain_state(:,t)] = brain_iteration_v3(swim(t-1), brain_state(:,t-1), grspeed(t-sens_delay), par); + if swim(t) + if ~swim(t-1) + bout_counter=bout_counter+1; + end + end +end \ No newline at end of file diff --git a/analysis/feedback_control_model/model_v3_individual_fish_genetic_fitting.m b/analysis/feedback_control_model/model_v3_individual_fish_genetic_fitting.m new file mode 100644 index 0000000..59fbcdd --- /dev/null +++ b/analysis/feedback_control_model/model_v3_individual_fish_genetic_fitting.m @@ -0,0 +1,250 @@ +clc; clear all; +addpath(genpath('C:\Markov_et_al_2021_Nat_Commun_data&code\analysis_code\feedback_control_model')); +pathname_MS_data = 'C:\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_model=[pathname_MS_data 'feedback_control_model\']; +cd(pathname_model); + +%% ground truth (load training data) +dt=0.01; +gt_train=load('gt.mat','gt_train','lat_train'); +lat_train=gt_train.lat_train; +gt_train=gt_train.gt_train; +n_fish=length(lat_train); +weights=ones(1,36); +weights(24)=5; % open loop interbouts +weights(23)=5; %lag 300 interbouts +weights(15)=5; % gain 2 bouts + +%% parameters and ranges +% par(1) - wf - weight between forward motion sensor and sensory integrator +% par(2) - wr - weight between reverse motion sensor and sensory integrator +% par(3) - taus - time constant of sensory integrator [s] +% par(4) - wi - weight between motor integrator and motor output generator +% par(5) - ws - weight of feed-forward self-excitation of motor output command cell +% par(6) - t - threshold of motor output command +% par(7) - wm - weight between motor output command cell and motor integrator +% par(8) - taum - time constant of motor integrator [s] +list_of_pars={'wf','wr','taus','wi','ws','t','wm','taum'}; +n_pars=length(list_of_pars); + +%% optimization parameters +min_n_gen=5; % number of generations +pop_size=100000; % population size +surv_rate=0.01; % fraction of survivers +mut_rate=0.1; % mutation rate + +% number of survivers +n_surv=pop_size*surv_rate; +n_offsrping=pop_size/n_surv; + +%% output +best_par=nan(n_pars,n_fish); + +%% name +my_name=[datestr(datetime('now'),'yymmddHHMM') '_fitting_v3_n_fish_' num2str(n_fish) '_min_n_gen_' num2str(min_n_gen) '_pop_size_' num2str(pop_size) '_surv_rate_' num2str(surv_rate) '_mut_rate_' num2str(mut_rate)]; + +%% display stuff +disp(['********* Starting evolution of ' num2str(n_fish) ' fish *********']); +disp(['* Population size: ' num2str(pop_size)]); +disp(['* Min number of generations: ' num2str(min_n_gen)]); +disp(['* Survival rate: ' num2str(surv_rate*100) '%']); +disp(['* Mutation rate: ' num2str(mut_rate*100) '%']); +disp(['* Number of survivers in each generation: ' num2str(n_surv)]); +disp(['* Number of offspring from each surviver: ' num2str(n_offsrping)]); +disp('**************************************************'); + +%% evolve populations one by one in parallel +lat_range=1; +tlat=0.01; +tmot=0.01; +for f=1:n_fish + disp(['Fish ' num2str(f) ' / ' num2str(n_fish)]); + reaf=load('gt.mat','reaf'); + reaf=reaf.reaf'; + for i=[2 4 5] + reaf(:,i)=round(reaf(:,i)/dt); + end + gt=gt_train(f,:); + weights0=weights./gt; + + lat_min=max(lat_train(f)-lat_range,0.25); + lat_max=min(lat_train(f)+lat_range,10); + + best_par_this_fish=nan(8,1); + best_perf=[]; + % original parameter ranges + min_taus=0.005; + max_taus=10; + min_taum=0.005; + max_taum=10; + min_wi=0; + max_wi=10; + min_t=0; + max_t=1; + min_wr=0; + min_ws=0; + min_wm=0; + % generate original population (independent parameters) + taus=rand(1,pop_size).*(max_taus-min_taus)+min_taus; + wi=rand(1,pop_size).*(max_wi-min_wi)+min_wi; + t=rand(1,pop_size).*(max_t-min_t)+min_t; + taum=rand(1,pop_size).*(max_taum-min_taum)+min_taum; + % generate dependent parameters + min_wf=compute_wf_v3(t, taus, lat_max); + max_wf=compute_wf_v3(t, taus, lat_min); + wf=rand(1,pop_size).*(max_wf-min_wf)+min_wf; + max_wr=compute_max_wr_v3(taus, tlat); + wr=rand(1,pop_size).*(max_wr-min_wf)+min_wr; + ws=rand(1,pop_size).*(t-min_ws)+min_ws; + max_wm=compute_wm_v3(taum, tmot); + wm=rand(1,pop_size).*(max_wm-min_wm)+min_wm; + + % create a population + this_pop=[wf;wr;taus;wi;ws;t;wm;taum]; + % convert taus to unitless + this_pop(3,:)=dt./this_pop(3,:); + this_pop(8,:)=dt./this_pop(8,:); + + process1=true; + process2=true; + gen=0; + super_gen=0; + super_gen_switch_id=0; + + while process1 + super_gen=super_gen+1; + super_gen_switch_id(super_gen)=gen; + while process2 + gen=gen+1; + perf=ones(1,pop_size)*inf; + for i=1:pop_size + data=zeros(1,36); + for j=1:18 + [data(j), data(j+18)] = model_compute_parameters_v3 (model_short_trial_v3(this_pop(:,i),dt,reaf(j,:)),dt); + end + perf(i) = sum(abs(gt-data).*weights0); + end + % convert taus back to seconds + this_pop(3,:)=dt./this_pop(3,:); + this_pop(8,:)=dt./this_pop(8,:); + % find best performers + [~,surv]=sort(perf, 'ascend'); + surv=surv(1:n_surv); + best_par_this_fish=this_pop(:,surv(1)); + best_perf(gen)=min(perf); + % exit the inner loop + if gen-super_gen_switch_id(super_gen)>=min_n_gen + if all(best_perf((gen-min_n_gen+1):gen)==best_perf(gen)) + process2=false; + super_gen_switch_id(super_gen)=gen; + do_the_breeding=false; + else + do_the_breeding=true; + end + else + do_the_breeding=true; + end + if do_the_breeding + % let them breed and mutate + mut_pars=rand(n_pars,pop_size)>=mut_rate; + mut_pars(:,1:n_offsrping:pop_size)=true; % to make sure that at least one kid doesn't mutate and population doesn't exstinct + % generate new random population (independent parameters) + taus=rand(1,pop_size).*(max_taus-min_taus)+min_taus; + wi=rand(1,pop_size).*(max_wi-min_wi)+min_wi; + t=rand(1,pop_size).*(max_t-min_t)+min_t; + taum=rand(1,pop_size).*(max_taum-min_taum)+min_taum; + % generate dependent parameters + min_wf=compute_wf_v3(t, taus, lat_max); + max_wf=compute_wf_v3(t, taus, lat_min); + wf=rand(1,pop_size).*(max_wf-min_wf)+min_wf; + max_wr=compute_max_wr_v3(taus, tlat); + wr=rand(1,pop_size).*(max_wr-min_wf)+min_wr; + ws=rand(1,pop_size).*(t-min_ws)+min_ws; + max_wm=compute_wm_v3(taum, tmot); + wm=rand(1,pop_size).*(max_wm-min_wm)+min_wm; + new_pop=[wf;wr;taus;wi;ws;t;wm;taum]; + % put non-mutated parametrs from the old population + count=0; + for i=1:n_surv + for ii=1:n_offsrping + count=count+1; + new_pop(mut_pars(:,count),count)=this_pop(mut_pars(:,count),surv(i)); + end + end + this_pop=new_pop; + % convert taus to unitless + this_pop(3,:)=dt./this_pop(3,:); + this_pop(8,:)=dt./this_pop(8,:); + end + end + + % if last min_n_gen gen were the same we appear here! + if super_gen>=min_n_gen + if all(best_perf(super_gen_switch_id((super_gen-min_n_gen+1):super_gen))==best_perf(gen)) + process1=false; + do_the_breeding=false; + else + do_the_breeding=true; + end + else + do_the_breeding=true; + end + if do_the_breeding + % let them breed and mutate + mut_pars=rand(n_pars,pop_size)>=mut_rate; + mut_pars(:,1:n_offsrping:pop_size)=true; + % narrow the ranges by 25 % + % 'wf','wr','taus','wi','ws','t','wm','taum'; + min_taus=min_taus+0.25*(best_par_this_fish(3)-min_taus); + max_taus=max_taus-0.25*(max_taus-best_par_this_fish(3)); + min_taum=min_taum+0.25*(best_par_this_fish(8)-min_taum); + max_taum=max_taum-0.25*(max_taum-best_par_this_fish(8)); + min_wi=min_wi+0.25*(best_par_this_fish(4)-min_wi); + max_wi=max_wi-0.25*(max_wi-best_par_this_fish(4)); + min_t=min_t+0.25*(best_par_this_fish(6)-min_t); + max_t=max_t-0.25*(max_t-best_par_this_fish(6)); + min_wr=min_wr+0.25*(best_par_this_fish(2)-min_wr); + min_ws=min_ws+0.25*(best_par_this_fish(5)-min_ws); + min_wm=min_wm+0.25*(best_par_this_fish(7)-min_wm); + % generate new random population (independent parameters) + if max_taus-min_taus>0 && ... + max_wi-min_wi>0 && ... + max_t-min_t>0 && ... + max_taum-min_taum>0 + taus=rand(1,pop_size).*(max_taus-min_taus)+min_taus; + wi=rand(1,pop_size).*(max_wi-min_wi)+min_wi; + t=rand(1,pop_size).*(max_t-min_t)+min_t; + taum=rand(1,pop_size).*(max_taum-min_taum)+min_taum; + % generate dependent parameters + min_wf=compute_wf_v3(t, taus, lat_max); + max_wf=compute_wf_v3(t, taus, lat_min); + wf=rand(1,pop_size).*(max_wf-min_wf)+min_wf; + max_wr=compute_max_wr_v3(taus, tlat); + wr=rand(1,pop_size).*(max_wr-min_wf)+min_wr; + ws=rand(1,pop_size).*(t-min_ws)+min_ws; + max_wm=compute_wm_v3(taum, tmot); + wm=rand(1,pop_size).*(max_wm-min_wm)+min_wm; + new_pop=[wf;wr;taus;wi;ws;t;wm;taum]; + % put non-mutated parametrs from the old population + count=0; + for i=1:n_surv + for ii=1:n_offsrping + count=count+1; + new_pop(mut_pars(:,count),count)=this_pop(mut_pars(:,count),surv(i)); + end + end + this_pop=new_pop; + % convert taus to unitless + this_pop(3,:)=dt./this_pop(3,:); + this_pop(8,:)=dt./this_pop(8,:); + process2=true; + else + process2=false; + process1=false; + end + end + end + best_par(:,f)=best_par_this_fish; +end +toc +save([pathname_model '\fitting\' my_name '.mat'],'best_par'); \ No newline at end of file diff --git a/analysis/feedback_control_model/readme.txt b/analysis/feedback_control_model/readme.txt new file mode 100644 index 0000000..dfbc24d --- /dev/null +++ b/analysis/feedback_control_model/readme.txt @@ -0,0 +1,32 @@ +The core of the model is brain_iteration_v3.m + +It computes two variables: +1. brain_state - current state of the model nodes: forward and reverse velocity sensors, velocity and motor integrators, and motor output generator. +2. swim - binary swimming variable + +... based on: +1. Previous brain_state +2. Previous swim +3. Current grating speed (mm/s) +4. Set of 8 model parameters + +Another useful function is exp_iteration_v3.m +It computes current grating speed depending on behavior of the model and reafference condition. +Reafference condition is defined as a 1 x 5 array with the following columns: +1. gain +2. lag +3. shunted (true) or non-shunted lag (false) +4. gain drop start (measured in frames with respect to the bout onset) +5. gain drop end + +These two functions are combined in an experiment program that defines an artificial experimental protocol. +Protocols used in this study can be found in the model_protocols folder: +1. model_one_bout_trial_v3 - grating starts moving 0.7 s after beginnig of the protocol +and stops 0.4 s after bout offset. The trial stops 1.1 s after bout offset. This protocol was used to present small pictograms of model nodes in Fig. 2b. +2. model_v3_real_trial.m - same as trials used in the acute reaction experiment. It was used to show model traces in an example trial (Fig. S1). +3. model_short_trial_v3.m - grating starts moving 0.3 s after beginnig of the protocol. The trial terminates at the onset of the 2nd bout. +This protocol was used for fitting the model to real data (Fig. 2c). + +Finally, model_compute_parameters_v3 simply computes second bout and interbout duration after model_short_trial_v3.m (Fig. 2c). + +model_v3_individual_fish_genetic_fitting.m was used to fit model parameters to all individual fish tested in the acute reaction experiment. \ No newline at end of file diff --git a/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_behavior.m b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_behavior.m new file mode 100644 index 0000000..9573a34 --- /dev/null +++ b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_behavior.m @@ -0,0 +1,303 @@ +% this progam analyses behavior of the long-term adaptation experiment during +% PC lightsheet imaging. It perfoms the same computations as behavioral_analysis.m +% but using a different sourse data format + +%% pathnames +clc; close all; clear all; +% original path to the raw behavioral hdf5 data saved by Stytra +pathname_data='J:\_Shared\experiments\E0030_long_term_adaptation\v09_lightsheet\data_behavior\'; +% final path to pre-processed data +pathname_MS_data = '...\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_behavior=[pathname_MS_data 'PC_imaging_long_term_adaptation\behavior\']; + +%% timing variables +dt=0.005; +rest_dur=7.5; +trial_dur=15; +full_trial_dur=trial_dur+2*rest_dur; +calib_notr=10; +pre_notr=10; +main_notr=50; +post_notr=50; +notr=calib_notr+pre_notr+main_notr+post_notr; +exp_dur=notr*full_trial_dur; +gr_starts=rest_dur:full_trial_dur:rest_dur+(notr-1)*full_trial_dur; +gr_ends=gr_starts+trial_dur; +t_pre_start=full_trial_dur*calib_notr; +t_main_start=full_trial_dur*(calib_notr+pre_notr); +t_post_start=full_trial_dur*(calib_notr+pre_notr+main_notr); +time_be=dt:dt:exp_dur; + +%% bout parameters +bout_par_names={'bout_duration','next_interbout_duration'}; +trial_par_names={'number_of_bouts','latency'}; +bout_arrays_names={'power','grspeed'}; +measures={'first','mean'}; + +%% loop through all fish +cd(pathname_data); +all_fish=dm_dir('*_f*'); +num_fish=length(all_fish); +for f=1:num_fish + this_fish=all_fish{f}; + this_path=[pathname_data this_fish '\']; + cd(this_path); + filename=[pathname_behavior this_fish '_behavior.mat']; + + %% work with metadata + filename_meta=dm_dir('*_metadata.json'); + meta2=read_json(filename_meta{end}); + meta=struct; + meta.dpf=meta2.general.animal.age; + meta.genotype=meta2.general.animal.genotype; + if isfield(meta2.imaging.microscope_config,'lightsheet') + meta.F=meta2.imaging.microscope_config.lightsheet.scanning.z.frequency; + meta.num_planes = meta2.imaging.microscope_config.lightsheet.scanning.triggering.n_planes; + meta.piezo_z_amp = meta2.imaging.microscope_config.lightsheet.scanning.z.piezo_max - meta2.imaging.microscope_config.lightsheet.scanning.z.piezo_min; + else + meta.F=meta2.imaging.microscope_config.piezo_z.frequency; + meta.num_planes = meta2.imaging.microscope_config.camera_trigger.n_planes; + meta.piezo_z_amp = meta2.imaging.microscope_config.piezo_z.amplitude; + end + meta.pulse_times = (0:(1/meta.F)/meta.num_planes:1/meta.F)'; + meta.pulse_times = meta.pulse_times(1:end-1); + meta.z_step = meta.piezo_z_amp*2/meta.num_planes; + meta.rez = 0.6; + if isfield(meta2.stimulus.log{3},'lag') + meta.lag_condition=meta2.stimulus.log{3}.lag; + else + meta.lag_condition=meta2.stimulus.log{4}.lag; + end + %% work with stimulus + filename_stim=cell2mat(dm_dir('*_stimulus_log.hdf5')); + var_names_stim = h5read(filename_stim,'/data/block0_items'); + for i=1:length(var_names_stim) + this_name = var_names_stim{i}; + this_name(double(this_name)==0)=[]; + var_names_stim{i} = this_name; + end + stim = h5read(filename_stim,'/data/block0_values'); + bad_points=diff(stim(strcmp(var_names_stim,'t'),:))==0; + stim(:,bad_points)=[]; + t_stim=stim(strcmp(var_names_stim,'t'),:); + base_grspeed=uint8(-nansum(stim(contains(var_names_stim,'base_vel'),:),1)); + grspeed=single(-nansum(stim(contains(var_names_stim,'vel') & ~contains(var_names_stim,'base_vel'),:),1)); + swim=nansum(stim(contains(var_names_stim,'fish_swimming'),:),1); + clear stim filename_stim var_names_stim; + bout_starts_ids=find(diff([0 swim])==1); + bout_ends_ids=find(diff([0 swim 0])==-1); + if ~isempty(bout_ends_ids) + if bout_ends_ids(end)>length(t_stim) + bout_ends_ids(end)=length(t_stim); + end + end + nob=length(bout_starts_ids); + + %% work with behavior + filename_be=cell2mat(dm_dir('*_behavior_log.hdf5')); + var_names_be = h5read(filename_be,'/data/block0_items'); + for i=1:length(var_names_be) + this_name = var_names_be{i}; + this_name(double(this_name)==0)=[]; + var_names_be{i} = this_name; + end + be = h5read(filename_be,'/data/block0_values'); + bad_points=diff(be(strcmp(var_names_be,'t'),:))==0; + be(:,bad_points)=[]; + t_be=be(strcmp(var_names_be,'t'),:); + tail=be(strcmp(var_names_be,'tail_sum'),:); + clear be filename_be var_names_be; + % interpolate tail trace, swim and grating speed + tail=interp1(t_be,tail,time_be); + swim=interp1(t_stim,swim,time_be)>=0.5; + grspeed=interp1(t_stim,grspeed,time_be); + grmov=interp1(t_stim,double(base_grspeed),time_be)>0.5; + % scale the tail + tail=tail-nanmean(tail(~swim)); + tail=tail/nanstd(tail(swim)); + tail(isnan(tail))=0; + % build vigor trace + vigor=nan(1,length(tail)); + for i=0.05/dt:length(tail) + vigor(i)=std(tail(i-(0.05/dt-1):i)); + end + + %% detect bouts accurately (and find min and max tail positions) + bouts.start=nan(1,nob); + bouts.end=nan(1,nob); + bouts.bad_bouts=false(1,nob); + mm_time_array=nan(nob,1000); + mm_val_array=mm_time_array; + max_tf_array=false(nob,1000); + for b=1:nob + bst0=round((t_stim(bout_starts_ids(b))-0.1)/dt); + bet0=round(t_stim(bout_ends_ids(b))/dt); + bouts.start(b)=t_stim(bout_starts_ids(b)); + bouts.end(b)=t_stim(bout_ends_ids(b)); + + % find individual flicks + this_mm_time_array=[]; + this_mm_val_array=[]; + this_max_tf_array=[]; + c=0; + if bst0<2 + bst0=2; + end + if bet0>exp_dur/dt-1 + bet0=exp_dur/dt-1; + end + for i=bst0:bet0 + if tail(i)>=tail(i-1) && tail(i)>tail(i+1) + c=c+1; + this_mm_time_array(c)=time_be(i); + this_mm_val_array(c)=tail(i); + this_max_tf_array(c)=true; + elseif tail(i)<=tail(i-1) && tail(i)=2 + bad_flicks=[abs(diff(this_mm_val_array))<0.14 false] & [false flip(abs(diff(flip(this_mm_val_array)))<0.14)]; + if abs(this_mm_val_array(2)-this_mm_val_array(1))<0.14 + bad_flicks(1)=true; + end + if abs(this_mm_val_array(end)-this_mm_val_array(end-1))<0.14 + bad_flicks(end)=true; + end + bad_flicks=bad_flicks | [false flip(abs(diff(flip(this_mm_time_array)))>0.1)]; + this_mm_time_array(bad_flicks)=[]; + this_mm_val_array(bad_flicks)=[]; + this_max_tf_array(bad_flicks)=[]; + bad_flicks=diff(this_max_tf_array)==0; + this_mm_time_array(bad_flicks)=[]; + this_mm_val_array(bad_flicks)=[]; + this_max_tf_array(bad_flicks)=[]; + if length(this_mm_time_array)>=2 + bouts.start(b)=this_mm_time_array(1); + bouts.end(b)=this_mm_time_array(end); + else + bouts.bad_bouts(b)=true; + end + else + bouts.bad_bouts(b)=true; + end + n=length(this_mm_time_array); + if n>1000 + n=1000; + end + mm_time_array(b,1:n)=this_mm_time_array(1:n); + mm_val_array(b,1:n)=this_mm_val_array(1:n); + max_tf_array(b,1:n)=this_max_tf_array(1:n); + end + % shorten the flicks arrays + mm_n=find(all(isnan(mm_time_array),1),1)-1; + if ~isempty(mm_n) + if mm_n>=50 + mm_n=50; + end + mm_time_array=mm_time_array(:,1:mm_n); + mm_val_array=mm_val_array(:,1:mm_n); + max_tf_array=max_tf_array(:,1:mm_n); + end + % create array of bad bouts + bouts.long_bouts=bouts.end-bouts.start>=0.3; + bouts.short_bouts=bouts.end-bouts.start<0.1; + bouts.bad_bouts=bouts.bad_bouts | ... % bouts that are already bad (failed to detect them properly) + bouts.short_bouts |... % bouts which are shorter than 100 ms + [false bouts.start(2:end)-bouts.end(1:end-1)<0.1] | [bouts.start(2:end)-bouts.end(1:end-1)<0.1 false] |... % bouts with interbouts shorter than 100 ms (tipically, these are bouts which were detected as 2 bouts) + all(isnan(mm_time_array),2)' |... % bouts with no flicks + max(diff(mm_time_array,1,2),[],2)'>0.1; % bouts with max delta flick time > 100 ms (this happens during some wierd ugly bouts) + % find spontaneous bouts (i.e. bouts which started after trial start and finished before trial end) + bouts.spont_bouts=true(1,nob); + for g=1:notr + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end=t_main_start; + bouts.main_bouts=bouts.main_bouts; + % good bouts: i.e. they are not bad, not spontaneous and happened during main part + bouts.good_bouts=bouts.main_bouts & ~bouts.bad_bouts & ~bouts.spont_bouts; + + %% find bout parameters + bouts.trial=nan(1,nob); + bouts.bout_duration=bouts.end-bouts.start; + bouts.next_interbout_duration=nan(1,nob); + for g=1:notr + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end=1.1/dt + be=bs+1.1/dt-1; + end + bouts.tail(b,:)=zeros(1,1.1/dt); + bouts.tail(b,1:be-bs+1)=tail(bs:be); + bouts.power(b,:)=zeros(1,1.1/dt); + bouts.power(b,1:be-bs+1)=tail(bs:be).^2; + bouts.grspeed(b,:)=nan(1,1.1/dt); + bouts.grspeed(b,1:be-bs+1)=grspeed(bs:be); + end + end + for p=1:length(bout_par_names) + bouts.(bout_par_names{p})(bouts.bad_bouts | bouts.spont_bouts)=nan; + end + for p=1:length(bout_arrays_names) + bouts.(bout_arrays_names{p})(bouts.bad_bouts | bouts.spont_bouts,:)=nan; + end + bouts.tail(bouts.bad_bouts | bouts.spont_bouts,:)=nan; + + %% find trial averages + trials=[]; + vigor_for_imagesc=nan(notr,full_trial_dur/dt); + for g=1:notr + trial_start=round((gr_starts(g)-rest_dur)/dt)+1; + trial_end=round((gr_ends(g)+rest_dur)/dt); + vigor_for_imagesc(g,:)=vigor(trial_start:trial_end); + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end0 + trials.(this_par).first(g)=these_bouts(1); + trials.(this_par).mean(g)=mean(these_bouts); + else + trials.(this_par).first(g)=nan; + trials.(this_par).mean(g)=nan; + end + end + for p=1:length(bout_arrays_names) + this_par=bout_arrays_names{p}; + these_bouts=bouts.(this_par)(bouts_in_this_trial,:); + these_bouts=these_bouts(~all(isnan(these_bouts),2),:); + trials.(this_par).n(g)=size(these_bouts,1); + if trials.(this_par).n(g)>0 + trials.(this_par).first(g,:)=these_bouts(1,:); + trials.(this_par).mean(g,:)=nanmean(these_bouts,1); + else + trials.(this_par).first(g,:)=nan(1,size(bouts.(this_par),2)); + trials.(this_par).mean(g,:)=nan(1,size(bouts.(this_par),2)); + end + end + end + + %% save the data + save(filename,'time_be','tail','grspeed','grmov','swim','bouts','trials','meta'); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_crit_suite2p.m b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_crit_suite2p.m new file mode 100644 index 0000000..8540e41 --- /dev/null +++ b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_crit_suite2p.m @@ -0,0 +1,116 @@ +% this program compute 4 criteria from scores: +% Criterion 1: difference between trials 11:20 and 21:30 +% Criterion 2: difference between trials 21:30 and 61:70 +% Criterion 3: difference between trials 61:70 and 71:80 +% Criterion 4: difference between trials 71:80 and 111:120 +% To compute the difference, we average scores within a block of 10 trials +% and subtract +% To binarize the scores, we do this 1000 times on randomly shuffled +% scores, and check whether the actual difference is within 95 % of the +% null-distribution + +%% pathnames +clc; close all; clear all; +pathname_MS_data = '...\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_PC_imaging_results=[pathname_MS_data 'PC_imaging_long_term_adaptation\']; +pathname_scores=[pathname_PC_imaging_results 'scores\']; +pathname_crit=[pathname_PC_imaging_results 'criteria\']; + +%% loop through all fish +cd(pathname_scores); +all_fish=dm_dir('*_f*_scores.mat'); +all_fish=strrep(all_fish,'_scores.mat',''); +n_fish=length(all_fish); +p_thresh = 0.05; +fish_id = all_fish{1}; +load([pathname_scores fish_id '_scores.mat'],'scores_be','scores_im','scores_motor_regr'); +n_boots = 10000; +progressbar('fish...','bootstraps...'); +for f=1:n_fish + fish_id = all_fish{f}; + filename = [pathname_crit fish_id '_criteria.mat']; + load([pathname_scores fish_id '_scores.mat'],'scores_im','scores_be','scores_motor_regr'); + n_rois = size(scores_im,1); + + %% compute criteria + crit_im = nan(n_rois,4); + temp_block2 = nanmean(scores_im(:,11:20),2); + temp_block3 = nanmean(scores_im(:,21:30),2); + temp_block7 = nanmean(scores_im(:,61:70),2); + temp_block8 = nanmean(scores_im(:,71:80),2); + temp_block12 = nanmean(scores_im(:,111:120),2); + crit_im(:,1) = temp_block3 - temp_block2; + crit_im(:,2) = temp_block7 - temp_block3; + crit_im(:,3) = temp_block8 - temp_block7; + crit_im(:,4) = temp_block12 - temp_block8; + + crit_motor_regr = nan(1,4); + temp_block2 = nanmean(scores_motor_regr(11:20),2); + temp_block3 = nanmean(scores_motor_regr(21:30),2); + temp_block7 = nanmean(scores_motor_regr(61:70),2); + temp_block8 = nanmean(scores_motor_regr(71:80),2); + temp_block12 = nanmean(scores_motor_regr(111:120),2); + crit_motor_regr(1) = temp_block3 - temp_block2; + crit_motor_regr(2) = temp_block7 - temp_block3; + crit_motor_regr(3) = temp_block8 - temp_block7; + crit_motor_regr(4) = temp_block12 - temp_block8; + + crit_be=nan(1,4); + temp_block2 = nanmean(scores_be(11:20)); + temp_block3 = nanmean(scores_be(21:30)); + temp_block7 = nanmean(scores_be(61:70)); + temp_block8 = nanmean(scores_be(71:80)); + temp_block12 = nanmean(scores_be(111:120)); + crit_be(1) = temp_block3 - temp_block2; + crit_be(2) = temp_block7 - temp_block3; + crit_be(3) = temp_block8 - temp_block7; + crit_be(4) = temp_block12 - temp_block8; + + %% compute null-distribution + H0_im=nan(n_rois,n_boots); + H0_motor_regr=nan(1,n_boots); + H0_be=nan(1,n_boots); + for i=1:n_boots + rand_ind = [1:10 randperm(110)+10]; + + scores_im_shuf=scores_im(:,rand_ind); + temp_block2 = nanmean(scores_im_shuf(:,11:20),2); + temp_block3 = nanmean(scores_im_shuf(:,21:30),2); + H0_im(:,i)=temp_block3-temp_block2; + scores_motor_regr_shuf=scores_motor_regr(rand_ind); + temp_block2 = nanmean(scores_motor_regr_shuf(11:20)); + temp_block3 = nanmean(scores_motor_regr_shuf(21:30)); + H0_motor_regr(i)=squeeze(temp_block3-temp_block2); + + scores_be_shuf = scores_be(rand_ind); + temp_block2 = nanmean(scores_be_shuf(11:20)); + temp_block3 = nanmean(scores_be_shuf(21:30)); + H0_be(i)=temp_block3-temp_block2; + progressbar([],i/n_boots); + end + + %% find percentiles + prcnt_min_im = prctile(H0_im,p_thresh*100/2,2); + prcnt_max_im = prctile(H0_im,100-p_thresh*100/2,2); + prcnt_min_motor_regr = prctile(H0_motor_regr,p_thresh*100/2); + prcnt_max_motor_regr = prctile(H0_motor_regr,100-p_thresh*100/2); + prcnt_min_be = prctile(H0_be,p_thresh*100/2); + prcnt_max_be = prctile(H0_be,100-p_thresh*100/2); + + %% find significant criteria + crit_im_signif = zeros(n_rois,4,'single'); + for i=1:4 + crit_im_signif(crit_im(:,i)prcnt_max_im,i)=1; + end + crit_motor_regr_signif = zeros(1,4,'single'); + crit_motor_regr_signif(crit_motor_regrprcnt_max_motor_regr)=1; + crit_be_signif = zeros(1,4); + crit_be_signif(crit_beprcnt_max_be)=1; + + %% save + save(filename,'crit_be','crit_be_signif','crit_im','crit_im_signif','crit_motor_regr','crit_motor_regr_signif','H0_im','H0_motor_regr','H0_be'); + progressbar(f/n_fish,[]); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_lighsheet_analysis.m b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_lighsheet_analysis.m new file mode 100644 index 0000000..90a225b --- /dev/null +++ b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_lighsheet_analysis.m @@ -0,0 +1,40 @@ +%% initial stuff +clc; close all; clear all; +addpath('C:\Markov_et_al_2021_Nat_Commun_data_code\analysis_code\imaging_analysis\PC_imaging_long_term_adaptation'); +addpath('C:\Markov_et_al_2021_Nat_Commun_data_code\analysis_code\MATLAB_functions'); + +%% morphing anatomies +% Manually save _anatomy.tif as .nrrd using FIJI nrrd writer +% Danger! Do not run the next program as a whole +% Morphing of these data was tricky, so +% it should be run section by section with manual tweaking +DM_E0030_v09_morph_anatomies; + +%% pre-processing +% analysis of the behavior, same as for behavioral experiments +DM_E0030_v09_behavior; +% extract traces and ROIs, filters traces, build motor regressor +DM_E0030_v09_preprocessing_suite2p; +% morph ROIs to the reference brain +DM_E0030_v09_morph_ROIs; + +% these four programs save pre-processed data to: +% ...\Markov_et_al_2021_Nat_Commun_data&code\data\PC_imaging_long_term_adaptation\... +% behavior +% anatomies +% traces +% ROIs + +%% subsequent analysis +% compute grating- and bout-triggered averages +DM_E0030_v09_trigaver_suite2p; +% compte scores +DM_E0030_v09_scores_suite2p; +% compute criteria +DM_E0030_v09_crit_suite2p; + +% these three programs save final data to: +% ...\Markov_et_al_2021_Nat_Commun_data&code\data\PC_imaging_long_term_adaptation\... +% triggered_traces +% scores +% criteria \ No newline at end of file diff --git a/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_morph_ROIs.m b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_morph_ROIs.m new file mode 100644 index 0000000..db8cf76 --- /dev/null +++ b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_morph_ROIs.m @@ -0,0 +1,88 @@ +%% pathnames +clc; close all; clear all; + +% path to raw anatomies +pathname_data='J:\_Shared\experiments\E0030_long_term_adaptation\v09_lightsheet\data_imaging_suite2p\'; +pathname_raw_anat=[pathname_data 'anatomies\']; +% path to morphed ROIs +pathname_MS_data = '...\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_PC_imaging_results=[pathname_MS_data 'PC_imaging_long_term_adaptation\']; +pathname_morphed_anat=[pathname_PC_imaging_results 'anatomies\']; +pathname_ROIs = [pathname_PC_imaging_results 'ROIs\']; +path_to_lists=[pathname_PC_imaging_results 'temp_pathname\']; +pathname_ref = [pathname_MS_data 'reference_brain_stacks\']; +filename_ref = 'PortuguesLab_PC_ref.nrrd'; +str_ref=[pathname_ref filename_ref]; +[sz_ref, rez_ref] = read_nrrd_metadata(str_ref); + +%% loop through fish +cd(pathname_ROIs); +all_fish=dm_dir('*_f*_ROIs.mat'); +all_fish=strrep(all_fish,'_ROIs.mat',''); +n_fish=length(all_fish); +progressbar('Fish progress...','Morphing ROIs...','Computing ROI coordinates...'); +for f=1:n_fish + fish_id=all_fish{f}; + load([pathname_ROIs fish_id '_ROIs.mat'],'ROIs','ROI_coord_ori_lin','ROI_coord_ori_vx_rcp'); + n_ROIs=length(ROI_coord_ori_lin); + [sz_ori, rez_ori] = read_nrrd_metadata([pathname_raw_anat fish_id '_anatomy.nrrd']); + affine_x=[pathname_morphed_anat fish_id '_anatomy.xform']; + ROIs_morphed=zeros(sz_ref,'uint16'); + for i=1:n_ROIs + % original indeces in voxels + rcp_ori_vx = double(ROI_coord_ori_vx_rcp{i}); + % original indeces in microns + rcp_ori_um = rcp_ori_vx.*rez_ori; + rows_ori_um=rcp_ori_um(:,1); + columns_ori_um=rcp_ori_um(:,2); + planes_ori_um=rcp_ori_um(:,3); + % extend ROIs in z + plane_ori_um=unique(planes_ori_um); + ext_planes=plane_ori_um-1:-1:plane_ori_um-rez_ori(3)+1; + n_ext_planes=length(ext_planes); + for ii=ext_planes + planes_ori_um=[planes_ori_um; ones(length(rows_ori_um),1)*ii]; %#ok + end + rows_ori_um=repmat(rows_ori_um,n_ext_planes+1,1); + columns_ori_um=repmat(columns_ori_um,n_ext_planes+1,1); + % morphed indeces in microns + rcp_morphed_um=DM_morph_non_ref_coord([rows_ori_um,columns_ori_um,planes_ori_um],affine_x,path_to_lists); + % morphed indeces in voxels + rcp_morphed_vx=rcp_morphed_um./rez_ref; + rcp_morphed_vx=unique([floor(rcp_morphed_vx);ceil(rcp_morphed_vx)],'rows'); + % remove out-of-stack voxels + bad_coord=find(any(rcp_morphed_vx<=0,2) | rcp_morphed_vx(:,1)>sz_ref(1) | rcp_morphed_vx(:,2)>sz_ref(2) | rcp_morphed_vx(:,3)>sz_ref(3)); + rcp_morphed_vx(bad_coord,:)=[]; + % remove 1/2 voxels that intercept with other already morphed ROIs + if ~isempty(rcp_morphed_vx) + % morphed linear coordinates + lin_morphed=sub2ind(sz_ref, rcp_morphed_vx(:,1), rcp_morphed_vx(:,2), rcp_morphed_vx(:,3)); + % tf stack of this ROI + this_ROI = false(sz_ref); + this_ROI(lin_morphed)=true; + % find if there are ROIs already + ROIs_there = unique(ROIs_morphed(this_ROI))'; + ROIs_there(ROIs_there==0)=[]; + for ii=ROIs_there + % find pixels that are intesepting and remove 1/2 + px = find(this_ROI & ROIs_morphed==ii); + this_ROI(px(randperm(length(px),round(length(px)/2))))=false; + end + % add this to ROIs morphed + ROIs_morphed(this_ROI)=i; + end + progressbar([],i/n_ROIs,[]); + end + + % find ROI coordinates + ROI_coord_morphed_lin=cell(n_ROIs,1); + for i=1:n_ROIs + ROI_coord_morphed_lin{i}=find(ROIs_morphed==i); + progressbar([],[],i/n_ROIs); + end + + % save + ROI_coord = ROI_coord_morphed_lin; + save([pathname_ROIs fish_id '_ROIs.mat'],'ROI_coord'); + progressbar(f/n_fish,[],[]); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_morph_anatomies.m b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_morph_anatomies.m new file mode 100644 index 0000000..b6cee1c --- /dev/null +++ b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_morph_anatomies.m @@ -0,0 +1,110 @@ +% this code is not supposed to be executed as a whole. Run sections +% separately and check manually how thigs go + +%% initial stuff +clc; close all; clear all; +pathname_results='C:\Users\dmarkov\Desktop\Data_Daniil\E0030_v09\'; +pathname_raw_anat=[pathname_results 'anatomies\raw_nrrds\']; +pathname_final_anat = [pathname_results 'anatomies\morphed\']; +pathname_MS_data = '...\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_ref = [pathname_MS_data 'reference_brain_stacks\']; +filename_ref = 'PortuguesLab_PC_ref.nrrd'; +str_ref=[pathname_ref filename_ref]; +sz_ref = read_nrrd_metadata(str_ref); + +%% try to morph all files to the original reference +cd(pathname_raw_anat); +all_fish=dm_dir('*_f*_anatomy.nrrd'); +progressbar('Morphing anatomies...'); +for f=1:length(all_fish) + str_final = [pathname_final_anat all_fish{f}]; + if exist(str_final,'file')~=2 + str_morph = [pathname_raw_anat all_fish{f}]; + affine_x = strrep(str_final,'.nrrd','.xform'); + morph_stack_to_ref(str_ref, str_morph, str_final, affine_x); + end + progressbar(f/length(all_fish)); +end +% this resulted in 15 acceptable morphings. Manually delete 10 bad ones and +% compute the mean transformed stack + +%% create average stack +cd(pathname_final_anat); +all_fish=dm_dir('*_f*_anatomy.nrrd'); +A=zeros(sz_ref); +for f=1:length(all_fish) + str_final = [pathname_final_anat all_fish{f}]; + B = double(nrrdread(str_final)); + A=A+B; +end +A=uint8(A/max(A(:))*255); +mat2tiff(A,pathname_final_anat,['average_' num2str(length(all_fish)) '_brains.tif']); +% set the correct rezolution manually and save as nrrd + +%% now try to morph the rest of the fish to this new averaged stack +str_ref2=[pathname_final_anat 'average_24_brains.nrrd']; +cd(pathname_raw_anat); +all_fish=dm_dir('*_f*_anatomy.nrrd'); +progressbar('Morphing anatomies...'); +for f=1:length(all_fish) + str_final = [pathname_final_anat all_fish{f}]; + if exist(str_final,'file')~=2 + str_morph = [pathname_raw_anat all_fish{f}]; + affine_x = strrep(str_final,'.nrrd','.xform'); + morph_stack_to_ref(str_ref2, str_morph, str_final, affine_x); + end + progressbar(f/length(all_fish)); +end +% morphing to average of 15 brains: one more fish. Create another averaged stack and try again +% morphing to average of 19 brains: no new fish. Change the approach +% morphing to average of 24 brains: did not work for the last stack + +%% Try to morph each of the remaining fish to each of the morphed fish +cd(pathname_raw_anat); +all_fish=dm_dir('*_f*_anatomy.nrrd'); +all_morphed_fish=dm_dir([pathname_final_anat '*_f*_anatomy.nrrd']); +progressbar('Morphing anatomies...'); +for f=1:length(all_fish) + if exist([pathname_final_anat all_fish{f}],'file')~=2 + str_morph = [pathname_raw_anat all_fish{f}]; + pathname_final2=[pathname_final_anat strrep(all_fish{f},'_anatomy.nrrd','') '_individual_morphings\']; + mkdir(pathname_final2); + for j=1:length(all_morphed_fish) + str_ref2 = [pathname_final_anat all_morphed_fish{j}]; + str_final = [pathname_final2 strrep(all_fish{f},'_anatomy.nrrd','') '_2_' strrep(all_morphed_fish{j},'_anatomy.nrrd','') '.nrrd']; + affine_x = strrep(str_final,'.nrrd','.xform'); + morph_stack_to_ref(str_ref2, str_morph, str_final, affine_x); + end + end + progressbar(f/length(all_fish)); +end +% morph 9 fish to 16 morphed fish: resulted in OK morphings for 8 fish. Keep the best nrrd stack +% morph the remaining fish to 24 morphed fish: kinda worked + +%% move them to the original folder +cd(pathname_final_anat); +all_fish=dm_dir('*_f*_individual_morphings'); +for f=1:length(all_fish) + fish_id=strrep(all_fish{f},'_individual_morphings',''); + cd([pathname_final_anat all_fish{f}]); + ref_fish_id = dm_dir('*_f*_2_*_f*.nrrd'); + movefile([pathname_final_anat fish_id '_individual_morphings\' ref_fish_id{1}], [pathname_final_anat fish_id '_anatomy.nrrd']); + movefile(strrep([pathname_final_anat fish_id '_individual_morphings\' ref_fish_id{1}],'.nrrd','.xform'), [pathname_final_anat fish_id '_anatomy.xform']); +end + +%% to check the everything is correct, apply computed transformations to each stack +cd(pathname_raw_anat); +all_fish=dm_dir('*_f*_anatomy.nrrd'); +progressbar('Morphing anatomies...'); +for f=1:length(all_fish) + str_final = [pathname_final_anat all_fish{f}]; + if exist(str_final,'file')~=2 + str_morph = [pathname_raw_anat all_fish{f}]; + affine_x = strrep(str_final,'.nrrd','.xform'); + apply_morphing(str_ref, str_morph, str_final,affine_x) + end + progressbar(f/length(all_fish)); +end + +% final 25 morphed anatomies are the ones uploaded with this manuscript into this folder: +% ...\Markov_et_al_2021_Nat_Commun_data&code\data\PC_imaging_long_term_adaptation\anatomies \ No newline at end of file diff --git a/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_preprocessing_suite2p.m b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_preprocessing_suite2p.m new file mode 100644 index 0000000..5515874 --- /dev/null +++ b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_preprocessing_suite2p.m @@ -0,0 +1,81 @@ +% this progam performs pre-processing of the traces and ROI +% of the long-term adaptation experiment during PC lightsheet imaging. + +%% pathnames +clc; close all; clear all; +% path to raw data +pathname_raw_data='J:\_Shared\experiments\E0030_long_term_adaptation\v09_lightsheet\data_imaging_suite2p\'; +pathname_data_traces=[pathname_raw_data 'traces_filtered\']; +pathname_data_ori_planes=[pathname_raw_data 'plane_idxs\']; +pathname_data_ROIs=[pathname_raw_data 'rois_filtered\']; +pathname_data_raw_anat=[pathname_raw_data 'anatomies\']; +% path to pre-processed data uploaded with the manuscript +pathname_MS_data = '...\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_PC_imaging_results=[pathname_MS_data 'PC_imaging_long_term_adaptation\']; +pathname_behavior=[pathname_PC_imaging_results 'behavior\']; +pathname_traces=[pathname_PC_imaging_results 'traces\']; +pathname_ROIs=[pathname_PC_imaging_results 'ROIs\']; + +%% cutoff frequency for high-pass filtering +fc_baseline=1/300; % Hz, 5 min period + +%% loop through all fish +all_fish=dm_dir([pathname_data_traces '*_f*_traces.h5']); +all_fish=strrep(all_fish,'_traces.h5',''); +n_fish=length(all_fish); +progressbar('Fish...','Traces...') +for f=1:n_fish + fish_id=all_fish{f}; + + %% load traces, ROIs, ori planes and anatomies, as well as metadata and swim for motor regressor + load([pathname_behavior fish_id '_behavior.mat'],'meta','swim','time_be'); + traces = h5read([pathname_data_traces fish_id '_traces.h5'],'/traces')'; + traces=double(traces); + ROIs = tiff2mat(pathname_data_ROIs, [fish_id '_rois.tif']); + ori_planes = h5read([pathname_data_ori_planes fish_id '_plane_idxs.h5'],'/plane_idxs')'; + anat = tiff2mat(pathname_data_raw_anat, [fish_id '_anatomy.tif']); + [n_ROIs, n_frames] = size(traces); + sz = size(anat); + + %% high-pass filter for removing slow drift in the traces + [bb_baseline,aa_baseline]=butter(3,2*fc_baseline/meta.F,'high'); + traces(traces==0)=nan; + + %% process this fish + ROI_coord_ori_lin = cell(n_ROIs,1); + ROI_coord_ori_vx_rcp = cell(n_ROIs,1); + time_offsets=nan(n_ROIs,1); + traces2=nan(n_ROIs,n_frames,'single'); + for i=1:n_ROIs + ROI_coord_ori_lin{i} = uint32(find(ROIs==i)); + [rows, columns, planes] = ind2sub(sz,ROI_coord_ori_lin{i}); + ROI_coord_ori_vx_rcp{i} = uint16([rows columns planes]); + plane=unique(planes); + time_offsets(i)=meta.pulse_times(ori_planes(plane)); + traces2(i,:) = process_trace_here(traces(i,:),bb_baseline,aa_baseline); + progressbar([],i/n_ROIs) + end + traces=traces2; + + %% build motor regressor + time_im=1/meta.F:1/meta.F:n_frames/meta.F; + s_half_decay = genotype2tau('GCaMP6s'); + my_kernel=2.^(-time_be/s_half_decay); + trace_motor_regr=trace2regressor(swim,my_kernel,time_be,time_im); + trace_motor_regr = process_trace_here(trace_motor_regr,bb_baseline,aa_baseline); + + %% save + save([pathname_ROIs fish_id '_ROIs.mat'],'ROIs','ROI_coord_ori_lin','ROI_coord_ori_vx_rcp'); + save([pathname_traces fish_id '_traces.mat'],'traces','time_offsets','trace_motor_regr'); + progressbar(f/n_fish,[]); +end + +function [trace] = process_trace_here(trace,bb_baseline,aa_baseline) +my_nans=isnan(trace); +trace(my_nans)=nanmean(trace); +trace=filtfilt(bb_baseline,aa_baseline,trace); +trace(my_nans)=nan; +trace=trace-nanmean(trace); +trace=trace/nanstd(trace); +trace=single(trace); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_scores_suite2p.m b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_scores_suite2p.m new file mode 100644 index 0000000..756e679 --- /dev/null +++ b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_scores_suite2p.m @@ -0,0 +1,34 @@ +%% pathnames +clc; close all; clear all; +pathname_MS_data = 'C:\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_PC_imaging_results=[pathname_MS_data 'PC_imaging_long_term_adaptation\']; +pathname_trigaver=[pathname_PC_imaging_results 'triggered_traces\']; +pathname_behavior=[pathname_PC_imaging_results 'behavior\']; +pathname_scores=[pathname_PC_imaging_results 'scores\']; + +%% loop through all fish +cd(pathname_trigaver); +all_fish=dm_dir('*_f*_trig_traces.mat'); +all_fish=strrep(all_fish,'_trig_traces.mat',''); +n_fish=length(all_fish); +fish_id = all_fish{1}; +load([pathname_trigaver fish_id '_trig_traces.mat']); +dt=time_trig(2)-time_trig(1); +dt=round(dt*100)/100; +clipping=1.2; +progressbar('Computing scores...'); +for f=1:n_fish + fish_id = all_fish{f}; + filename = [pathname_scores fish_id '_scores.mat']; + load([pathname_trigaver fish_id '_trig_traces.mat']); + scores_im = compute_scores_here(traces_bout_trig,time_trig,clipping); + scores_motor_regr = compute_scores_here(trace_motor_regr_bout_trig,time_trig,clipping)'; + load([pathname_behavior fish_id '_behavior.mat'],'trials'); + scores_be=trials.bout_duration.first; + save(filename,'scores_be','scores_im','scores_motor_regr') + progressbar(f/n_fish); +end + +function [scores] = compute_scores_here(data,time,clipping) +scores=squeeze(nanmean(data(:,time>0 & time<=clipping,:),2)); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_trigaver_suite2p.m b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_trigaver_suite2p.m new file mode 100644 index 0000000..c98ac3b --- /dev/null +++ b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/DM_E0030_v09_trigaver_suite2p.m @@ -0,0 +1,60 @@ +%% pathnames +clc; close all; clear all; +pathname_MS_data = '...\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_PC_imaging_results=[pathname_MS_data 'PC_imaging_long_term_adaptation\']; +pathname_behavior=[pathname_PC_imaging_results 'behavior\']; +pathname_traces=[pathname_PC_imaging_results 'traces\']; +pathname_trigaver=[pathname_PC_imaging_results 'triggered_traces\']; + +%% timing stuff +s_pre = 1; +s_post = 9; +dt=0.2; % 200 ms, corresponds to 5 Hz. + +%% loop through all fish +all_fish=dm_dir([pathname_traces '*_f*_traces.mat']); +all_fish=strrep(all_fish,'_traces.mat',''); +n_fish=length(all_fish); +for f = 1:n_fish + fish_id = all_fish{f}; + filename = [pathname_trigaver fish_id '_trig_traces.mat']; + + %% create empty structure + trigaver=struct; + + %% load the data + load([pathname_traces fish_id '_traces.mat'],'traces','time_offsets','trace_motor_regr'); + load([pathname_behavior fish_id '_behavior.mat'],'bouts','grmov','meta','time_be'); + [n_ROIs, n_frames] = size(traces); + time_im_ori=1/meta.F:1/meta.F:n_frames/meta.F; + time_im=0:dt:time_im_ori(end)+30-dt; + + %% find trigger times + gr_starts=time_be(diff(grmov)==1); + bout1_starts = nan(1,length(gr_starts)); + for t=1:length(gr_starts) + bouts_in_this_trial = bouts.start(bouts.trial==t); + if ~isempty(bouts_in_this_trial) + bout1_starts(t)= bouts_in_this_trial(1); + end + end + + %% interpolate traces + traces_interp = zeros(n_ROIs,length(time_im),'single'); + for t=1:n_ROIs + traces_interp(t,:) = interp1(time_im_ori+time_offsets(t), traces(t,:), time_im); + end + trace_motor_regr_interp = zeros(1,length(time_im),'single'); + trace_motor_regr_interp(1,:) = interp1(time_im_ori, trace_motor_regr, time_im); + + %% grating_onset +% [trigaver.gr_on.data, trigaver.gr_on.time] = dm_compute_triggered_traces(gr_starts,s_pre,s_post,dt,time_im,traces_interp); +% [trigaver_motor_regr.gr_on.data, trigaver_motor_regr.gr_on.time] = dm_compute_triggered_traces(gr_starts,s_pre,s_post,dt,time_im,trace_motor_regr_interp); + + %% first bout onset + [traces_bout_trig, time_trig] = dm_compute_triggered_traces(bout1_starts,s_pre,s_post,dt,time_im,traces_interp); + trace_motor_regr_bout_trig = dm_compute_triggered_traces(bout1_starts,s_pre,s_post,dt,time_im,trace_motor_regr_interp); + + %% save + save(filename,'traces_bout_trig','trace_motor_regr_bout_trig','time_trig'); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/PC_imaging_long_term_adaptation/readme.txt b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/readme.txt new file mode 100644 index 0000000..381cf57 --- /dev/null +++ b/analysis/imaging_analysis/PC_imaging_long_term_adaptation/readme.txt @@ -0,0 +1,2 @@ +DM_E0030_v09_lighsheet_analysis.m is the main code that calls other scripts from this folder. +Note that we only upload somewhat pre-processed data so the first several scripts will not be possible to execute. \ No newline at end of file diff --git a/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_behavior.m b/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_behavior.m new file mode 100644 index 0000000..3d150bf --- /dev/null +++ b/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_behavior.m @@ -0,0 +1,474 @@ +% this progam analyses behavior of the whole-brain imaging experiment. +% It perfoms the same computations as behavioral_analysis.m +% but using a different sourse data format + +%% pathnames +clc; close all; clear all; +pathname_raw_data='J:\_Shared\experiments\E0031_acute_adaptation\v02_lightsheet\data_behavior\'; +pathname_MS_data = '...\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_imaging_results=[pathname_MS_data 'whole_brain_imaging_inetgrators\']; +pathname_behavior=[pathname_imaging_results 'behavior\']; + +%% some important variables +dt=0.005; +spont_dur=120; +rest_dur=7.5; +trial_dur=15; +full_trial_dur=trial_dur+2*rest_dur; +calib_notr=0; %10; +pre_notr=10; +main_notr=40; +post_notr=0; + +spont_notr=spont_dur/full_trial_dur; +total_notr=calib_notr+pre_notr+main_notr+post_notr; +t_pre_start=full_trial_dur*calib_notr+spont_dur; +t_main_start=full_trial_dur*(calib_notr+pre_notr)+spont_dur; +t_post_start=full_trial_dur*(calib_notr+pre_notr+main_notr)+spont_dur; +gr_starts=spont_dur+(rest_dur:full_trial_dur:rest_dur+(total_notr-1)*full_trial_dur); +gr_ends=gr_starts+trial_dur; +time_be=dt:dt:total_notr*30+spont_dur; + +bout_par_names={'bout_duration','next_interbout_duration','sum_bout_vigor','mean_bout_freq','median_bout_freq','max_bout_freq','mean_bout_amp','median_bout_amp','max_bout_amp','distance_bout','distance_bout_interbout'}; +trial_par_names={'number_of_bouts','latency'}; +bout_arrays_names={'vigor','power','grspeed','flick_amps','flick_freqs'}; +measures={'first','mean','median','max','std','ste'}; + + +%% loop through all fish +cd(pathname_raw_data); +all_fish=dm_dir('*_f*'); +num_fish=length(all_fish); +for f=1:num_fish + this_fish=all_fish{f}; + filename_data=[this_fish '_data']; + %% metadata + path_to_fish=[pathname_raw_data this_name '\']; + cd(path_to_fish); + meta=load(filename_data,'meta'); + meta=meta.meta; + time_exp_dur=datetime(meta.general.t_protocol_end([1:10 12:19]),'InputFormat','yyyy-MM-ddHH:mm:ss')-datetime(meta.general.t_protocol_start([1:10 12:19]),'InputFormat','yyyy-MM-ddHH:mm:ss'); + comments=meta.general.animal.comments; + + %% stimulus + % read the values + stim=load(filename_data,'stim'); + stim=stim.stim; + if isfield(stim, 'grspeed_premainpost') + stim=rmfield(stim, {'grspeed_premainpost','base_grspeed_premainpost','swim_premainpost'}); + end + + bad_points=diff(stim.time)==0; + if sum(bad_points)>0 + for i=fieldnames(stim)' + stim.(cell2mat(i))(bad_points)=[]; + end + end + tf_prepost=(stim.time>=t_pre_start & stim.timet_post_start; + tf_main=stim.time>=t_main_start & stim.timelength(stim.time) + bout_ends_ids(end)=length(stim.time); + end + end + nob=length(bout_starts_ids); + % find reafference of all these bouts + bouts=[]; + gain=ones(1,length(stim.time)); + gain(tf_main)=stim.gain_main(tf_main); + lag=zeros(1,length(stim.time)); + lag(tf_main)=stim.lag_main(tf_main); + gd_starts=zeros(1,length(stim.time)); + gd_starts(tf_main)=stim.gd_starts_main(tf_main); + gd_ends=zeros(1,length(stim.time)); + gd_ends(tf_main)=stim.gd_ends_main(tf_main); + bouts.gain=gain(bout_starts_ids); + bouts.lag=lag(bout_starts_ids); + bouts.measured_lag=nan(1,nob); + bouts.gain_drop_start=gd_starts(bout_starts_ids); + bouts.gain_drop_start(isnan(bouts.gain_drop_start))=0; + bouts.gain_drop_end=gd_ends(bout_starts_ids); + bouts.gain_drop_end(isnan(bouts.gain_drop_end))=0; + bouts.gain_drop_duration=round((bouts.gain_drop_end-bouts.gain_drop_start)*1000)/1000; + notr=sum(diff(base_grspeed)==-10 & base_grspeed(1:end-1)==10); + + % prepare conditions + cond = find_all_conditions (bouts); + + %% behavioral traces + % read the values + be=load(filename_data,'be'); + be=be.be; + % correct the repeated time points + bad_points=diff(be.time)==0; + if sum(bad_points)>0 + be.time(bad_points)=[]; + be.tail(bad_points)=[]; + end + % interpolate tail trace, swim and grating speed + tail=interp1(be.time,be.tail,time_be); + swim=round(interp1(stim.time,swim,time_be))==1; + grspeed=interp1(stim.time,grspeed,time_be); + % scale the tail + tail=tail-nanmean(tail(~swim)); + tail=tail/nanstd(tail(swim)); + tail(isnan(tail))=0; + % build vigor trace + vigor=nan(1,length(tail)); + for i=0.05/dt:length(tail) + vigor(i)=std(tail(i-(0.05/dt-1):i)); + end + if length(vigor)total_notr*full_trial_dur/dt-1 + bet0=total_notr*full_trial_dur/dt-1; + end + for i=bst0:bet0 + if tail(i)>=tail(i-1) && tail(i)>tail(i+1) + c=c+1; + this_mm_time_array(c)=time_be(i); + this_mm_val_array(c)=tail(i); + this_max_tf_array(c)=true; + elseif tail(i)<=tail(i-1) && tail(i)=2 + bad_flicks=[abs(diff(this_mm_val_array))<0.14 false] & [false flip(abs(diff(flip(this_mm_val_array)))<0.14)]; + if abs(this_mm_val_array(2)-this_mm_val_array(1))<0.14 + bad_flicks(1)=true; + end + if abs(this_mm_val_array(end)-this_mm_val_array(end-1))<0.14 + bad_flicks(end)=true; + end + bad_flicks=bad_flicks | [false flip(abs(diff(flip(this_mm_time_array)))>0.1)]; + this_mm_time_array(bad_flicks)=[]; + this_mm_val_array(bad_flicks)=[]; + this_max_tf_array(bad_flicks)=[]; + bad_flicks=diff(this_max_tf_array)==0; + this_mm_time_array(bad_flicks)=[]; + this_mm_val_array(bad_flicks)=[]; + this_max_tf_array(bad_flicks)=[]; + if length(this_mm_time_array)>=2 + bouts.start(b)=this_mm_time_array(1); + bouts.end(b)=this_mm_time_array(end); + else + bouts.bad_bouts(b)=true; + end + else + bouts.bad_bouts(b)=true; + end + n=length(this_mm_time_array); + if n>1000 + n=1000; + end + mm_time_array(b,1:n)=this_mm_time_array(1:n); + mm_val_array(b,1:n)=this_mm_val_array(1:n); + max_tf_array(b,1:n)=this_max_tf_array(1:n); + end + % shorten the flicks arrays + mm_n=find(all(isnan(mm_time_array),1),1)-1; + if ~isempty(mm_n) + if mm_n>=50 + mm_n=50; + end + mm_time_array=mm_time_array(:,1:mm_n); + mm_val_array=mm_val_array(:,1:mm_n); + max_tf_array=max_tf_array(:,1:mm_n); + end + % create array of bad bouts + bouts.long_bouts=bouts.end-bouts.start>=0.3; + bouts.short_bouts=bouts.end-bouts.start<0.1; + bouts.bad_bouts=bouts.bad_bouts | ... % bouts that are already bad (failed to detect them properly) + bouts.short_bouts |... % bouts which are shorter than 100 ms + [false bouts.start(2:end)-bouts.end(1:end-1)<0.1] | [bouts.start(2:end)-bouts.end(1:end-1)<0.1 false] |... % bouts with interbouts shorter than 100 ms (tipically, these are bouts which were detected as 2 bouts) + all(isnan(mm_time_array),2)' |... % bouts with no flicks + max(diff(mm_time_array,1,2),[],2)'>0.1; % bouts with max delta flick time > 100 ms (this happens during some wierd ugly bouts) + % find spontaneous bouts (i.e. bouts which started after trial start and finished before trial end) + bouts.spont_bouts=true(1,nob); + for g=1:notr + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end=t_main_start; + bouts.main_bouts=bouts.main_bouts'; + % good bouts: i.e. they are not bad, not spontaneous and happened during main part + bouts.good_bouts=bouts.main_bouts & ~bouts.bad_bouts & ~bouts.spont_bouts; + + %% find bout parameters + bouts.trial=nan(1,nob); + bouts.bout_duration=bouts.end-bouts.start; + bouts.next_interbout_duration=nan(1,nob); + bouts.distance_bout=nan(1,nob); + bouts.distance_bout_interbout=nan(1,nob); + for g=1:notr + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end=1.1/dt + be=bs+1.1/dt-1; + end + bouts.tail(b,:)=zeros(1,1.1/dt); % changed from nan + bouts.tail(b,1:be-bs+1)=tail(bs:be); + bouts.vigor(b,:)=zeros(1,1.1/dt); % changed from nan + bouts.vigor(b,1:be-bs+1)=vigor(bs:be); + bouts.power(b,:)=zeros(1,1.1/dt); % changed from nan + bouts.power(b,1:be-bs+1)=tail(bs:be).^2; + bouts.grspeed(b,:)=nan(1,1.1/dt); + bouts.grspeed(b,1:be-bs+1)=grspeed(bs:be); + bouts.flick_times(b,:)=mm_time_array(b,:); + bouts.flick_values(b,:)=mm_val_array(b,:); + bouts.flick_amps(b,:)=abs(diff(bouts.flick_values(b,:),1,2)); + bouts.flick_freqs(b,:)=1./(diff(bouts.flick_times(b,:),1,2)*2); + end + end + for p=1:length(bout_par_names) + bouts.(bout_par_names{p})(bouts.bad_bouts | bouts.spont_bouts)=nan; + end + for p=1:length(bout_arrays_names) + bouts.(bout_arrays_names{p})(bouts.bad_bouts | bouts.spont_bouts,:)=nan; + end + bouts.tail(bouts.bad_bouts | bouts.spont_bouts,:)=nan; + bouts.flick_times(bouts.bad_bouts | bouts.spont_bouts,:)=nan; + bouts.flick_values(bouts.bad_bouts | bouts.spont_bouts,:)=nan; + + %% find trial averages + trials=[]; + vigor_for_imagesc=nan(total_notr+spont_notr,full_trial_dur/dt); + vigor_for_imagesc(1:spont_notr,:)=reshape(vigor(1:spont_dur/dt),full_trial_dur/dt,spont_notr)'; + for g=1:notr + trial_start=round((gr_starts(g)-rest_dur)/dt)+1; + trial_end=round((gr_ends(g)+rest_dur)/dt); + vigor_for_imagesc(g+spont_notr,:)=vigor(trial_start:trial_end); + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end0 + trials.(this_par).first(g)=these_bouts(1); + trials.(this_par).mean(g)=mean(these_bouts); + trials.(this_par).median(g)=median(these_bouts); + trials.(this_par).max(g)=max(these_bouts); + trials.(this_par).std(g)=std(these_bouts); + trials.(this_par).ste(g)=trials.(this_par).std(g)/sqrt(n); + else + trials.(this_par).first(g)=nan; + trials.(this_par).mean(g)=nan; + trials.(this_par).median(g)=nan; + trials.(this_par).max(g)=nan; + trials.(this_par).std(g)=nan; + trials.(this_par).ste(g)=nan; + end + end + for p=1:length(bout_arrays_names) + this_par=bout_arrays_names{p}; + these_bouts=bouts.(this_par)(bouts_in_this_trial,:); + these_bouts=these_bouts(~all(isnan(these_bouts),2),:); + trials.(this_par).n(g)=size(these_bouts,1); + if trials.(this_par).n(g)>0 + trials.(this_par).first(g,:)=these_bouts(1,:); + trials.(this_par).mean(g,:)=nanmean(these_bouts,1); + trials.(this_par).median(g,:)=nanmedian(these_bouts,1); + trials.(this_par).max(g,:)=nanmax(these_bouts,[],1); + trials.(this_par).std(g,:)=nanstd(these_bouts,0,1); + trials.(this_par).ste(g,:)=trials.(this_par).std(g,:)/sqrt(n); + else + trials.(this_par).first(g,:)=nan(1,size(bouts.(this_par),2)); + trials.(this_par).mean(g,:)=nan(1,size(bouts.(this_par),2)); + trials.(this_par).median(g,:)=nan(1,size(bouts.(this_par),2)); + trials.(this_par).max(g,:)=nan(1,size(bouts.(this_par),2)); + trials.(this_par).std(g,:)=nan(1,size(bouts.(this_par),2)); + trials.(this_par).ste(g,:)=nan(1,size(bouts.(this_par),2)); + end + end + end + + %% find phase mean + for g=1:floor(notr/10) + these_trials=(g-1)*10+1:g*10; + for p=1:length(trial_par_names) + this_par=trial_par_names{p}; + these_bouts=trials.(this_par)(these_trials); + these_bouts=these_bouts(~isnan(these_bouts)); + trials.phase_mean.(this_par).n(g)=length(these_bouts); + if trials.phase_mean.(this_par).n(g)>0 + trials.phase_mean.(this_par).mean(g)=mean(these_bouts); + trials.phase_mean.(this_par).median(g)=median(these_bouts); + trials.phase_mean.(this_par).max(g)=max(these_bouts); + trials.phase_mean.(this_par).std(g)=std(these_bouts); + trials.phase_mean.(this_par).ste(g)=trials.phase_mean.(this_par).std(g)/sqrt(trials.phase_mean.(this_par).n(g)); + else + trials.phase_mean.(this_par).mean(g)=nan; + trials.phase_mean.(this_par).median(g)=nan; + trials.phase_mean.(this_par).max(g)=nan; + trials.phase_mean.(this_par).std(g)=nan; + trials.phase_mean.(this_par).ste(g)=nan; + end + end + for p=1:length(bout_par_names) + this_par=bout_par_names{p}; + for m=1:length(measures) + this_measure_name=measures{m}; + these_bouts=trials.(this_par).(this_measure_name)(these_trials); + these_bouts=these_bouts(~isnan(these_bouts)); + trials.phase_mean.(this_par).(this_measure_name).n(g)=length(these_bouts); + if trials.phase_mean.(this_par).(this_measure_name).n(g)>0 + trials.phase_mean.(this_par).(this_measure_name).mean(g)=mean(these_bouts); + trials.phase_mean.(this_par).(this_measure_name).median(g)=median(these_bouts); + trials.phase_mean.(this_par).(this_measure_name).max(g)=max(these_bouts); + trials.phase_mean.(this_par).(this_measure_name).std(g)=std(these_bouts); + trials.phase_mean.(this_par).(this_measure_name).ste(g)=trials.phase_mean.(this_par).(this_measure_name).std(g)/sqrt(trials.phase_mean.(this_par).(this_measure_name).n(g)); + else + trials.phase_mean.(this_par).(this_measure_name).mean(g)=nan; + trials.phase_mean.(this_par).(this_measure_name).median(g)=nan; + trials.phase_mean.(this_par).(this_measure_name).max(g)=nan; + trials.phase_mean.(this_par).(this_measure_name).std(g)=nan; + trials.phase_mean.(this_par).(this_measure_name).ste(g)=nan; + end + end + end + for p=1:length(bout_arrays_names) + this_par=bout_arrays_names{p}; + for m=1:length(measures) + this_measure_name=measures{m}; + these_bouts=trials.(this_par).(this_measure_name)(these_trials,:); + these_bouts=these_bouts(~all(isnan(these_bouts),2),:); + trials.phase_mean.(this_par).(this_measure_name).n(g)=size(these_bouts,1); + if trials.phase_mean.(this_par).(this_measure_name).n(g)>0 + trials.phase_mean.(this_par).(this_measure_name).mean(g,:)=nanmean(these_bouts,1); + trials.phase_mean.(this_par).(this_measure_name).median(g,:)=nanmedian(these_bouts,1); + trials.phase_mean.(this_par).(this_measure_name).max(g,:)=nanmax(these_bouts,[],1); + trials.phase_mean.(this_par).(this_measure_name).std(g,:)=nanstd(these_bouts,0,1); + trials.phase_mean.(this_par).(this_measure_name).ste(g,:)=trials.phase_mean.(this_par).(this_measure_name).std(g,:)/sqrt(trials.phase_mean.(this_par).(this_measure_name).n(g)); + else + trials.phase_mean.(this_par).(this_measure_name).mean(g,:)=nan(1,size(bouts.(this_par),2)); + trials.phase_mean.(this_par).(this_measure_name).median(g,:)=nan(1,size(bouts.(this_par),2)); + trials.phase_mean.(this_par).(this_measure_name).max(g,:)=nan(1,size(bouts.(this_par),2)); + trials.phase_mean.(this_par).(this_measure_name).std(g,:)=nan(1,size(bouts.(this_par),2)); + trials.phase_mean.(this_par).(this_measure_name).ste(g,:)=nan(1,size(bouts.(this_par),2)); + end + end + end + end + + %% find condtition averages + for c=1:length(cond.names) + this_cond_name=cond.names{c}; + this_cond_vals=cond.vals{c}; + bouts.condition_mean.(this_cond_name).conditions=cond.xlabel{c}; + for i=1:length(bouts.condition_mean.(this_cond_name).conditions) + tf=bouts.good_bouts & bouts.lag==this_cond_vals(1,i) & bouts.gain==this_cond_vals(2,i) & bouts.gain_drop_start==this_cond_vals(3,i) & bouts.gain_drop_end==this_cond_vals(4,i); + for p=1:length(bout_par_names) + this_par=bout_par_names{p}; + these_bouts=bouts.(this_par)(tf); + these_bouts=these_bouts(~isnan(these_bouts)); + bouts.condition_mean.(this_cond_name).(this_par).n(i)=length(these_bouts); + if bouts.condition_mean.(this_cond_name).(this_par).n(i)>0 + bouts.condition_mean.(this_cond_name).(this_par).mean(i)=mean(these_bouts); + bouts.condition_mean.(this_cond_name).(this_par).median(i)=median(these_bouts); + bouts.condition_mean.(this_cond_name).(this_par).max(i)=max(these_bouts); + bouts.condition_mean.(this_cond_name).(this_par).std(i)=std(these_bouts); + bouts.condition_mean.(this_cond_name).(this_par).ste(i)=bouts.condition_mean.(this_cond_name).(this_par).std(i)/sqrt(bouts.condition_mean.(this_cond_name).(this_par).n(i)); + else + bouts.condition_mean.(this_cond_name).(this_par).mean(i)=nan; + bouts.condition_mean.(this_cond_name).(this_par).median(i)=nan; + bouts.condition_mean.(this_cond_name).(this_par).max(i)=nan; + bouts.condition_mean.(this_cond_name).(this_par).std(i)=nan; + bouts.condition_mean.(this_cond_name).(this_par).ste(i)=nan; + end + end + for p=1:length(bout_arrays_names) + this_par=bout_arrays_names{p}; + these_bouts=bouts.(this_par)(tf,:); + these_bouts=these_bouts(~all(isnan(these_bouts),2),:); + bouts.condition_mean.(this_cond_name).(this_par).n(i)=size(these_bouts,1); + if bouts.condition_mean.(this_cond_name).(this_par).n(i) + bouts.condition_mean.(this_cond_name).(this_par).mean(i,:)=nanmean(these_bouts,1); + bouts.condition_mean.(this_cond_name).(this_par).median(i,:)=nanmedian(these_bouts,1); + bouts.condition_mean.(this_cond_name).(this_par).max(i,:)=nanmax(these_bouts,[],1); + bouts.condition_mean.(this_cond_name).(this_par).std(i,:)=nanstd(these_bouts,0,1); + bouts.condition_mean.(this_cond_name).(this_par).ste(i,:)=bouts.condition_mean.(this_cond_name).(this_par).std(i,:)/sqrt(bouts.condition_mean.(this_cond_name).(this_par).n(i)); + else + bouts.condition_mean.(this_cond_name).(this_par).mean(i,:)=nan(1,size(bouts.(this_par),2)); + bouts.condition_mean.(this_cond_name).(this_par).median(i,:)=nan(1,size(bouts.(this_par),2)); + bouts.condition_mean.(this_cond_name).(this_par).max(i,:)=nan(1,size(bouts.(this_par),2)); + bouts.condition_mean.(this_cond_name).(this_par).std(i,:)=nan(1,size(bouts.(this_par),2)); + bouts.condition_mean.(this_cond_name).(this_par).ste(i,:)=nan(1,size(bouts.(this_par),2)); + end + end + end + end + + %% save the data + filename=[pathname_behavior this_fish '_behavior.mat']; + save(filename,'time_be','tail','grspeed','swim','bouts','trials','meta'); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_compress_csv_files.m b/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_compress_csv_files.m new file mode 100644 index 0000000..0dd8011 --- /dev/null +++ b/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_compress_csv_files.m @@ -0,0 +1,70 @@ +% this will compress new stytra acute fish + +%% initiate +clc; close all; clear all; + +path_to_data='J:\_Shared\experiments\E0031_acute_adaptation\v02_lightsheet\data_behavior\'; +cd(path_to_data); +all_fish=dir('*_f*'); +%% loop through fish +progressbar('Fish'); +for f=1:length(all_fish) + %% check if this fish is not already compressed + this_name=all_fish(f).name; + path_to_fish=[path_to_data this_name]; + cd(path_to_fish); + filename_data=[this_name '_data.mat']; + %% compress + if exist(filename_data,'file')~=2 % only if it was not compressed before + %% stimulus + filename_stim=dir('*_stimulus_log.csv'); + A=readtable(filename_stim.name); + stim=[]; + stim.time=A{:,'t'}; + stim.grspeed_prepost=-A{:,'general_cl1D_vel'}; + stim.base_grspeed_prepost=-A{:,'general_cl1D_base_vel'}; + stim.swim_prepost=A{:,'general_cl1D_fish_swimming'}; + stim.grspeed_main=-A{:,'acute_cl1D_vel'}; + stim.base_grspeed_main=-A{:,'acute_cl1D_base_vel'}; + stim.swim_main=A{:,'acute_cl1D_fish_swimming'}; + stim.gain_main=A{:,'acute_cl1D_gain'}; + stim.lag_main=A{:,'acute_cl1D_lag'}; + stim.gd_starts_main=A{:,'acute_cl1D_gain_drop_start'}; + stim.gd_ends_main=A{:,'acute_cl1D_gain_drop_end'}; + stim.shunted_lag_main=A{:,'acute_cl1D_shunted'}; + + %% estimator + filename_estim=dir('*_estimator_log.csv'); + A=readtable(filename_estim.name); + estim=[]; + estim.time=A{:,'t'}; + estim.vigor=A{:,'vigor'}; + + %% behavior + filename_be=dir('*_behavior_log.csv'); + A=readtable(filename_be.name); + be=[]; + be.time=A{:,'t'}; + be.tail=A{:,'tail_sum'}; + var_names=A.Properties.VariableNames; + n_tailpoints=0; + for i=1:length(var_names) + if ~isempty(strfind(var_names{i},'theta_')) + n_tailpoints=n_tailpoints+1; + end + end + for i=1:n_tailpoints + be.individual_tailpoints(:,i)=A{:,['theta_' num2str(i-1,'%02.f')]}; + end + + %% metadata + filename_meta=dir('*_metadata.json'); + A=read_json(filename_meta.name); + meta=A; + + %% save + save(filename_data,'stim','estim','be','meta','-v7.3'); + + end + progressbar(f/length(all_fish)); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_fit_time_constants.m b/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_fit_time_constants.m new file mode 100644 index 0000000..5a393c6 --- /dev/null +++ b/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_fit_time_constants.m @@ -0,0 +1,103 @@ +%% pathnames +clc; close all; clear all; +pathname_MS_data = 'C:\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_imaging_results=[pathname_MS_data 'whole_brain_imaging_inetgrators\']; +pathname_behavior=[pathname_imaging_results 'behavior\']; +pathname_traces=[pathname_imaging_results 'traces\']; +pathname_clustering=[pathname_imaging_results 'clustering\']; +pathname_time_constants=[pathname_imaging_results 'time_constants\']; + +%% all fish to be analyzed +all_fish=dm_dir([pathname_traces '*_f*_traces.mat']); +all_fish=strrep(all_fish,'_traces.mat',''); +n_fish=length(all_fish); + +%% build regressors for different time constants +% time of forward moving grating +load([pathname_behavior all_fish{1} '_behavior.mat'],'meta','time_be'); +forw_gr_starts = 120+7.5:30:time_be(end); +forw_gr_ends=forw_gr_starts+15; +dt=1/meta.fs; +time_im = dt:dt:time_be(end); +n_frames = length(time_im); +% convert times into indices +forw_gr_starts=round(forw_gr_starts/dt); +forw_gr_ends=round(forw_gr_ends/dt); +% model activity of a neuron which is active during trials of forward +% moving grating and silent otherwise +model_act = zeros(1,n_frames); +for i=1:length(forw_gr_starts) + model_act(forw_gr_starts(i):forw_gr_ends(i))=1; +end +% build calcium kernel +s_half_decay = genotype2tau(meta.genotype); +my_kernel=2.^(-(time_im)/s_half_decay); +% time constants to probe +max_tau=10; +probing_taus=dt:dt:max_tau; +n_taus=length(probing_taus); +% compute leaky integratrion for a list of taus and +% convolve it with the calcium kernel +integrated_traces = zeros(n_taus,n_frames); +% if tau == dt, no integration +for i = 1:n_taus + tau=probing_taus(i); + tau=dt/tau; + this_integrated_trace = zeros(1,n_frames); + if tau0)=1; +% build calcium kernel +load([pathname_behavior all_fish{1} '_behavior.mat'],'meta'); +dt = time_trig(2)-time_trig(1); +s_half_decay = genotype2tau(meta.genotype); +my_kernel=2.^(-(dt:dt:10)/s_half_decay); +% time constants to probe +max_tau=10; +probing_taus=dt:dt:max_tau; +n_taus=length(probing_taus); +% compute leaky integratrion for a list of taus and +% convolve it with the calcium kernel +integrated_traces = zeros(n_taus,n_frames); +% if tau == dt, no integration +for i = 1:n_taus + tau=probing_taus(i); + tau=dt/tau; + this_integrated_trace = zeros(1,n_frames); + if tau0; + +%% cutoff frequency for high-pass filtering +fc_baseline=1/300; % Hz, 5 min period + +%% loop through all fish +all_fish=dm_dir([pathname_anatomies '*_f*_anatomy.nrrd']); +all_fish=strrep(all_fish,'_anatomy.nrrd',''); +n_fish=length(all_fish); +progressbar('Fish progress...','Morphing ROIs...','Fixing ROI IDs, processing traces...','Computing ROI coordinates...') +for f=1:n_fish + this_name=all_fish{f}; + + %% load traces, ROIs, as well as metadata + % path to raw data of this fish + path_to_fish=[pathname_raw_data this_name '\exp0031\']; + affine_x=[path_to_affine_x this_name '_anatomy.xform']; + % load ROIs and traces, metadata, prepare time_offsets + ROIs_local = tiff2mat(path_to_fish, 'rois.tif')+1; + sz_ROIs_local=size(ROIs_local); + traces=load([path_to_fish 'matlab_data.mat'],'traces'); + traces=traces.traces'; + meta=load([pathname_behavior this_name '_behavior.mat'],'meta'); + meta=meta.meta; + pulse_times=flip(meta.pulse_times); + + %% filters for computing baseline and denoising the trace + [bb_baseline,aa_baseline]=butter(3,2*fc_baseline/meta.fs,'low'); + fc=1/genotype2tau(meta.genotype); + [bb_6s,aa_6s]=butter(3,2*fc/meta.fs,'low'); + + %% process this fish + % remove ROIs from the first 4 planes + ROIs_local(:,:,1:4)=0; + % remove ROIs with artifact traces + max_diff=max(abs(diff(traces,1,2)),[],2); + artifact_ROIs=find(max_diff>100); + ROIs_local(ismember(ROIs_local,artifact_ROIs))=0; + % get IDis of remaining ROIs + all_ROIs=unique(ROIs_local)'; + all_ROIs(all_ROIs==0)=[]; + n_ROIs=length(all_ROIs); + % flip ROIs + ROIs_local=flip(ROIs_local,3); + % create output variables + ROIs=zeros(sz_ref,'uint32'); + time_offsets=nan(n_ROIs,1); + % start the loop that morphs the ROIs to the refernce brain + c=0; + for i=all_ROIs + c=c+1; + coord0=find(ROIs_local==i); + [row0,column0,plane0]=ind2sub(sz_ROIs_local, coord0); + ori_plane=unique(plane0); + row0=row0*meta.rez(1); + column0=column0*meta.rez(2); + plane0=plane0*meta.rez(3); + ori_plane_um=ori_plane*meta.rez(3); + extended_planes=ori_plane_um-1:-1:ori_plane_um-meta.rez(3)+1; + num_ext_planes=length(extended_planes); + for ii=extended_planes + plane0=[plane0; ones(length(row0),1)*ii]; + end + row0=repmat(row0,num_ext_planes+1,1); + column0=repmat(column0,num_ext_planes+1,1); + + coord1=DM_morph_non_ref_coord([row0,column0,plane0],affine_x,path_to_lists); + coord1=coord1./rez_ref; + coord1=unique([floor(coord1);ceil(coord1)],'rows'); + bad_coord=find(any(coord1<=0,2) | coord1(:,1)>sz_ref(1) | coord1(:,2)>sz_ref(2) | coord1(:,3)>sz_ref(3)); + coord1(bad_coord,:)=[]; + if ~isempty(coord1) + % write it's mid plane + % add this ROI coordinates + coord1=sub2ind(sz_ref, coord1(:,1), coord1(:,2), coord1(:,3)); + this_ROI = false(sz_ref); + this_ROI(coord1)=true; + % find if there are rois already + ROIs_there = unique(ROIs (this_ROI))'; + ROIs_there(ROIs_there==0)=[]; + for ii=ROIs_there + % find pixels that are intesepting and remove 1/2 + px = find(this_ROI & ROIs==ii); + this_ROI(px(randperm(length(px),round(length(px)/2))))=false; + end + ROIs(this_ROI)=i; + % write the temporal offset of this roi + time_offsets(i)=pulse_times(ori_plane); + end + progressbar([],c/n_ROIs,[],[]) + end + % remove out of brain ROIs + ROIs(~ref_mask)=0; + % find all remaining ROIs + all_ROIs=unique(ROIs)'; + all_ROIs(all_ROIs==0)=[]; + n_ROIs=length(all_ROIs); + % fix ROI IDs and process the traces + ROIs2=zeros(sz_ref,'uint32'); + traces=double(traces); + traces(traces==0)=nan; + traces2=nan(n_ROIs,size(traces,2),'single'); + time_offsets2=nan(n_ROIs,1); + for i=1:n_ROIs + old_id=all_ROIs(i); + ROIs2(ROIs==old_id)=i; + time_offsets2(i)=time_offsets(old_id); + traces2(i,:) = process_trace_here(traces(old_id,:),bb_baseline,aa_baseline,bb_6s,aa_6s); + progressbar([],[],i/n_ROIs,[]); + end + ROIs=ROIs2; + traces=traces2; + time_offsets=time_offsets2; + % extract linear coordinates of morphed ROIs + ROI_coord=cell(n_ROIs,1); + for i=1:n_ROIs + coord=uint32(find(ROIs==i)); + ROI_coord{i}=coord; + progressbar([],[],[],i/n_ROIs); + end + % save the data + filename=[pathname_ROIs this_name '_ROIs.mat']; + save(filename,'ROI_coord'); + filename=[pathname_traces this_name '_traces.mat']; + save(filename,'traces','time_offsets'); + progressbar(f/length(all_fish),[],[],[]) +end + +function [trace] = process_trace_here(trace,bb_baseline,aa_baseline,bb_6s,aa_6s) +my_nans=isnan(trace); +trace(my_nans)=nanmean(trace); +trace=filtfilt(bb_6s,aa_6s,trace); +trace_baseline=filtfilt(bb_baseline,aa_baseline,trace); +trace=trace-trace_baseline; +trace(my_nans)=nan; +trace=trace-nanmean(trace); +trace=trace/nanstd(trace); +trace=single(trace); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_signif_ROIs.m b/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_signif_ROIs.m new file mode 100644 index 0000000..ac148f3 --- /dev/null +++ b/analysis/imaging_analysis/whole_brain_imaging_inetgrators/DM_E0031_v02_signif_ROIs.m @@ -0,0 +1,96 @@ +%% pathnames +clc; close all; clear all; +pathname_MS_data = 'C:\Markov_et_al_2021_Nat_Commun_data&code\data\'; +pathname_imaging_results=[pathname_MS_data 'whole_brain_imaging_inetgrators\']; +pathname_ROIs=[pathname_imaging_results 'ROIs\']; +pathname_clustering=[pathname_imaging_results 'clustering\']; +pathname_time_constants=[pathname_imaging_results 'time_constants\']; +pathname_reference_brains = [pathname_MS_data 'reference_brain_stacks\']; + +%% size of the reference brain +sz=read_nrrd_metadata([pathname_reference_brains 'PortuguesLab_wholebrain_ref.nrrd']); + +%% load the data (coordinates and time constants) +all_fish=dm_dir([pathname_ROIs '*_f*_ROIs.mat']); +all_fish=strrep(all_fish,'_ROIs.mat',''); +n_fish=length(all_fish); +coord={}; +clust=uint8([]); +for f=1:n_fish + fish_id=all_fish{f}; + load([pathname_ROIs fish_id '_ROIs.mat'],'ROI_coord'); + coord=[coord; ROI_coord]; + load([pathname_clustering fish_id '_clustering.mat'],'sensmot_clust'); + load([pathname_time_constants fish_id '_time_constants.mat'],'time_constants'); + sensmot_clust(time_constants>1.5)=3; + clust=[clust; sensmot_clust]; +end +n_ROIs = length(clust); +clear time_constants ROI_coord f all_fish n_fish fish_id sensmot_clust; + +%% build stacks where value of each voxel equals number of fish with activity in that voxel +% for all active ROIs and for individual functional labels +stack_num_fish=zeros(sz,'uint8'); +stack_num_sensors=stack_num_fish; +stack_num_motor=stack_num_fish; +stack_num_integrators=stack_num_fish; +for i=1:n_ROIs + this_coord=coord{i}; + switch clust(i) + case 1 + stack_num_fish(this_coord)=stack_num_fish(this_coord)+1; + stack_num_sensors(this_coord)=stack_num_sensors(this_coord)+1; + case 2 + stack_num_fish(this_coord)=stack_num_fish(this_coord)+1; + stack_num_motor(this_coord)=stack_num_motor(this_coord)+1; + case 3 + stack_num_fish(this_coord)=stack_num_fish(this_coord)+1; + stack_num_integrators(this_coord)=stack_num_integrators(this_coord)+1; + end +end +clear i this_coord; + +%% Formulate the H0 +% All active ROIs have equal probability to be asiged with any of the three +% funtional labels (p=1/3). +% Note: active ROI means that it has any of the functional labels. + +% We test this H0 for each ROI. To do so, we first define a term "locus" +% as all voxels that belong to that ROI. We then find number of +% fish with active ROIs in that locus (N) and number of fish with ROIs that +% share the functional label with the original ROI in that locus (M). We then +% estimate the probability P of observing M or more ROIs out of total N active ROIs given H0. +% if P < 0.05, we reject the H0 and conclude that ROIs in that locus are +% more likely to belong to the functional group of the original ROI than to +% any other functional group. +p=1/3; +signif_ROIs=false(n_ROIs,1); +p_thresh = 0.05; +for i=1:n_ROIs + if clust(i)~=0 % if this ROI is active + % find its "locus" + this_coord=coord{i}; + % find number of fish with active ROIs in that locus + N = max(stack_num_fish(this_coord)); + % find number of fish with ROIs with the same functional label in that locus + switch clust(i) + case 1 + M=max(stack_num_sensors(this_coord)); + case 2 + M=max(stack_num_motor(this_coord)); + case 3 + M=max(stack_num_integrators(this_coord)); + end + % compute the probability P of this or more extreme observations given the H0 + % (by "more extreme" I mean observing M or more ROIs) + P=0; + for ii=M:N + P=P+binopdf(ii,N,1/3); + end + % make a decision about rejecting the H0 given 95% significance level + if P0;time_trig>0 & time_trig<2]; % sens tf; mot tf +baseline_tf=1:time_pre/dt-1; + +%% parameters for bootstrapping +n_bootstrap = 1000; +chunk_length = 23; % seconds +chunk_length = round(chunk_length/dt); % frames + +%% loop through all fish +all_fish=dm_dir([pathname_traces '*_f*_traces.mat']); +all_fish=strrep(all_fish,'_traces.mat',''); +n_fish=length(all_fish); +progressbar('Fish progress...','Interpolating traces...','Computing H0 for scores') +for f=4:n_fish + fish_id=all_fish{f}; + filename_trigaver = [pathname_trigaver fish_id '_trig_traces.mat']; + filename_clustering = [pathname_clustering fish_id '_clustering.mat']; + + %% load the data + load([pathname_traces fish_id '_traces.mat'],'traces','time_offsets'); + n_ROIs=size(traces,1); + load([pathname_behavior fish_id '_behavior.mat'],'bouts','meta'); + im_dt=1/meta.fs; + time_im_ori=im_dt:im_dt:size(traces,2)*im_dt; + time_im=round((-time_pre+dt:dt:time_im_ori(end)+time_post)*100)/100; + num_frames_total=length(time_im); + + %% create triggers + % sensory triggers + forw_gr_starts = 120+7.5:30:time_im_ori(end); + forw_gr_ends=forw_gr_starts+15; + rev_gr_starts = 120+2.5:30:time_im_ori(end); + % extract motor triggeres + bout_starts=bouts.start; + % build all triggers together + all_trig=sort([forw_gr_starts, forw_gr_ends, rev_gr_starts, bout_starts]); + all_trig_cell = {forw_gr_starts, bout_starts}; + num_trig_types=length(all_trig_cell); + % work with triggers + n_trig=zeros(1,num_trig_types); + id_start=cell(1,num_trig_types); + id_end=id_start; + trig_length=id_start; + for i=1:num_trig_types + % remove triggers that have any other triggers 'time_pre' seconds before + this_trig=remove_trig(all_trig_cell{i}, all_trig, time_pre); + % find first and last frames for every trigger + n_trig(i)=length(this_trig); + this_id_start=nan(1,n_trig(i)); + this_id_end=this_id_start; + for j=1:n_trig(i) + % first frame (trig - time_pre) + [~, this_id_start(j)] = min(abs(time_im - (this_trig(j) - time_pre))); + this_id_start(j)=this_id_start(j)+1; + % last frame (trig + time_post or 1 imaging frame before next trig); + next_trig_id=find(all_trig-this_trig(j)>0,1); + if isempty(next_trig_id) + next_trig=inf; + else + next_trig=all_trig(next_trig_id)-im_dt; + end + this_id_end(j)=min(next_trig,this_trig(j) + time_post); + [~, this_id_end(j)] = min(abs(time_im - this_id_end(j))); + end + % remove triggers that are too close to the next trigger + tf_remove=time_im(this_id_end)<=this_trig; + this_id_start(tf_remove)=[]; + this_id_end(tf_remove)=[]; + id_start{i} = this_id_start; + id_end{i} = this_id_end; + trig_length{i}=this_id_end-this_id_start+1; + n_trig(i) = length(this_id_start); + end + + %% interpolate all traces to time_im + traces_interp = nan(n_ROIs,num_frames_total,'single'); + for i=1:n_ROIs + traces_interp(i,:)=interp1(time_im_ori+time_offsets(i),traces(i,:),time_im); + progressbar([],i/n_ROIs,[]); + end + + %% compute triggered averages and sensory and motor scores + scores=nan(n_ROIs,num_trig_types); + mean_traces=nan(n_ROIs,n_frames,num_trig_types,'single'); + ste_traces=mean_traces; + for i=1:num_trig_types + [mean_traces(:,:,i), ste_traces(:,:,i), scores(:,i)] = compute_trigaver_here(... + id_start{i},... + id_end{i},... + trig_length{i},... + n_ROIs,... + n_frames,... + n_trig(i),... + traces_interp,... + baseline_tf,... + score_tf(i,:)); + end + + %% build null ditributions for sens and motor scores + chunk_start_ids = [1 : chunk_length : num_frames_total num_frames_total+1]; + n_chunks=length(chunk_start_ids(chunk_start_ids~=num_frames_total & chunk_start_ids~=num_frames_total+1)); + H0_scores=nan(n_ROIs,num_trig_types,n_bootstrap); + for ii=1:n_bootstrap + chunk_ord=randperm(n_chunks); + t=1; + shuffled_traces=nan(n_ROIs,num_frames_total,'single'); + for j=1:n_chunks + this_chunk_ids = chunk_start_ids(chunk_ord(j)) : chunk_start_ids(chunk_ord(j)+1)-1; + this_chink_length = length(this_chunk_ids); + shuffled_traces(:,t:t+this_chink_length-1) = traces_interp(:,this_chunk_ids); + t=t+this_chink_length; + end + for i=1:num_trig_types + H0_scores(:,i,ii) = compute_trigaver_here_fast(... + id_start{i},... + id_end{i},... + trig_length{i},... + n_ROIs,... + n_frames,... + n_trig(i),... + shuffled_traces,... + baseline_tf,... + score_tf(i,:)); + end + progressbar([],[],ii/n_bootstrap); + end + + %% prepare relevant data for saving + traces_gr_trig_mean = mean_traces(:,:,1); + traces_bout_trig_mean = mean_traces(:,:,2); + traces_gr_trig_ste = ste_traces(:,:,1); + traces_bout_trig_ste = ste_traces(:,:,2); + scores_gr = scores(:,1); + scores_bouts = scores(:,2); + + %% cluster into sensory and motor cells + thresh95=prctile(H0_scores,100-5,3); + tf_sens=scores_gr>thresh95(:,1); + tf_mot=scores_bouts>thresh95(:,2) & scores_grlength(t_stim) + bout_ends_ids(end)=length(t_stim); + end + end + nob=length(bout_starts_ids); + + %% work with behavior + filename_be=cell2mat(dm_dir('*_behavior_log.hdf5')); + var_names_be = h5read(filename_be,'/data/block0_items'); + for i=1:length(var_names_be) + this_name = var_names_be{i}; + this_name(double(this_name)==0)=[]; + var_names_be{i} = this_name; + end + be = h5read(filename_be,'/data/block0_values'); + bad_points=diff(be(strcmp(var_names_be,'t'),:))==0; + be(:,bad_points)=[]; + t_be=be(strcmp(var_names_be,'t'),:); + tail=be(strcmp(var_names_be,'tail_sum'),:); + clear be filename_be var_names_be; + % interpolate tail trace, swim and grating speed + tail=interp1(t_be,tail,time_be); + swim=interp1(t_stim,swim,time_be)>=0.5; + grspeed=interp1(t_stim,grspeed,time_be); + grmov=interp1(t_stim,double(base_grspeed),time_be)>0.5; + % scale the tail + tail=tail-nanmean(tail(~swim)); + tail=tail/nanstd(tail(swim)); + tail(isnan(tail))=0; + % build vigor trace + vigor=nan(1,length(tail)); + for i=0.05/dt:length(tail) + vigor(i)=std(tail(i-(0.05/dt-1):i)); + end + + %% detect bouts accurately (and find min and max tail positions) + bouts.start=nan(1,nob); + bouts.end=nan(1,nob); + bouts.bad_bouts=false(1,nob); + mm_time_array=nan(nob,1000); + mm_val_array=mm_time_array; + max_tf_array=false(nob,1000); + for b=1:nob + bst0=round((t_stim(bout_starts_ids(b))-0.1)/dt); + bet0=round(t_stim(bout_ends_ids(b))/dt); + bouts.start(b)=t_stim(bout_starts_ids(b)); + bouts.end(b)=t_stim(bout_ends_ids(b)); + + % find individual flicks + this_mm_time_array=[]; + this_mm_val_array=[]; + this_max_tf_array=[]; + c=0; + if bst0<2 + bst0=2; + end + if bet0>exp_dur/dt-1 + bet0=exp_dur/dt-1; + end + for i=bst0:bet0 + if tail(i)>=tail(i-1) && tail(i)>tail(i+1) + c=c+1; + this_mm_time_array(c)=time_be(i); + this_mm_val_array(c)=tail(i); + this_max_tf_array(c)=true; + elseif tail(i)<=tail(i-1) && tail(i)=2 + bad_flicks=[abs(diff(this_mm_val_array))<0.14 false] & [false flip(abs(diff(flip(this_mm_val_array)))<0.14)]; + if abs(this_mm_val_array(2)-this_mm_val_array(1))<0.14 + bad_flicks(1)=true; + end + if abs(this_mm_val_array(end)-this_mm_val_array(end-1))<0.14 + bad_flicks(end)=true; + end + bad_flicks=bad_flicks | [false flip(abs(diff(flip(this_mm_time_array)))>0.1)]; + this_mm_time_array(bad_flicks)=[]; + this_mm_val_array(bad_flicks)=[]; + this_max_tf_array(bad_flicks)=[]; + bad_flicks=diff(this_max_tf_array)==0; + this_mm_time_array(bad_flicks)=[]; + this_mm_val_array(bad_flicks)=[]; + this_max_tf_array(bad_flicks)=[]; + if length(this_mm_time_array)>=2 + bouts.start(b)=this_mm_time_array(1); + bouts.end(b)=this_mm_time_array(end); + else + bouts.bad_bouts(b)=true; + end + else + bouts.bad_bouts(b)=true; + end + n=length(this_mm_time_array); + if n>1000 + n=1000; + end + mm_time_array(b,1:n)=this_mm_time_array(1:n); + mm_val_array(b,1:n)=this_mm_val_array(1:n); + max_tf_array(b,1:n)=this_max_tf_array(1:n); + end + % shorten the flicks arrays + mm_n=find(all(isnan(mm_time_array),1),1)-1; + if ~isempty(mm_n) + if mm_n>=50 + mm_n=50; + end + mm_time_array=mm_time_array(:,1:mm_n); + mm_val_array=mm_val_array(:,1:mm_n); + max_tf_array=max_tf_array(:,1:mm_n); + end + % create array of bad bouts + bouts.long_bouts=bouts.end-bouts.start>=0.3; + bouts.short_bouts=bouts.end-bouts.start<0.1; + bouts.bad_bouts=bouts.bad_bouts | ... % bouts that are already bad (failed to detect them properly) + bouts.short_bouts |... % bouts which are shorter than 100 ms + [false bouts.start(2:end)-bouts.end(1:end-1)<0.1] | [bouts.start(2:end)-bouts.end(1:end-1)<0.1 false] |... % bouts with interbouts shorter than 100 ms (tipically, these are bouts which were detected as 2 bouts) + all(isnan(mm_time_array),2)' |... % bouts with no flicks + max(diff(mm_time_array,1,2),[],2)'>0.1; % bouts with max delta flick time > 100 ms (this happens during some wierd ugly bouts) + % find spontaneous bouts (i.e. bouts which started after trial start and finished before trial end) + bouts.spont_bouts=true(1,nob); + for g=1:notr + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end=t_main_start; + bouts.main_bouts=bouts.main_bouts; + % good bouts: i.e. they are not bad, not spontaneous and happened during main part + bouts.good_bouts=bouts.main_bouts & ~bouts.bad_bouts & ~bouts.spont_bouts; + + %% find bout parameters + bouts.trial=nan(1,nob); + bouts.bout_duration=bouts.end-bouts.start; + bouts.next_interbout_duration=nan(1,nob); + for g=1:notr + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end=1.1/dt + be=bs+1.1/dt-1; + end + bouts.tail(b,:)=zeros(1,1.1/dt); + bouts.tail(b,1:be-bs+1)=tail(bs:be); + bouts.power(b,:)=zeros(1,1.1/dt); + bouts.power(b,1:be-bs+1)=tail(bs:be).^2; + bouts.grspeed(b,:)=nan(1,1.1/dt); + bouts.grspeed(b,1:be-bs+1)=grspeed(bs:be); + end + end + for p=1:length(bout_par_names) + bouts.(bout_par_names{p})(bouts.bad_bouts | bouts.spont_bouts)=nan; + end + for p=1:length(bout_arrays_names) + bouts.(bout_arrays_names{p})(bouts.bad_bouts | bouts.spont_bouts,:)=nan; + end + bouts.tail(bouts.bad_bouts | bouts.spont_bouts,:)=nan; + + %% find trial averages + trials=[]; + vigor_for_imagesc=nan(notr,full_trial_dur/dt); + for g=1:notr + trial_start=round((gr_starts(g)-rest_dur)/dt)+1; + trial_end=round((gr_ends(g)+rest_dur)/dt); + vigor_for_imagesc(g,:)=vigor(trial_start:trial_end); + bouts_in_this_trial=find(bouts.start>gr_starts(g) & bouts.end0 + trials.(this_par).first(g)=these_bouts(1); + trials.(this_par).mean(g)=mean(these_bouts); + else + trials.(this_par).first(g)=nan; + trials.(this_par).mean(g)=nan; + end + end + for p=1:length(bout_arrays_names) + this_par=bout_arrays_names{p}; + these_bouts=bouts.(this_par)(bouts_in_this_trial,:); + these_bouts=these_bouts(~all(isnan(these_bouts),2),:); + trials.(this_par).n(g)=size(these_bouts,1); + if trials.(this_par).n(g)>0 + trials.(this_par).first(g,:)=these_bouts(1,:); + trials.(this_par).mean(g,:)=nanmean(these_bouts,1); + else + trials.(this_par).first(g,:)=nan(1,size(bouts.(this_par),2)); + trials.(this_par).mean(g,:)=nan(1,size(bouts.(this_par),2)); + end + end + end + + %% determine experimental condition + if meta.lag_condition==0 + meta.group = 'control'; + else + if nanmean(trials.bout_duration.first(61:70)) - nanmean(trials.bout_duration.first(21:30))<-0.04 + meta.group = 'lag-trained adapting'; + else + meta.group = 'lag-trained non-adapting'; + end + end + disp(meta.group); + + %% save the data + save(filename,'time_be','tail','grspeed','grmov','swim','bouts','trials','meta'); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_lighsheet_analysis.asv b/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_lighsheet_analysis.asv new file mode 100644 index 0000000..36b6e2e --- /dev/null +++ b/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_lighsheet_analysis.asv @@ -0,0 +1,39 @@ +%% initial stuff +clc; close all; clear all; +addpath('C:\Markov_et_al_2021_Nat_Commun_data_code\analysis_code\imaging_analysis\whole_brain_imaging_long_term_adaptation'); +addpath('C:\Markov_et_al_2021_Nat_Commun_data_code\analysis_code\MATLfunctions'); + +%% morphing anatomies +% same is in the whole-brain exp + +%% pre-processing +% analysis of the behavior, same as for behavioral experiments +DM_wb_lta_behavior; +% pre-process traces, morph ROIs +DM_wb_lta_preprocessing; + +% these four programs save pre-processed data to: +% ...\Markov_et_al_2021_Nat_Commun_data_code\data\whole_brain_imaging_long_term_adaptation\... +% behavior +% anatomies +% traces +% ROIs + +%% subsequent analysis +DM_wb_lta_main_analysis; +% % compute grating- and bout-triggered averages +% DM_wb_lta_trigaver; +% % compute scores +% DM_wb_lta_scores; +% % compute criteria +% DM_wb_lta_crit; +% % compute data for sensorymotor clustering (as in the other whole-brain experiment) +% DM_wb_lta_sensmot_clustering; +% % fit the time constants +% DM_wb_lta_fit_time_constants; + +% these three programs save final data to: +% ...\Markov_et_al_2021_Nat_Commun_data_code\data\whole_brain_imaging_long_term_adaptation\... +% triggered_traces +% scores +% criteria diff --git a/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_lighsheet_analysis.m b/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_lighsheet_analysis.m new file mode 100644 index 0000000..35bed39 --- /dev/null +++ b/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_lighsheet_analysis.m @@ -0,0 +1,26 @@ +%% initial stuff +clc; close all; clear all; +addpath('C:\Markov_et_al_2021_Nat_Commun_data_code\analysis_code\imaging_analysis\whole_brain_imaging_long_term_adaptation'); +addpath('C:\Markov_et_al_2021_Nat_Commun_data_code\analysis_code\MATLAB_functions'); + +%% morphing anatomies +% same is in the whole-brain exp + +%% pre-processing +% analysis of the behavior, same as for behavioral experiments +DM_wb_lta_behavior; +% pre-process traces, morph ROIs +DM_wb_lta_preprocessing; + +% these two programs save pre-processed data to: +% ...\data\whole_brain_imaging_long_term_adaptation\... +% behavior +% anatomies +% traces +% ROIs + +%% subsequent analysis +DM_wb_lta_main_analysis; + +% these three programs save final data to: +% ...\data\whole_brain_imaging_long_term_adaptation\processed_data\ \ No newline at end of file diff --git a/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_main_analysis.m b/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_main_analysis.m new file mode 100644 index 0000000..b8bf611 --- /dev/null +++ b/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_main_analysis.m @@ -0,0 +1,409 @@ +%% pathnames +clc; close all; clear all; +pathname_MS_data = 'C:\Markov_et_al_2021_Nat_Commun_data_code\data\'; +pathname_wb_imaging_results=[pathname_MS_data 'whole_brain_imaging_long_term_adaptation\']; +pathname_behavior=[pathname_wb_imaging_results 'behavior\']; +pathname_traces=[pathname_wb_imaging_results 'traces\']; +pathname_processed_data=[pathname_wb_imaging_results 'processed_data\']; + +%% timing stuff +s_pre = 1; +s_post = 4; +dt=0.2; % 200 ms, corresponds to 5 Hz. +time_trig=round((-s_pre+dt:dt:s_post)*100)/100; +n_frames_trig = length(time_trig); +score_tf=[time_trig>0;time_trig>0 & time_trig<2]; % sens tf; mot tf +baseline_tf=1:s_pre/dt-1; + +%% parameters for bootstrapping +n_boots = 1000; +chunk_length = 23; % seconds +chunk_length = round(chunk_length/dt); % frames + +%% for computing scores used for criteria +clipping=1.2; + +%% loop through all fish +all_fish=dm_dir([pathname_traces '*_f*_traces.mat']); +all_fish=strrep(all_fish,'_traces.mat',''); +n_fish=length(all_fish); +progressbar('Fish progress...','Interpolating traces...','Bootstrapping...','Fitting time constants...'); +for f = 1:n_fish + fish_id = all_fish{f}; + filename = [pathname_processed_data fish_id '_processed_data.mat']; + + %% load the behavioral data + load([pathname_behavior fish_id '_behavior.mat'],'bouts','grmov','meta','time_be','trials'); + + %% load and interpolate traces + load([pathname_traces fish_id '_traces.mat'],'traces','time_offsets','trace_motor_regr'); + [n_ROIs, n_frames_ori] = size(traces); + im_dt = 1/meta.F; + time_im_ori=(im_dt:im_dt:n_frames_ori/meta.F)-im_dt; + time_im=dt:dt:time_im_ori(end)+30-dt; + n_frames=length(time_im); + traces_interp = zeros(n_ROIs,length(time_im),'single'); + for i=1:n_ROIs + traces_interp(i,:) = interp1(time_im_ori+time_offsets(i), traces(i,:), time_im); + progressbar([],i/n_ROIs,[],[]) + end + trace_motor_regr_interp = zeros(1,length(time_im),'single'); + trace_motor_regr_interp(1,:) = interp1(time_im_ori, trace_motor_regr, time_im); + clear traces trace_motor_regr; + + %% build triggers + gr_starts=time_be(diff(grmov)==1); + gr_ends=gr_starts+15; + bout_starts=bouts.start; + bout1_starts = nan(1,length(gr_starts)); + for t=1:length(gr_starts) + bouts_in_this_trial = bout_starts(bouts.trial==t); + if ~isempty(bouts_in_this_trial) + bout1_starts(t)= bouts_in_this_trial(1); + end + end + % build all triggers together + all_trig=sort([gr_starts, gr_ends, bout_starts]); + all_trig_cell = {gr_starts, bout_starts}; + num_trig_types=length(all_trig_cell); + % work with triggers + n_trig=zeros(1,num_trig_types); + id_start=cell(1,num_trig_types); + id_end=id_start; + trig_length=id_start; + for i=1:num_trig_types + % remove triggers that have any other triggers 's_pre' seconds before + this_trig=remove_trig(all_trig_cell{i}, all_trig, s_pre); + % find first and last frames for every trigger + n_trig(i)=length(this_trig); + this_id_start=nan(1,n_trig(i)); + this_id_end=this_id_start; + for j=1:n_trig(i) + % first frame (trig - s_pre) + [~, this_id_start(j)] = min(abs(time_im - (this_trig(j) - s_pre))); + this_id_start(j)=this_id_start(j)+1; + % last frame (trig + s_post or 1 imaging frame before next trig); + next_trig_id=find(all_trig-this_trig(j)>0,1); + if isempty(next_trig_id) + next_trig=inf; + else + next_trig=all_trig(next_trig_id)-im_dt; + end + this_id_end(j)=min(next_trig,this_trig(j) + s_post); + [~, this_id_end(j)] = min(abs(time_im - this_id_end(j))); + end + % remove triggers that are too close to the next trigger + tf_remove=time_im(this_id_end)<=this_trig; + this_id_start(tf_remove)=[]; + this_id_end(tf_remove)=[]; + id_start{i} = this_id_start; + id_end{i} = this_id_end; + trig_length{i}=this_id_end-this_id_start+1; + n_trig(i) = length(this_id_start); + end + + %% analysis for criteria (barcodes) + % compute triggered avereages + traces_bout_trig_crit = dm_compute_triggered_traces(bout1_starts,s_pre,s_post,dt,time_im,traces_interp); + trace_motor_regr_bout_trig_crit = dm_compute_triggered_traces(bout1_starts,s_pre,s_post,dt,time_im,trace_motor_regr_interp); + + % compute scores + scores_im = compute_scores_here(traces_bout_trig_crit,time_trig,clipping); + scores_motor_regr = compute_scores_here(trace_motor_regr_bout_trig_crit,time_trig,clipping)'; + scores_be=trials.bout_duration.first; + + % compute criteria + crit_im = nan(n_ROIs,4); + temp_block2 = nanmean(scores_im(:,11:20),2); + temp_block3 = nanmean(scores_im(:,21:30),2); + temp_block7 = nanmean(scores_im(:,61:70),2); + temp_block8 = nanmean(scores_im(:,71:80),2); + temp_block12 = nanmean(scores_im(:,111:120),2); + crit_im(:,1) = temp_block3 - temp_block2; + crit_im(:,2) = temp_block7 - temp_block3; + crit_im(:,3) = temp_block8 - temp_block7; + crit_im(:,4) = temp_block12 - temp_block8; + + crit_motor_regr = nan(1,4); + temp_block2 = nanmean(scores_motor_regr(11:20),2); + temp_block3 = nanmean(scores_motor_regr(21:30),2); + temp_block7 = nanmean(scores_motor_regr(61:70),2); + temp_block8 = nanmean(scores_motor_regr(71:80),2); + temp_block12 = nanmean(scores_motor_regr(111:120),2); + crit_motor_regr(1) = temp_block3 - temp_block2; + crit_motor_regr(2) = temp_block7 - temp_block3; + crit_motor_regr(3) = temp_block8 - temp_block7; + crit_motor_regr(4) = temp_block12 - temp_block8; + + crit_be=nan(1,4); + temp_block2 = nanmean(scores_be(11:20)); + temp_block3 = nanmean(scores_be(21:30)); + temp_block7 = nanmean(scores_be(61:70)); + temp_block8 = nanmean(scores_be(71:80)); + temp_block12 = nanmean(scores_be(111:120)); + crit_be(1) = temp_block3 - temp_block2; + crit_be(2) = temp_block7 - temp_block3; + crit_be(3) = temp_block8 - temp_block7; + crit_be(4) = temp_block12 - temp_block8; + + %% analysis for sensorimotor clustering + % compute trigered averages + scores=nan(n_ROIs,num_trig_types); + mean_traces=nan(n_ROIs,n_frames_trig,num_trig_types,'single'); + ste_traces=mean_traces; + for i=1:num_trig_types + [mean_traces(:,:,i), ste_traces(:,:,i), scores(:,i)] = compute_trigaver_here(... + id_start{i},... + id_end{i},... + trig_length{i},... + n_ROIs,... + n_frames_trig,... + n_trig(i),... + traces_interp,... + baseline_tf,... + score_tf(i,:)); + end + traces_gr_trig_mean = mean_traces(:,:,1); + traces_bout_trig_mean = mean_traces(:,:,2); + traces_gr_trig_ste = ste_traces(:,:,1); + traces_bout_trig_ste = ste_traces(:,:,2); + scores_gr = scores(:,1); + scores_bouts = scores(:,2); + clear mean_traces ste_traces; + + %% bootstrapping + % to build null ditributions for sens and motor scores + % and for criteria + chunk_start_ids = [1 : chunk_length : n_frames n_frames+1]; + n_chunks=length(chunk_start_ids(chunk_start_ids~=n_frames & chunk_start_ids~=n_frames+1)); + H0_scores=nan(n_ROIs,num_trig_types,n_boots); + H0_im=nan(n_ROIs,n_boots); + H0_motor_regr=nan(1,n_boots); + H0_be=nan(1,n_boots); + for ii=1:n_boots + % for sensorymotor clustering + chunk_ord=randperm(n_chunks); + t=1; + shuffled_traces=nan(n_ROIs,n_frames,'single'); + for j=1:n_chunks + this_chunk_ids = chunk_start_ids(chunk_ord(j)) : chunk_start_ids(chunk_ord(j)+1)-1; + this_chink_length = length(this_chunk_ids); + shuffled_traces(:,t:t+this_chink_length-1) = traces_interp(:,this_chunk_ids); + t=t+this_chink_length; + end + for i=1:num_trig_types + H0_scores(:,i,ii) = compute_trigaver_here_fast(... + id_start{i},... + id_end{i},... + trig_length{i},... + n_ROIs,... + n_frames_trig,... + n_trig(i),... + shuffled_traces,... + baseline_tf,... + score_tf(i,:)); + end + % for criteria + rand_ind = [1:10 randperm(110)+10]; + scores_im_shuf=scores_im(:,rand_ind); + temp_block2 = nanmean(scores_im_shuf(:,11:20),2); + temp_block3 = nanmean(scores_im_shuf(:,21:30),2); + H0_im(:,ii)=temp_block3-temp_block2; + scores_motor_regr_shuf=scores_motor_regr(rand_ind); + temp_block2 = nanmean(scores_motor_regr_shuf(11:20)); + temp_block3 = nanmean(scores_motor_regr_shuf(21:30)); + H0_motor_regr(ii)=squeeze(temp_block3-temp_block2); + scores_be_shuf = scores_be(rand_ind); + temp_block2 = nanmean(scores_be_shuf(11:20)); + temp_block3 = nanmean(scores_be_shuf(21:30)); + H0_be(ii)=temp_block3-temp_block2; + progressbar([],[],ii/n_boots,[]); + end + + %% find significant criteria + p_thresh = 0.05; + prcnt_min_im_5 = prctile(H0_im,p_thresh*100/2,2); + prcnt_max_im_5 = prctile(H0_im,100-p_thresh*100/2,2); + prcnt_min_motor_regr = prctile(H0_motor_regr,p_thresh*100/2); + prcnt_max_motor_regr = prctile(H0_motor_regr,100-p_thresh*100/2); + prcnt_min_be = prctile(H0_be,p_thresh*100/2); + prcnt_max_be = prctile(H0_be,100-p_thresh*100/2); + p_thresh = 0.15; + prcnt_min_im_15 = prctile(H0_im,p_thresh*100/2,2); + prcnt_max_im_15 = prctile(H0_im,100-p_thresh*100/2,2); + + crit_im_signif_5 = zeros(n_ROIs,4,'single'); + crit_im_signif_15 = zeros(n_ROIs,4,'single'); + for i=1:4 + crit_im_signif_5(crit_im(:,i)prcnt_max_im_5,i)=1; + crit_im_signif_15(crit_im(:,i)prcnt_max_im_15,i)=1; + end + crit_motor_regr_signif = zeros(1,4,'single'); + crit_motor_regr_signif(crit_motor_regrprcnt_max_motor_regr)=1; + crit_be_signif = zeros(1,4); + crit_be_signif(crit_beprcnt_max_be)=1; + clear H0_im H0_motor_regr H0_be + + %% cluster into sensory and motor cells + thresh95=prctile(H0_scores,100-5,3); + tf_sens=scores_gr>thresh95(:,1); + tf_mot=scores_bouts>thresh95(:,2) & scores_gr=gr_starts(t)-7.5 & time_im0 & time<=clipping,:),2)); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_preprocessing.m b/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_preprocessing.m new file mode 100644 index 0000000..ffa895f --- /dev/null +++ b/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/DM_wb_lta_preprocessing.m @@ -0,0 +1,156 @@ +% this progam performs pre-processing of the traces and ROI +% of the long-term adaptation experiment during whole-brain lightsheet imaging + +%% pathnames +clc; close all; clear all; +% path to raw data +pathname_MS_data = 'C:\Markov_et_al_2021_Nat_Commun_data_code\data\'; +pathname_wb_imaging_results=[pathname_MS_data 'whole_brain_imaging_long_term_adaptation\']; +pathname_raw_ROIs = [pathname_wb_imaging_results 'raw_ROIs\']; +pathname_raw_traces = [pathname_wb_imaging_results 'raw_traces\']; +pathname_affine_x=[pathname_wb_imaging_results 'anatomies\morphed\']; +pathname_temp_lists='C:\users\dmark\'; +pathname_ROIs = [pathname_wb_imaging_results 'ROIs\']; +pathname_traces = [pathname_wb_imaging_results 'traces\']; +pathname_behavior=[pathname_wb_imaging_results 'behavior\']; + +%% size and rezolution of the reference brain +[sz_ref,rez_ref]=read_nrrd_metadata([pathname_MS_data 'reference_brain_stacks\PortuguesLab_wholebrain_ref.nrrd']); +% whole brian mask +ref_mask=nrrdread([pathname_MS_data 'reference_brain_stacks\PortuguesLab_wholebrain_ref_mask.nrrd']); +ref_mask=ref_mask>0; + +%% cutoff frequency for high-pass filtering +fc_baseline=1/300; % Hz, 5 min period + +%% for building the motor regressor +s_half_decay = genotype2tau('GCaMP6s'); + +%% loop through all fish +all_fish=dm_dir([pathname_raw_traces '*_f*']); +n_fish=length(all_fish); +progressbar('Fish progress...','Morphing ROIs...','Fixing ROI IDs, processing traces...'); +for f=18%1:n_fish + fish_id=all_fish{f}; + + %% load traces + traces = h5read([pathname_raw_traces fish_id '\traces.h5'],'/traces')'; + traces=double(traces); + traces(all(isnan(traces),2),:)=[]; + [n_ROIs, n_frames] = size(traces); + + %% load ROIs + ROIs_local = tiff2mat(pathname_raw_ROIs, ['rois_' fish_id '.tif']); + ROIs_local = ROIs_local - min(ROIs_local(:))+1; + ROIs_local(ROIs_local==max(ROIs_local(:))) = 0; + ROIs_local=flip(ROIs_local,3); + ROIs_local = rot90(ROIs_local); + sz_ROIs_local=size(ROIs_local); + + %% affine x folder for morphing ROIs + affine_x=[pathname_affine_x fish_id '_anatomy_affine.xform']; + + %% behavior + load([pathname_behavior fish_id '_behavior.mat'],'meta','swim','time_be'); + pulse_times=flip(meta.pulse_times); + + %% high-pass filter for removing slow drift in the traces + [bb_baseline,aa_baseline]=butter(3,2*fc_baseline/meta.F,'high'); + traces(traces==0)=nan; + + %% process this fish + % get IDis of remaining ROIs + all_ROIs=unique(ROIs_local)'; + all_ROIs(all_ROIs==0)=[]; + % create output variables + ROIs=zeros(sz_ref,'uint32'); + time_offsets=nan(n_ROIs,1); + % start the loop that morphs the ROIs to the refernce brain + c=0; + for i=all_ROIs + c=c+1; + coord0=find(ROIs_local==i); + [row0,column0,plane0]=ind2sub(sz_ROIs_local, coord0); + ori_plane=plane0(1); + row0=row0*meta.rez; + column0=column0*meta.rez; + plane0=plane0*meta.z_step; + ori_plane_um=ori_plane*meta.z_step; + extended_planes=ori_plane_um-1:-1:ori_plane_um-meta.z_step+1; + num_ext_planes=length(extended_planes); + for ii=extended_planes + plane0=[plane0; ones(length(row0),1)*ii]; + end + row0=repmat(row0,num_ext_planes+1,1); + column0=repmat(column0,num_ext_planes+1,1); + + coord1=DM_morph_non_ref_coord([row0,column0,plane0],affine_x,pathname_temp_lists); + coord1=coord1./rez_ref; + coord1=unique([floor(coord1);ceil(coord1)],'rows'); + bad_coord=find(any(coord1<=0,2) | coord1(:,1)>sz_ref(1) | coord1(:,2)>sz_ref(2) | coord1(:,3)>sz_ref(3)); + coord1(bad_coord,:)=[]; + if ~isempty(coord1) + % write it's mid plane + % add this ROI coordinates + coord1=sub2ind(sz_ref, coord1(:,1), coord1(:,2), coord1(:,3)); + this_ROI = false(sz_ref); + this_ROI(coord1)=true; + % find if there are rois already + ROIs_there = unique(ROIs (this_ROI))'; + ROIs_there(ROIs_there==0)=[]; + for ii=ROIs_there + % find pixels that are intesecting and remove 1/2 + px = find(this_ROI & ROIs==ii); + this_ROI(px(randperm(length(px),round(length(px)/2))))=false; + end + ROIs(this_ROI)=i; + % write the temporal offset of this roi + time_offsets(i)=pulse_times(ori_plane); + end + progressbar([],c/n_ROIs,[]) + end + % remove out of brain ROIs + ROIs(~ref_mask)=0; + % find all remaining ROIs + all_ROIs=unique(ROIs)'; + all_ROIs(all_ROIs==0)=[]; + n_ROIs=length(all_ROIs); + % fix ROI IDs and process the traces + ROIs2=zeros(sz_ref,'uint32'); + traces2=nan(n_ROIs,n_frames,'single'); + time_offsets2=nan(n_ROIs,1); + ROI_coord=cell(n_ROIs,1); + for i=1:n_ROIs + old_id=all_ROIs(i); + coord = ROIs==old_id; + ROIs2(coord)=i; + time_offsets2(i)=time_offsets(old_id); + traces2(i,:) = process_trace_here(traces(old_id,:),bb_baseline,aa_baseline); + ROI_coord{i}=int32(find(coord)); + progressbar([],[],i/n_ROIs); + end + ROIs=ROIs2; + traces=traces2; + time_offsets=time_offsets2; + + %% build motor regressor + time_im=1/meta.F:1/meta.F:n_frames/meta.F; + my_kernel=2.^(-time_be/s_half_decay); + trace_motor_regr=trace2regressor(swim,my_kernel,time_be,time_im); + trace_motor_regr = process_trace_here(trace_motor_regr,bb_baseline,aa_baseline); + + %% save + save([pathname_ROIs fish_id '_ROIs.mat'],'ROIs','ROI_coord'); + save([pathname_traces fish_id '_traces.mat'],'traces','time_offsets','trace_motor_regr'); + progressbar(f/n_fish,[],[]) +end + +function [trace] = process_trace_here(trace,bb_baseline,aa_baseline) +my_nans=isnan(trace); +trace(my_nans)=nanmean(trace); +trace=filtfilt(bb_baseline,aa_baseline,trace); +trace(my_nans)=nan; +trace=trace-nanmean(trace); +trace=trace/nanstd(trace); +trace=single(trace); +end \ No newline at end of file diff --git a/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/readme.txt b/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/readme.txt new file mode 100644 index 0000000..695978f --- /dev/null +++ b/analysis/imaging_analysis/whole_brain_imaging_long_term_adaptation/readme.txt @@ -0,0 +1 @@ +DM_wb_lta_lighsheet_analysis.m is the main code that calls other scripts from this folder. \ No newline at end of file diff --git a/stytra_scripts/E0030_long_term_adaptation_v01_normal.py b/experiment_control/E0030_long_term_adaptation_v01_normal.py similarity index 100% rename from stytra_scripts/E0030_long_term_adaptation_v01_normal.py rename to experiment_control/E0030_long_term_adaptation_v01_normal.py diff --git a/stytra_scripts/E0030_long_term_adaptation_v02_lag.py b/experiment_control/E0030_long_term_adaptation_v02_lag.py similarity index 100% rename from stytra_scripts/E0030_long_term_adaptation_v02_lag.py rename to experiment_control/E0030_long_term_adaptation_v02_lag.py diff --git a/experiment_control/E0030_long_term_adaptation_v09_lightsheet.py b/experiment_control/E0030_long_term_adaptation_v09_lightsheet.py new file mode 100644 index 0000000..ce5f855 --- /dev/null +++ b/experiment_control/E0030_long_term_adaptation_v09_lightsheet.py @@ -0,0 +1,132 @@ +import numpy as np +import pandas as pd + +from stytra_config import ConfiguredStytra +from stytra.stimulation import Protocol +from stytra.stimulation.stimuli import CalibratingClosedLoop1D, \ + GratingStimulus, Basic_CL_1D, GainLagClosedLoop1D, GainChangerStimulus +from lightparam import Param + + +class ClosedLoop1DProt(Protocol): + name = "E0030_long_term_adaptation/v09_lightsheet" + + stytra_config = dict( + tracking=dict(embedded=True, method="tail", estimator="vigor"), + log_format="hdf5" + ) + + def __init__(self): + super().__init__() + + self.grating_cycle = Param(10, loadable=False, editable=False) + self.n_repeats_selfcalib = Param(10, loadable=False, editable=False) + self.n_repeats_pre = Param(10, loadable=False, editable=False) + self.n_repeats_exp = Param(50, loadable=False, editable=False) + self.n_repeats_post = Param(50, loadable=False, editable=False) + self.target_vel = Param(-20., limits=(-20, 20), loadable=False, editable=False) + self.calibrate_after = Param(10, loadable=False, editable=False) + self.max_interbout_time = Param(300, loadable=False, editable=False) + self.min_bouts_n = Param(20, loadable=False, editable=False) + self.start_gain = Param(-26, limits=(-50., 0.), loadable=False, editable=False) + self.lag = Param(0.225, limits=[0, 0.225]) + self.swimming_threshold = Param(-5, limits=(-20, 20)) + inter_stim_pause = 7.5 + grating_vel = 10 + grating_duration = 15 + self.inter_stim_pause = Param(inter_stim_pause, loadable=False, editable=False) + self.grating_vel = Param(grating_vel, loadable=False, editable=False) + self.grating_duration = Param(grating_duration, loadable=False, editable=False) + + self.t_base = np.array([0, inter_stim_pause, + inter_stim_pause, inter_stim_pause + grating_duration, + inter_stim_pause + grating_duration, 2 * inter_stim_pause +grating_duration]) + self.vel_base = np.array([0, 0, -grating_vel, -grating_vel, 0, 0]) + + self.ClosedLoop1DGratings = type("Stim", (Basic_CL_1D, + GratingStimulus), {}) + + def get_experimental_trials(self): + t = [0] + vel = [0] + for i in range(self.n_repeats_exp): + t.extend(self.t_base + t[-1]) + vel.extend(self.vel_base) + df = pd.DataFrame(dict(t=t, base_vel=vel)) + + ClosedLoop1DGratings = type("Stim", (GainLagClosedLoop1D, + GratingStimulus), {}) + lag = float(self.lag) + print(lag) + return ClosedLoop1DGratings( + df_param=df, + lag=lag, + grating_angle=np.pi / 2, + grating_period=self.grating_cycle, + swimming_threshold=self.swimming_threshold, + max_interbout_time=self.max_interbout_time) + + def get_stim_sequence(self): + stimuli = [] + # # gratings + # Calibration: + stimuli.append(GainChangerStimulus(self.start_gain)) + + t = [0] + vel = [0] + for i in range(self.n_repeats_selfcalib): + t.extend(self.t_base + t[-1]) + vel.extend(self.vel_base) + df = pd.DataFrame(dict(t=t, base_vel=vel)) + + ClosedLoop1DCalibratingGratings = type("Stim", (CalibratingClosedLoop1D, + GratingStimulus), {}) + + stimuli.append( + ClosedLoop1DCalibratingGratings( + df_param=df, + grating_angle=np.pi / 2, + grating_period=self.grating_cycle, + min_bout_n=self.min_bouts_n, + swimming_threshold=self.swimming_threshold, + target_avg_fish_vel=self.target_vel, + calibrate_after=self.calibrate_after, + max_interbout_time=self.max_interbout_time)) + + t = [0] + vel = [0] + for i in range(self.n_repeats_pre): + t.extend(self.t_base + t[-1]) + vel.extend(self.vel_base) + df = pd.DataFrame(dict(t=t, base_vel=vel)) + + stimuli.append( + self.ClosedLoop1DGratings( + df_param=df, + grating_angle=np.pi / 2, + grating_period=self.grating_cycle, + swimming_threshold=self.swimming_threshold, + max_interbout_time=self.max_interbout_time)) + + stimuli.append(self.get_experimental_trials()) + + t = [0] + vel = [0] + for i in range(self.n_repeats_post): + t.extend(self.t_base + t[-1]) + vel.extend(self.vel_base) + df = pd.DataFrame(dict(t=t, base_vel=vel)) + + stimuli.append( + self.ClosedLoop1DGratings( + df_param=df, + grating_angle=np.pi / 2, + grating_period=self.grating_cycle, + swimming_threshold=self.swimming_threshold, + max_interbout_time=self.max_interbout_time)) + + return stimuli + + +if __name__ == "__main__": + s = ConfiguredStytra(protocol=ClosedLoop1DProt()) diff --git a/stytra_scripts/E0031_acute_adaptation.py b/experiment_control/E0031_acute_adaptation.py similarity index 100% rename from stytra_scripts/E0031_acute_adaptation.py rename to experiment_control/E0031_acute_adaptation.py diff --git a/stytra_scripts/E0031_acute_adaptation_v02_lightsheet.py b/experiment_control/E0031_acute_adaptation_v02_lightsheet.py similarity index 100% rename from stytra_scripts/E0031_acute_adaptation_v02_lightsheet.py rename to experiment_control/E0031_acute_adaptation_v02_lightsheet.py diff --git a/imaging_preprocessing/convert_suite2p_data.ipynb b/preprocessing/convert_suite2p_data.ipynb similarity index 100% rename from imaging_preprocessing/convert_suite2p_data.ipynb rename to preprocessing/convert_suite2p_data.ipynb diff --git a/imaging_preprocessing/ls_import_2021_fimpy.ipynb b/preprocessing/ls_import_2021_fimpy.ipynb similarity index 100% rename from imaging_preprocessing/ls_import_2021_fimpy.ipynb rename to preprocessing/ls_import_2021_fimpy.ipynb diff --git a/imaging_preprocessing/run_suite2p.ipynb b/preprocessing/run_suite2p.ipynb similarity index 100% rename from imaging_preprocessing/run_suite2p.ipynb rename to preprocessing/run_suite2p.ipynb