diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..31c95a0 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8876070 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +SM_SpikeAnalysis.m diff --git a/AR_Process.m b/AR_Process.m new file mode 100644 index 0000000..be05f59 --- /dev/null +++ b/AR_Process.m @@ -0,0 +1,135 @@ +function [B,Pvals,BurstRate,threshVec] = AR_Process(P_Av_Data,Fs,maxThreshold) +%AR_Process.m +% Fit a generalized-linear model with a log link function to the burst +% data (which is preprocessed to consider burst activity as a point process, +% i.e. as a series of ones and zeros. The firing rate, mu, is modelled as +% a function of the activity during 20 seconds of lags up to the present +% like ln(mu) = X*b, where X is a matrix of the previous 20 seconds of +% activity. Thus, the log odds of firing a burst at the present moment +% depends on a linear combination of the previous 20 seconds of bursting +% activity. The output vector b(lag) represents the odds of firing in the +% present given a burst lag-1 bins ago. So, the value of b(2) gives the +% log odds of firing a burst given a burst 1 time step ago and no bursts +% at any other time +% See Pillow et al. Nature 2008 +% See also Gerhard et al. PLoS Comp Bio 2013 +%INPUT: P_Av_Data - output of the Ca_im_DataStream code, i.e. +% Processed_Data.Av_Data +% This code assumes that, for a given night, the same number of +% frames were taken for each video, i.e. each video was recorded for +% the same amount of time +% Fs - sampling frequency, Hertz +% maxThreshold - fraction from 0 to 1, the code will progressively +% threshold the burst data taking only those bursts with greater than +% threshold fraction of the total number of active ROIs, and +% maxThreshold tells this threshold procedure when to stop +%OUTPUT: B - list of coefficients for the link function ln(mu) = X*b +% Each row of B represents a burst threshold (see above), while +% each column represents the number of lags +% B(1,1) represents the log odds of firing a burst given no activity +% in the previous 20 seconds and a burst threshold of only a single +% ROI, B(1,2) is a lag of one frame, B(1,3) is a lag of two frames +% Pvals - statistics on the fit of the model +% equal to stats.p, for the p-value of the t test, which +% evaluates the null hypothesis that the coefficient b(lag) is equal +% to zero +% BurstRate - the baseline rate of bursting at each threshold (Hertz) +% threshVec - vector of thresholds up to maxThreshold +% +%Created: 2016/02/19 at 24 Cummington, Boston +% Byron Price +%Updated: 2016/04/06 +% By: Byron Price + +threshVec = 0:0.1:maxThreshold; +%timeLag = 2; +%numLags = round(timeLag*Fs); +numLags = 600; +timeLag = numLags/Fs; + +a =15;c=65; +phiVec = 20*pi:pi/2:31.5*pi; +numBases = length(phiVec); +BASIS = zeros(numLags,numBases); +count = 1; +t = 1:numLags; +for phi = phiVec + for tt=1:numLags + if a*log(t(tt)+c) > (phi-pi) && a*log(t(tt)+c) < (phi+pi) + BASIS(tt,count) = 0.5.*cos(a*log(t(tt)+c)-phi)+0.5; + else + BASIS(tt,count) = 0; + end + end +% plot(t,b) +% hold on; +% title(sprintf('phi=%d',phi)); +% pause(0.2) + count = count+1; +end + +numNights = size(P_Av_Data,2); +numVideos = zeros(numNights,1); +numFrames = zeros(numNights,1); +totalLength = 0; +for ii=1:numNights + numVideos(ii) = size(P_Av_Data{ii},1); + numFrames(ii) = size(P_Av_Data{ii},2); + if numFrames(ii) > numLags + totalLength = totalLength + numVideos(ii)*(numFrames(ii)-numLags); + else + display('Must decrease the variable timeLag') + return; + end +end +clear numVideos numFrames; + +Time = linspace(1/Fs,timeLag,numLags); +B = zeros(length(threshVec),numBases+1); +Pvals = zeros(length(threshVec),numBases+1); +threshcount = 1; +for threshold=threshVec + Y = zeros(totalLength,1); + HIST = zeros(totalLength,numLags); + count = 1; + for zz=1:numNights + Av_Data = P_Av_Data{zz}; + numVideos = size(Av_Data,1); + numFrames = size(Av_Data,2); + for jj=1:numVideos + newData = Av_Data(jj,:)./max(Av_Data(jj,:)); + newData(newData0) = 1; + if count == 1 + top = 1; + else + top = bottom+1; + end + bottom = top+length(newData((numLags+1):end))-1; + Y(top:bottom,1) = newData((numLags+1):end); + for kk=1:numLags + HIST(top:bottom,kk) = newData((numLags-(kk-1)):(numFrames-kk)); + end + count = count+1; + clear newData; + end + end + X = HIST*BASIS; + [b,~,stats] = glmfit(X,Y,'poisson'); + B(threshcount,:) = b'; + Pvals(threshcount,:) = stats.p; + threshcount = threshcount+1; +end +figure();plot(Time,BASIS*(B(1,2:end)'));xlabel('Time Lag (seconds)');ylabel('Probability of Bursting'); +title('Probability a burst will occur time-lag seconds after a previous burst (Threshold for Bursting of 1 ROI'); +figure();plot(1:numBases,Pvals(1,2:end));xlabel('Parameter');ylabel('P-value'); +title('P-values for each of the model parameters'); +figure();imagesc(Time,threshVec,(BASIS*(B(:,2:end)'))');xlabel('Time Lag (seconds)');ylabel('Threshold'); +title('Probability of bursting (all thresholds)'); +%figure();plot(Time,B(1,2:end));figure();plot(Time,B(end,2:end)); +BurstRate = exp(B(:,1)).*Fs; +figure();plot(threshVec,BurstRate);ylabel('Baseline Burst Rate (Hz)'); +xlabel('Threshold (fraction of total ROIs active)'); +title('Burst rate as a function of burst threshold'); +end + diff --git a/Byrons_Avalanche_Analysis.m b/Byrons_Avalanche_Analysis.m new file mode 100644 index 0000000..b467f99 --- /dev/null +++ b/Byrons_Avalanche_Analysis.m @@ -0,0 +1,182 @@ +function [Av_Size,mean_Size,Av_IEI,mean_IEI,StDev_IEI,Time] = Byrons_Avalanche_Analysis(Av_Data,window,maxThreshold) +%Avalanche_Analysis.m +% Take "Av_Data" matrix from "From_Raw_To_Traces.m" output and count +% avalanches using different definitions and thresholds. +% Created: 2015/12/15 at 24 Cummington, Boston +% Byron Price +% Updated: 2015/12/15 +% by: Byron Price +% +% INPUT: Av_Data - a single matrix size videos by frames +% +% window - for avalanche definition +% maxThreshold - also for avalanche definition, the code will +% iterate from a threshold of 1 up to maxThreshold, where each +% threshold signifies the minimum number of ROIs that must be active +% in a single frame for an avalanche to be counted +% +% OUTPUT: Av_Size - a matrix with count data for each of the possible +% thresholds and avalanche sizes ... if Av_Size(1,1) = 50, then +% there were 50 instances of an avalanche of size 1 +% * matrix size threshold by max number of ROIs +% +% mean_Av_Size - the mean size of an avalanche at each threshold +% ... this isn't so interesting as we force the minimum up with +% each increase in the treshold +% +% Av_IEI - a matrix with count data for each of the possible +% avalanche thresholds and inter-event intervals +% = There are # avalanches with an IEI of 1 frame; 2 frames; etc. +% +% mean_Av_IEI - the mean inter-event interval between avalanches of +% size at least "threshold" +% +% Time - vector of times corresponding to the bins in Av_IEI, +% try plotting plot(Time, Av_IEI(1,:)) for a plot of the number +% of instances of an inter-event interval at each of the times in +% Time assuming only those bins with greater than or equal to 1 +% active ROI is counted as an avalanche ... Av_IEI(2,:) would give +% you the same plot but with IEI's between those avalanches greater +% than or equal to a size of two ROIs +% +% AVALANCHE DEFINITION +% If window = 0, then the definition is ... the summed activity across +% all ROIs in a single time bin, if that sum is greater than the value of +% threshold. So, if 10 ROIs are active in time bin 20, +% then that's an avalanche of size 10. Each bin is an island and +% contiguous bins are never counted as part of the same avalanche. As +% threshold increases, the minimum number of active ROIs per bin +% increases. +% Example: For a threshold of 1, a sequence from Av_Data like +% [0,0,1,3,4,0,5,6,9,0,0,0] would have 4 inter-event intervals of +% 0 seconds (contiguous bins active), 1 IEI of 0.0333 seconds (1 bin +% separation), 1 IEI of 0.0666 seconds and at the end 1 of 0.0999 seconds. +% That would be for threshold 1 ... Av_IEI(1,:). For a threshold of +% 2, stored in Av_IEI(2,:), you would have only 4 avalanches and the +% IEIs would change. +% +% If window = 1, then the definition is ... the summed activity across +% all ROIs and time bins for which at least "threshold" ROIs are active. +% So, for threshold = 1, contiguous bins with at least one ROI active are +% counted as a single avalanche. +% Example: Given the sequence above [0,0,1,3,4,0,5,6,9,0,0,0] and a +% threshold of 1, the inter-event inetervals would be the same, except +% there would be no IEIs of 0 seconds because IEIs of 0 seconds mean +% two consecutive bins were active and both bins are counted in the +% same avalanche. The sizes, however, would change, with 1 avalanche +% of size 1+3+4=8 ROIs and another avalanche of size 5+6+9=20 ROIs. +% +% As 'window' increases, the number of bins with activity below threshold +% between bins with activity above or equal to threshold grows. Thus, +% for window = 2 and the sequence above [0,0,1,3,4,0,5,6,9,0,0,0], there +% would now be only one avalanche of size 28. The IEIs would be +% basically the same but with 1 IEI of 2 bins (0.0666 seconds) and one of +% 3 bins (0.0999 seconds). +% +Fs = 30; +numVideos = size(Av_Data,1); +T = size(Av_Data,2); +Time = 0:1/Fs:T/Fs; +maxROIs = 500; + +Av_Size = zeros(maxThreshold,maxROIs); % avalanche size +%Av_Size(:,:,2) = ones(maxThreshold,1)*(1:maxROIs); +mean_Size = zeros(maxThreshold,1); + +Av_IEI = zeros(maxThreshold,length(Time)); % inter-event interval (seconds), or time + % between avalanches +mean_IEI = zeros(maxThreshold,1); + + +for threshold = 1:maxThreshold + Sizes = []; + IEIs = []; + for i=1:numVideos + icount = 0; + scount = 0; + if window == 0 + for t=1:T + if Av_Data(i,t) >= threshold || t == 1 + if Av_Data(i,t) >= threshold + Av_Size(threshold,Av_Data(i,t),1) = Av_Size(threshold,Av_Data(i,t),1)+1; + Sizes = [Sizes,Av_Data(i,t)]; + end + count = 0; + k = t+1; + while Av_Data(i,k) < threshold && k < T + k = k+1; + count = count+1; + end + if count < T-2 + Av_IEI(threshold,count+1,1) = Av_IEI(threshold,count+1,1)+1; + IEIs = [IEIs,Time(count+1)]; + end + end + end + + else + for t=1:T + if t >= (T-(window-1)) + if t == T + if scount > 0 + scount = sum(squeeze(Av_Data(i,t-scount:end))); + Av_Size(threshold,scount,1) = Av_Size(threshold,scount,1)+1; + Sizes = [Sizes,scount]; + end + if icount < T-1 + icount = icount+(window-1); + Av_IEI(threshold,icount+1,1) = Av_IEI(threshold,icount+1,1)+1; + IEIs = [IEIs,Time(icount+1)]; + end + else + len = length(Av_Data(i,t:end)); + if (squeeze(Av_Data(i,t:end)) < threshold) == ones(1,len) + icount = icount+1; + if scount > 0 + scount = sum(squeeze(Av_Data(i,t-scount:t-1))); + Av_Size(threshold,scount,1) = Av_Size(threshold,scount,1)+1; + Sizes = [Sizes,scount]; + scount = 0; + end + else + scount = scount+1; + if icount > 0 + icount = icount+(window-1); + Av_IEI(threshold,icount+1,1) = Av_IEI(threshold,icount+1,1)+1; + IEIs = [IEIs,Time(icount+1)]; + icount = 0; + end + end + end + else + if (squeeze(Av_Data(i,t:(t+(window-1)))) < threshold) == ones(1,window) + icount = icount+1; + if scount > 0 + scount = sum(squeeze(Av_Data(i,t-scount:t-1))); + Av_Size(threshold,scount,1) = Av_Size(threshold,scount,1)+1; + Sizes = [Sizes,scount]; + scount = 0; + end + else + scount = scount+1; + if icount > 0 + icount = icount+(window-1); + Av_IEI(threshold,icount+1,1) = Av_IEI(threshold,icount+1,1)+1; + IEIs = [IEIs,Time(icount+1)]; + icount = 0; + end + end + end + end + end + end + mean_Size(threshold,1) = mean(Sizes); + mean_IEI(threshold,1) = mean(IEIs); + StDev_IEI(threshold,1) = std(IEIs); + + +end +save('Spontaneous_Data_Averages2_2.mat','Av_Data','Av_IEI','Av_Size','mean_Size','mean_IEI','StDev_IEI'); +end + + diff --git a/Byrons_Burst_Analysis.m b/Byrons_Burst_Analysis.m new file mode 100644 index 0000000..b525b94 --- /dev/null +++ b/Byrons_Burst_Analysis.m @@ -0,0 +1,160 @@ +function [Av_Size,mean_Size,Av_IEI,mean_IEI,StDev_IEI,Time] = Byrons_Burst_Analysis(Av_Data,window,maxThreshold,Fs) +%Burst_Analysis.m +% Take "Av_Data" matrix from Ca_im_DataStream output and count +% avalanches using different definitions and thresholds. +% +% +% INPUT: Av_Data - a single matrix size videos by frames +% window - for avalanche definition (see below) +% maxThreshold - also for avalanche definition, the code will +% iterate from a threshold of 1 up to maxThreshold, where each +% threshold signifies the minimum number of ROIs that must be active +% in a single frame for an avalanche to be counted +% Fs - sampling frequency +% +% OUTPUT: Av_Size - a matrix with count data for each of the possible +% thresholds and avalanche sizes ... if Av_Size(1,1) = 50, then +% there were 50 instances of an avalanche of size 1 +% +% Av_IEI - a matrix with count data for each of the possible +% avalanche thresholds and inter-event intervals, Av_IEI(1,1) would +% be the number of instances of an avalanche of size at least 1 +% with an inter-event interval of 1/Fs, or one time bin ... +% Av_IEI(1,2) would be the number of instances of an avalanche of +% size at least 1 with an IEI of 2/Fs, or two time bins, so the +% activity would be something like this [1,0,1], the time between +% the first instance and the third instance is counted as two +% frames +% +% Time - vector of times corresponding to the bins in Av_IEI, +% try plotting plot(Time, Av_IEI(1,:)) for a plot of the number +% of instances of an inter-event interval at each of the times in +% Time assuming only those bins with greater than or equal to 1 +% active ROI is counted as an avalanche ... Av_IEI(2,:) would give +% you the same plot but with IEI's between those avalanches greater +% than or equal to a size of two ROIs +% +% AVALANCHE DEFINITION +% If window = 0, then the definition is ... the summed activity across +% all ROIs in a single time bin, if that sum is greater than the value of +% threshold. So, if 10 ROIs are active in time bin 20, +% then that's an avalanche of size 10. Each bin is an island and +% contiguous bins are never counted as part of the same avalanche. As +% threshold increases, the minimum number of active ROIs per bin +% increases. +% Example: For a threshold of 1, a sequence from Av_Data like +% [0,0,1,3,4,0,5,6,9,0,0,0] would have 4 inter-event intervals of +% 1/Fs seconds (contiguous bins active), 1 IEI of 2/Fs seconds (one empty bin +% jumpted), 1 IEI of 3/Fs seconds, and the beginning and end won't be +% counted. +% That would be for threshold 1 ... Av_IEI(1,:). For a threshold of +% two, stored in Av_IEI(2,:), you would have only 5 avalanches and +% so the IEIs would change accordingly +% +% If window = 1, then the definition is ... the summed activity across +% all ROIs and time bins for which at least "threshold" ROIs are active. +% So, for threshold = 1, contiguous bins with at least one ROI active are +% counted as a single avalanche. +% Example: Given the sequence above, [0,0,1,3,4,0,5,6,9,0,0,0], and a +% threshold of 1, the inter-event inetervals would be the same, except +% there would be no IEIs of 1/Fs seconds, because IEIs of 1/Fs seconds mean +% two consecutive bins were active and, if that is true, those two bins +% are counted in the same avalanche. The sizes, however, would change, +% with 1 avalanche of size 1+3+4=8 ROIs and another avalanche of size +% 5+6+9=20 ROIs. +% +% As 'window' increases, the number of bins with activity below threshold +% between bins with activity above or equal to threshold grows. Thus, +% for window = 2 and the sequence above [0,0,1,3,4,0,5,6,9,0,0,0], there +% would now be only one avalanche of size 28. There would now be no IEIs +% counted because the beginning and end are ignored. +% +% Created: 2015/12/15 at 24 Cummington, Boston +% Byron Price +% Updated: 2016/02/19 +% By: Byron Price + +numVideos = size(Av_Data,1); +numFrames = size(Av_Data,2); +Time = 1/Fs:1/Fs:numFrames/Fs; +maxROIs = 500; + +Av_Size = zeros(maxThreshold,maxROIs); % avalanche size + +Av_IEI = zeros(maxThreshold,length(Time)); % inter-event interval (seconds), or time + % between avalanches + +for threshold = 1:maxThreshold + Sizes = []; + IEIs = []; + for ii=1:numVideos + newData = Av_Data(ii,:); + newData(newData 1 + Av_IEI(threshold,burstsAt(jj)-burstsAt(jj-1)) = ... + Av_IEI(threshold,burstsAt(jj)-burstsAt(jj-1))+1; + end + end + + elseif window > 0 + extraNewData = zeros(length(newData),1); + for jj=1:length(burstsAt) + count = 0; + for kk=jj+1:length(burstsAt) + if (burstsAt(kk)-burstsAt(kk-1)) <= window + count = count+1; + else + break; + end + end + if count == 0 + newcount = count; + extraNewData(burstsAt(jj)) = newData(burstsAt(jj)); + else + summedActiv = sum(newData(burstsAt(jj):burstsAt(jj)+count)); + if mod(count,2) == 0 + extraNewData(burstsAt(jj)+count/2) = summedActiv; + newData(burstsAt(jj)+count/2) = summedActiv; + newcount = count/2; + elseif mod(count,2) == 1 + randNum = rand; + if randNum <= 0.5 + newcount = floor(count/2); + extraNewData(burstsAt(jj)+floor(count/2)) = summedActiv; + newData(burstsAt(jj)+floor(count/2)) = summedActiv; + elseif randNum > 0.5 + newcount = ceil(count/2); + extraNewData(burstsAt(jj)+ceil(count/2)) = summedActiv; + newData(burstsAt(jj)+ceil(count/2)) = summedActiv; + end + end + end + newData([burstsAt(jj):(burstsAt(jj)+newcount-1),(burstsAt(jj)+newcount+1):burstsAt(jj+count)]) = 0; + end + clear burstsAt; + burstsAt = find(extraNewData); + for ll=1:length(burstsAt) + Av_Size(threshold,extraNewData(burstsAt(ll))) = ... + Av_Size(threshold,extraNewData(burstsAt(ll)))+1; + if ll > 1 + Av_IEI(threshold,burstsAt(ll)-burstsAt(ll-1)) = ... + Av_IEI(threshold,burstsAt(ll)-burstsAt(ll-1))+1; + end + end + end + end + mean_Size(threshold,1) = mean(Sizes); + mean_IEI(threshold,1) = mean(IEIs); + StDev_IEI(threshold,1) = std(IEIs); + + +end +% save('Spontaneous_Data_Averages3.mat','Av_Data','Av_IEI','Av_Size','mean_Size','mean_IEI','StDev_IEI'); +save('Spontaneous_Data_Averages3.mat','Av_Data','Av_IEI','Av_Size'); +end diff --git a/Byrons_From_Raw_To_Traces.m b/Byrons_From_Raw_To_Traces.m new file mode 100755 index 0000000..c0d931d --- /dev/null +++ b/Byrons_From_Raw_To_Traces.m @@ -0,0 +1,188 @@ +function [Av_Data,Trace_Data,Spike_Data] = Byrons_From_Raw_To_Traces(aveRoiRaw,threshold,FitType,Fs,binSize) +%From_Raw_To_Traces.m +% +% Created: 2015/12/11 at 24 Cummington, Boston +% Byron Price +% Updated: 2015/12/11 +% By: Byron Price +% This file will run through raw data of fluorescence traces and output +% detrended fluorescence traces, spike data, and summed spike data +% across ROIs (called avalanches). +% +% INPUT: aveRoiRaw - the roi_ave.raw matrix from a single session +% FOUR OPTIONAL INPUTS +% FitType - string with type of fit to perform on data from single +% ROIs within individual recordings, this is for +% detrending bleaching and some noise, MATLAB allows +% varied input, like 'poly1' for linear or 'fourier8' +% for 8-term Fourier series +% threshold - z-score threshold (peaks in activity above this value +% are counted as spikes, default = 2 +% Fs - sampling frequency (Hz), default = 30 +% binSize - width of bins (secs), spikes are counted as having occurred +% within bins of a certain size, default = 1/Fs +% OUTPUT: Av_Data - number videos by number frames matrix of summed spike +% activity +% Trace_Data - number videos by number ROIs by number frames +% matrix of detrended fluorescence traces +% Spike_Data - number videos by number ROIs by number frames +% matrix of spike data (zeros and ones for each ROI +% indicating a spike in a bin) +% + +tic + +%OPTIONAL INPUTS +if nargin > 5 + error('Gardner:DataStream:TooManyInputs', ... + 'Requires at most 4 optional inputs'); +end + +% Fill in unset optional inputs. +switch nargin + case 1 + threshold = 2; + FitType = 'fourier5'; % could try 'fourier1' 'fourier4' fourier8' 'exp1' + Fs = 30; + binSize = 1/Fs; + case 2 + FitType = 'fourier5'; + Fs = 30; + binSize = 1/Fs; + case 3 + Fs = 30; + binSize = 1/Fs; + case 4 + binSize = 1/Fs; +end + +% FIGURE OUT HOW MANY VIDEOS, ROIs, and FRAMES +alldata = aveRoiRaw; +numVideos = size(alldata,2); +numROIs = size(alldata{1},1); +shift = 1*Fs; % how many frames to cut off from beginning and end + % the number is in units of seconds +numFrames = length(alldata{1,1}(1,shift:end-shift)); + +% DETREND EACH ROI INDIVIDUALLY FOR EACH VIDEO +Trace_Data = zeros(numVideos,numROIs,numFrames); +for i = 1:numVideos + for j = 1:numROIs + [alldata{1,i}(j,shift:end-shift)] = Preprocessing(alldata{1,i}(j,shift:end-shift),FitType); + end + Trace_Data(i,:,:) = alldata{1,i}(:,shift:end-shift); +end + +Detrended = toc + +% COUNT SPIKES AND SUM ACROSS ROIs IN A SINGLE RECORDING +Spike_Data = zeros(numVideos,numROIs,numFrames); +Av_Data = zeros(numVideos,numFrames); +for j=1:numVideos + binarySpikes = []; % will contain event data for all ROIs in + % a single recording + for k=1:numROIs + % detect calcium spikes + [~,Spikes] = Spike_Detector(squeeze(Trace_Data(j,k,:)),Fs,binSize,threshold); + binarySpikes = [binarySpikes,Spikes]; + end + Spike_Data(j,:,:) = binarySpikes'; + sumSpikes = sum(binarySpikes,2); % add up spikes from each ROI + % into a single vector, this + % will be used to deterimine + % avalanche size + + Av_Data(j,:) = sumSpikes; + +end + +save('Spontaneous_Data.mat','Av_Data','Spike_Data','Trace_Data'); + +end + + + +function [timeSeries] = Preprocessing(timeSeries,FitType) +% Av_Preprocessing.m +% Detrend a time series and subtract out the mean +% Created:2015/10/21 at 24 Cummington, Boston +% Byron Price +% Updated: 2015/12/11 +% By: Byron Price +% INPUT: timeSeries - calcium imaging pixel intensities over time for a +% single ROI +% OUTPUT: timeSeries - detrended data + +% LINEAR REGRESSION TO SUBTRACT OUT BLEACHING +% x = 1:1:length(timeSeries); +% X = [ones(length(x),1) x']; +% b = X\timeSeries'; +% ycalc = X*b; +% +% timeSeries = (timeSeries'-ycalc)'; + +% REGRESSION TO SUBTRACT OUT BLEACHING AND OTHER +% INHOMOGENEITIES IN THE DATA +x = 1:length(timeSeries); +f = fit(x',timeSeries',FitType); +Y = f(x); + +timeSeries = (timeSeries'-Y)'; + +timeSeries = timeSeries./max(timeSeries); +end + +function [numBins,Spikes] = Spike_Detector(timeSeries,sampleFreq,binSize,threshold) +%Avalanche.m +% Detect calcium spikes in imaging data for a single ROI. +% Created: 2015/09/30 at 24 Cummington, Boston +% Byron Price +% Updated: 2015/12/11 +% By: Byron Price +% +% REFERENCE: Klaus, Plenz 2011 Statistical Analyses Support Power Law ... +% Ribeiro, Copelli et al. 2010 Spike Avalanches Exhibit ... +% +% INPUT: timeSeries - change in activity over time for a single ROI in +% units given by T = 1/Fs ... Fs = sampling frequency +% sampleFreq - sampling frequency, Hz +% binSize - width of bin (seconds) +% Spikes are counted as having occurred within a given +% bin if the activity of that bin is above "threshold" +% threshold - zscore threshold (1.5, 2 etc. standard deviations +% above the mean) for decision: above threshold = activity +% forms part of an avalanche +% OUTPUT: numBins - given the binSize and the length of the recording, +% numBins = (total # frames) / (# frames / bin) +% Spikes - a vector containing either a 0 or a 1, 1 being an +% spike of activity within that bin, 0 otherwise + +T = 1/sampleFreq; % period for a single frame +framesPerBin = round(binSize/T); + + +times = 1:framesPerBin:length(timeSeries); +numBins = length(times); %number of bins, based on the + % length of the data and bin size (secs) + +Spikes = zeros(numBins,1); +% timeSeries = timeSeries./max(timeSeries); +stdActivity = std(timeSeries); +% SPIKE DETECTION LOOP + +% the trace was already divided by its maximum value, there are two steps to being +% counted as a calcium spike: 1) have value that is greater than or equal to +% 2 standard deviations above the mean; and 2) be a local maximum, meaning +% the fluorescence intensity of the current time step should be greater +% than both of its neighbors + +for i=2:numBins-1 + if timeSeries(i)/stdActivity > threshold % tentatively counted as spike if above threshold + if timeSeries(i) > timeSeries(i-1) && timeSeries(i) > timeSeries(i+1) + Spikes(i) = 1; + end + end +end +end + + diff --git a/Byrons_Plot_Spikes_Traces.m b/Byrons_Plot_Spikes_Traces.m new file mode 100755 index 0000000..1574a6c --- /dev/null +++ b/Byrons_Plot_Spikes_Traces.m @@ -0,0 +1,610 @@ +function [] = Byrons_Plot_Spikes_Traces(filename, roi_ave) +%Plot_Spikes_Bursts +% Created: 2015/12/11 at 24 Cummington, Boston +% Byron Price +% plotSpikeRaster was made by Jeffrey Chiou ... see below +% Updated: 2015/12/11 +% By: Byron Price +% This file will run through detrended fluorescence traces, spike data, +% and summed spike data across ROIs, creating a single figure for each +% video. It assumes a sampling frequency of 30 Hz. +% +% Call this file as Plot_Spikes_Traces( ... ); with no output +% INPUT: Av_Data - number videos by number frames matrix of summed spike +% activity +% Trace_Data - number videos by number ROIs by number frames +% matrix of detrended fluorescence traces +% Spike_Data - number videos by number ROIs by number frames +% matrix of spike data (zeros and ones for each ROI +% indicating a spike in a bin) +% +% OUTPUT: plots as many figures as videos ... be careful if there are lots +% videos +load(filename) +Fs = 30; +%n = [ 2 4 5 7 11 13 14 15 18 19 20 21 24 27 28 30 31 1 32 33]; +% 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 +numVideos = size(Spike_Data,1); +numROIs = size(Spike_Data,2); %length(n); +numFrames = size(Spike_Data,3); +n = 1:numROIs; + +Recording_Time = size(Spike_Data,3)/Fs; + +for i=1:numVideos + avalanches = squeeze(Av_Data(i,:)); + spikes = squeeze(Spike_Data(i,n,:)); + traces = squeeze(Trace_Data(i,n,:)); + times = 1/Fs:1/Fs:Recording_Time; + + FigName = ['Video ' num2str(i) ' ' roi_ave.filename{i}]; + figure('Name',FigName); hold on + % AVALANCHE PLOT + h(1) = subplot(4,1,4); + bar(times,avalanches) + axis([1 Recording_Time 0 max(avalanches)+5]) + ylabel('ROI count') + xlabel('Time (s)') + + % necessary to change data input for plotSpikeRaster + spikecell = cell(numROIs,1); + for j = 1:numROIs + for k=1:numFrames + if spikes(j,k) == 1 + spikecell{j} = [spikecell{j},times(k)]; + end + end + end + % SPIKE RASTERS + h(2)=subplot(4,1,3); + plot_rastergram(times, spikes, 'colors', lines(numROIs)); % uses Nathan's plot_rastergram script; can be used with colors + %[~,~] = plotSpikeRaster(spikecell,'PlotType','vertline','SpikeDuration',1/Fs,'TimePerBin',1/Fs); % uses function in this script - draws one, NaN-interrupted line as spike raster + ylabel('ROI') + xlabel('Time (s)') + + % TRACE PLOT + h(3) = subplot(4,1,[1:2]); +% Fluorescence_Plot(traces,times,Recording_Time) + trace_range = max(roi_ave.raw{i}, [], 2) - min(roi_ave.raw{i}, [], 2); % rescale lines so that noise in traces without spikes is not scaled up + plot_many(times,bsxfun(@(x, y) x * y, traces', trace_range(n)')); % uses Nathan's plotting script that orders the lines top to bottom, labels them, etc + ylabel('ROI') + linkaxes(h,'x') + hold off +end + +end + +function Fluorescence_Plot(Input_Data,times,Recording_Time) + +numROIs = size(Input_Data,1); +c = colormap(lines(numROIs)); + +count = 1; +for i = numROIs:-1:1 + hold on + + z = Input_Data(i,:); + + shiftup = (3*count); + plot(times,z+shiftup,'Color',c(count,:),'LineWidth',1); + count = count+1; +end +axis([0 Recording_Time 0 shiftup+3]) +hold off +end + +function [xPoints, yPoints] = plotSpikeRaster(spikes,varargin) +% PLOTSPIKERASTER Create raster plot from binary spike data or spike times +% Efficiently creates raster plots with formatting support. Faster than +% common implementations. Multiple plot types and parameters available! +% Look at Parameters section below. +% +% Inputs: +% M x N logical array (binary spike data): +% where M is the number of trials and N is the number of time +% bins with maximum of 1 spike per bin. Assumes time starts at 0. +% M x 1 cell of spike times: +% M is the number of trials and each cell contains a 1 x N vector +% of spike times. Units should be in seconds. +% +% Output: +% xPoints - vector of x points used for the plot. +% yPoints - vector of y points used for the plot. +% +% Parameters: +% PlotType - default 'horzline'. Several types of plots available: +% 1. 'horzline' - plots spikes as gray horizontal lines. +% 2. 'vertline' - plots spikes as vertical lines, centered +% vertically on the trial number. +% 3. 'scatter' - plots spikes as gray dots. +% +% ONLY FOR BINARY SPIKE DATA: +% 4. 'imagesc' - plots using imagesc. Flips colormap so +% black indicates a spike. Not affected by SpikeDuration, +% RelSpikeStartTime, and similar timing parameters. +% 5. 'horzline2' - more efficient plotting than horzline if +% you have many timebins, few trials, and high spike density. +% Note: SpikeDuration parameter DOES NOT WORK IF LESS THAN +% TIME PER BIN. +% 6. 'vertline2' - more efficient plotting than vertline if +% you have few timebins, many trials, and high spike density. +% Note: Horzline and vertline should be fine for most tasks. +% +% FigHandle - default gcf (get current figure). +% Specify a specific figure or subplot to plot in. If no figure +% is specified, plotting will occur on the current figure. If no +% figure is available, a new figure will be created. +% +% LineFormat - default line is gray. Used for 'horzline' and +% 'vertline' plots only. Usage example: +% LineFormat = struct() +% LineFormat.Color = [0.3 0.3 0.3]; +% LineFormat.LineWidth = 0.35; +% LineFormat.LineStyle = ':'; +% plotSpikeRaster(spikes,'LineFormat',LineFormat) +% +% MarkerFormat - default marker is a gray dot with size 1. Used for +% scatter type plots only. Usage is the same as LineFormat. +% +% AutoLabel - default 0. +% Automatically labels x-axis as 'Time (ms)' or 'Time (s)' and +% y-axis as 'Trial'. +% +% XLimForCell - default [NaN NaN]. +% Sets x-axis window limits if using cell spike time data. If +% unchanged, the default limits will be 0.05% of the range. For +% better performance, this parameter should be set. +% +% TimePerBin - default 0.001 (1 millisecond). +% Sets the duration of each timebin for binary spike train data. +% +% SpikeDuration - default 0.001 (1 millisecond). +% Sets the horizontal spike length for cell spike time data. +% +% RelSpikeStartTime - default 0 seconds. +% Determines the starting point of the spike relative to the time +% indicated by spike times or time bins. For example, a relative +% spike start time of -0.0005 would center 1ms spikes for a +% horzline plot of binary spike data. +% +% rasterWindowOffset - default NaN +% Exactly the same as relSpikeStartTime, but unlike +% relSpikeStartTime, the name implies that it can be used to make +% x-axis start at a certain time. If set, takes precedence over +% relSpikeStartTime. +% +% VertSpikePosition - default 0 (centered on trial). +% Determines where the spike position is relative to the trial. A +% value of 0 is centered on the trial number - so a spike on +% trial 3 would have its y-center on 3. Example: A common type of +% spike raster plots vertical spikes from previous trial to +% current trial. Set VertSpikePosition to -0.5 to center the +% spike between trials. +% +% VertSpikeHeight - default 1 (spans 1 trial). +% Determines height of spike for 'vertline' plots. Decrease to +% separate trials with a gap. +% +% Examples: +% plotSpikeRaster(spikeTimes); +% Plots raster plot with horizontal lines. +% +% plotSpikeRaster(spikeTimes,'PlotType','vertline'); +% Plots raster plot with vertical lines. +% +% plotSpikeRaster(spikeTimes,'FigHandle',h,'AutoLabel',1,... +% 'XLimForCell',[0 10],'HorzSpikeLength',0.002,); +% Plots raster plot on figure with handle h using horizontal +% lines of length 0.002, with a window from 0 to 10 seconds, +% and automatic labeling. +% +% plotSpikeRaster(spikeTimes,'PlotType','scatter',... +% 'MarkerFormat',MarkerFormat); +% Plots raster plot using dots with a format specified by +% MarkerFormat. + + +% AUTHOR : Jeffrey Chiou +% $DATE : 07-Feb-2014 12:15:47 $ +% $Revision : 1.2 $ +% DEVELOPED : 8.1.0.604 (R2013a) +% FILENAME : plotSpikeRaster.m + +% Set Defaults and Load optional arguments +LineFormat.Color = [0.2 0.2 0.2]; +MarkerFormat.MarkerSize = 1; +MarkerFormat.Color = [0.2 0.2 0.2]; +MarkerFormat.LineStyle = 'none'; + +p = inputParser; +p.addRequired('spikes',@(x) islogical(x) || iscell(x)); +p.addParamValue('FigHandle',gcf,@isinteger); +p.addParamValue('PlotType','horzLine',@ischar); +p.addParamValue('LineFormat',LineFormat,@isstruct) +p.addParamValue('MarkerFormat',MarkerFormat,@isstruct); +p.addParamValue('AutoLabel',0, @islogical); +p.addParamValue('XLimForCell',[NaN NaN],@(x) isnumeric(x) && isvector(x)); +p.addParamValue('TimePerBin',0.001,@(x) isnumeric(x) && isscalar(x)); +p.addParamValue('SpikeDuration',0.001,@(x) isnumeric(x) && isscalar(x)); +p.addParamValue('RelSpikeStartTime',0,@(x) isnumeric(x) && isscalar(x)); +p.addParamValue('RasterWindowOffset',NaN,@(x) isnumeric(x) && isscalar(x)); +p.addParamValue('VertSpikePosition',0,@(x) isnumeric(x) && isscalar(x)); +p.addParamValue('VertSpikeHeight',1,@(x) isnumeric(x) && isscalar(x)); +p.parse(spikes,varargin{:}); + +spikes = p.Results.spikes; +figH = p.Results.FigHandle; +plotType = lower(p.Results.PlotType); +lineFormat = struct2opt(p.Results.LineFormat); +markerFormat = struct2opt(p.Results.MarkerFormat); +autoLabel = p.Results.AutoLabel; +xLimForCell = p.Results.XLimForCell; +timePerBin = p.Results.TimePerBin; +spikeDuration = p.Results.SpikeDuration; +relSpikeStartTime = p.Results.RelSpikeStartTime; +rasterWindowOffset = p.Results.RasterWindowOffset; +vertSpikePosition = p.Results.VertSpikePosition; +vertSpikeHeight = p.Results.VertSpikeHeight; + +if ~isnan(rasterWindowOffset) && relSpikeStartTime==0 + relSpikeStartTime = rasterWindowOffset; +elseif ~isnan(rasterWindowOffset) && relSpikeStartTime~=0 + disp(['Warning: RasterWindoWOffset and RelSpikeStartTime perform the same function. '... + 'The value set in RasterWindowOffset will be used over RelSpikesStartTime']); + relSpikeStartTime = rasterWindowOffset; +end + +% Initialize figure and begin plotting logic +figure(figH); +hold on; + +if islogical(spikes) +% Binary spike train matrix case. Initialize variables and set axes. + nTrials = size(spikes,1); + nTimes = size(spikes,2); + % Convert Parameters to correct units using TimePerBin. Default is 1 ms + % per bin (0.001s) + spikeDuration = spikeDuration/timePerBin; + relSpikeStartTime = relSpikeStartTime/timePerBin; + + % Note: xlim and ylim are much, much faster than axis or set(gca,...). + xlim([0+relSpikeStartTime nTimes+1+relSpikeStartTime]); + ylim([0 nTrials+1]); + + switch plotType + case 'horzline' + % Horizontal Lines + % Find the trial (yPoints) and timebin (xPoints) of each spike + [trials,timebins] = find(spikes); + trials = trials'; + timebins = timebins'; + + xPoints = [ timebins + relSpikeStartTime; + timebins + relSpikeStartTime + spikeDuration; + NaN(size(timebins)) ]; + yPoints = [ trials + vertSpikePosition; + trials + vertSpikePosition; + NaN(size(trials)) ]; + + xPoints = xPoints(:); + yPoints = yPoints(:); + plot(xPoints,yPoints,'k',lineFormat{:}); + case 'vertline' + % Vertical Lines + % Find the trial (yPoints) and timebin (xPoints) of each spike + [trials,timebins] = find(spikes); + trials = trials'; + timebins = timebins'; + halfSpikeHeight = vertSpikeHeight/2; + + xPoints = [ timebins + relSpikeStartTime; + timebins + relSpikeStartTime; + NaN(size(timebins)) ]; + yPoints = [ trials - halfSpikeHeight + vertSpikePosition; + trials + halfSpikeHeight + vertSpikePosition; + NaN(size(trials)) ]; + + xPoints = xPoints(:); + yPoints = yPoints(:); + plot(xPoints,yPoints,'k',lineFormat{:}); + case 'horzline2' + % Horizontal lines, for many timebins + % Plots a horizontal line the width of a time bin for each + % spike. Efficient for fewer trials and many timebins. + xPoints = []; + yPoints = []; + + for trials = 1:nTrials + % If there are spikes, plot a line. Otherwise, do nothing. + if sum(spikes(trials,:)) > 0 + + % Find the difference in spike times. Padding at the + % front and back with a zero accounts for spikes in + % the first and last indices, and keeps startY and endY + % the same size + spikeDiff = diff([0 spikes(trials,:) 0]); + % Ex. [0 1 1] -> [0 0 1 1 0]. diff(...) -> [0 1 0 -1] + + % Find line segments to plot (line segments longer than + % one trial are for spikes on consecutive trials) + startX = find(spikeDiff > 0); + % Ex. cont. from above: find(...) -> 2 + endX = find(spikeDiff < 0); + % Ex. cont. from above: find(...) -> 4. Thus a line + % segment will be defined from 2 to 4 (x-axis) + + % Combine x points and adjust x points according to + % parameters. Add Add NaNs to break up line segments. + trialXPoints = [startX + relSpikeStartTime;... + endX + relSpikeStartTime + (spikeDuration - 1);... + NaN(size(startX)) ]; + % Explanation for 'spikeDuration - 1': spikeDuration + % has been converted already using timePerBin, so the + % offset at the end is simply duration - one timeBin, + % since 1 timebin's worth of spikes has passed. Only + % affects last spike if less than time per bin. + + % Convert x points array to vector + trialXPoints = trialXPoints(:)'; + + % Add y points centered on the trial by default + % (adjustable with vertSpikePosition parameter) + trialYPoints = trials*ones(size(trialXPoints)) + vertSpikePosition; + + % Store this trial's x and y points. Unfortunately, + % preallocating and trimming may actually be slower, + % depending on data. + xPoints = [xPoints trialXPoints]; + yPoints = [yPoints trialYPoints]; + + end + end + + plot(xPoints, yPoints,'k', lineFormat{:}); + + case 'vertline2' + % Vertical lines, for many trials + % Plot one long line for each timebin. Reduces the number of + % objects to plot. Efficient for many trials and fewer timebins + xPoints = []; + yPoints = []; + + for time = 1:nTimes + if sum(spikes(:,time)) > 0 + + % Find the difference in spike times. Same principle as + % horzline2. See comments above for explanation. + spikeDiff = diff([0 spikes(:,time)' 0]); + + % Find line segments to plot (line segments longer than + % one trial are for spikes on consecutive trials) + startY = find(spikeDiff > 0); + endY = find(spikeDiff < 0); + + % Add NaNs to break up line segments + timeBinYPoints = [startY + vertSpikePosition;... + endY + vertSpikePosition; NaN(size(startY))]; + % Convert to vector + timeBinYPoints = timeBinYPoints(:)'; + timeBinXPoints = time*ones(size(timeBinYPoints)); + + % Store this timebin's x and y points. + xPoints = [xPoints timeBinXPoints]; + % Subtract 0.5 from each y point so spikes are centered + % by default (adjustable with vertSpikePosition) + yPoints = [yPoints timeBinYPoints-0.5]; + + end + end + + plot(xPoints, yPoints, 'k', lineFormat{:}); + + case 'scatter' + % Dots or other markers (scatterplot style) + % Find the trial (yPoints) and timebin (xPoints) of each + % spike + [yPoints,xPoints] = find(spikes==1); + xPoints = xPoints + relSpikeStartTime; + plot(xPoints,yPoints,'.k',markerFormat{:}); + + case 'imagesc' + % Imagesc + imagesc(spikes); + % Flip the colormap since the default is white for 1, black for + % 0. + colormap(flipud(colormap('gray'))); + + otherwise + error('Invalid plot type. Must be horzline, vertline, horzline2, vertline2, scatter, or imagesc'); + end % switch + set(gca,'YDir','reverse'); + + % Label + if autoLabel + xlabel('Time (ms)'); + ylabel('Trial'); + end + +else % Equivalent to elseif iscell(spikes). + % Cell case + + % Validation: First check to see if cell array is a vector, and each + % trial within is a vector. + if ~isvector(spikes) + error('Spike cell array must be an M x 1 vector.') + end + trialIsVector = cellfun(@isvector,spikes); + if sum(trialIsVector) < length(spikes) + error('Cells must contain 1 x N vectors of spike times.'); + end + + % Now make sure cell array is M x 1 and not 1 x M. + if size(spikes,2) > 1 && size(spikes,1) == 1 + spikes = spikes'; + end + + % Make sure each trial is 1 x N and not N x 1 + nRowsInTrial = cellfun(@(x) size(x,1),spikes); + % If there is more than 1 row in any trial, add a warning, and + % transpose those trials. Allows for empty trials/cells (nRows > 1 + % instead of > 0). + if sum(nRowsInTrial > 1) > 0 + trialsToReformat = find(nRowsInTrial > 1); + disp('Warning - some cells (trials) have more than 1 row. Those trials will be transposed.'); + for t = trialsToReformat + spikes{trialsToReformat} = spikes{trialsToReformat}'; + end + end + + nTrials = length(spikes); + + % Find x-axis limits that aren't manually set (default [NaN NaN]), and + % automatically set them. This is because we don't assume spikes start + % at 0 - we can have negative spike times. + limitsToSet = isnan(xLimForCell); + if sum(limitsToSet) > 0 + % First find range of spike times + minTimes = cellfun(@min,spikes,'UniformOutput',false); + minTime = min( [ minTimes{:} ] ); + maxTimes = cellfun(@max,spikes,'UniformOutput',false); + maxTime = max( [ maxTimes{:} ] ); + timeRange = maxTime - minTime; + + % Find 0.05% of the range. + xStartOffset = relSpikeStartTime - 0.0005*timeRange; + xEndOffset = relSpikeStartTime + 0.0005*timeRange + spikeDuration; + newLim = [ minTime+xStartOffset, maxTime+xEndOffset ]; + xLimForCell(limitsToSet) = newLim(limitsToSet); + % End result, if both limits are automatically set, is that the x + % axis is expanded 0.1%, so you can see initial and final spikes. + end + xlim(xLimForCell); + ylim([0 nTrials+1]); + + if strcmpi(plotType,'vertline') || strcmpi(plotType,'horzline') + % Vertical or horizontal line logic + nTotalSpikes = sum(cellfun(@length,spikes)); + + % Preallocation is possible since we know how many points to + % plot, unlike discrete case. 3 points per spike - the top pt, + % bottom pt, and NaN. + xPoints = NaN(nTotalSpikes*3,1); + yPoints = xPoints; + currentInd = 1; + + if strcmpi(plotType,'vertline') + % Vertical Lines + halfSpikeHeight = vertSpikeHeight/2; + for trials = 1:nTrials + nSpikes = length(spikes{trials}); + nanSeparator = NaN(1,nSpikes); + + trialXPoints = [ spikes{trials} + relSpikeStartTime;... + spikes{trials} + relSpikeStartTime; nanSeparator ]; + trialXPoints = trialXPoints(:); + + trialYPoints = [ (trials-halfSpikeHeight)*ones(1,nSpikes);... + (trials+halfSpikeHeight)*ones(1,nSpikes); nanSeparator ]; + trialYPoints = trialYPoints(:); + + % Save points and update current index + xPoints(currentInd:currentInd+nSpikes*3-1) = trialXPoints; + yPoints(currentInd:currentInd+nSpikes*3-1) = trialYPoints; + currentInd = currentInd + nSpikes*3; + end + + else % (if plotType is 'horzline') + % Horizontal Lines + for trials = 1:nTrials + nSpikes = length(spikes{trials}); + nanSeparator = NaN(1,nSpikes); + + trialXPoints = [ spikes{trials} + relSpikeStartTime;... + spikes{trials} + relSpikeStartTime + spikeDuration;... + nanSeparator ]; + trialXPoints = trialXPoints(:); + + trialYPoints = [ trials*ones(1,nSpikes);... + trials*ones(1,nSpikes); nanSeparator ]; + trialYPoints = trialYPoints(:); + + % Save points and update current index + xPoints(currentInd:currentInd+nSpikes*3-1) = trialXPoints; + yPoints(currentInd:currentInd+nSpikes*3-1) = trialYPoints; + currentInd = currentInd + nSpikes*3; + end + + end + + % Plot everything at once! We will reverse y-axis direction later. + plot(xPoints, yPoints, 'k', lineFormat{:}); + + elseif strcmpi(plotType,'scatter') + % Dots or other markers (scatterplot style) + % Combine all spike times into one vector + xPoints = [ spikes{:} ]; + + % Getting the trials is trickier. 3 steps: + % 1. First convert all the spike times into ones. + trials = cellfun( @(x) {ones(size(x))}, spikes ); + % 2. Then multiply by trial number. + for trialNum = 1:length(spikes) + trials{trialNum} = trialNum*trials{trialNum}; + end + % 3. Finally convert into a vector + yPoints = [ trials{:} ]; + + % Now we can plot! We will reverse y-axis direction later. + plot(xPoints,yPoints,'.k',markerFormat{:}); + + elseif strcmpi(plotType,'imagesc') || strcmpi(plotType,'vertline2') || strcmpi(plotType,'horzline2') + error('Can''t use imagesc/horzline2/vertline2 with cell array. Use with logical array of binary spike train data.'); + else + error('Invalid plot type. With cell array of spike times, plot type must be horzline, vertline, or scatter.'); + end % plot type switching + + % Reverse y-axis direction and label + set(gca,'YDir','reverse'); + if autoLabel + xlabel('Time (s)'); + ylabel('Trial'); + end + +end % logical vs cell switching + +% Figure formatting +% Draw the tick marks on the outside +set(gca,'TickDir','out') + +% Use special formatting if there is only a single trial. +% Source - http://labrigger.com/blog/2011/12/05/raster-plots-and-matlab/ +if size(spikes,1) == 1 + set(gca,'YTick', []) % don't draw y-axis ticks + set(gca,'PlotBoxAspectRatio',[1 0.05 1]) % short and wide + set(gca,'YColor',get(gcf,'Color')) % hide the y axis + ylim([0.5 1.5]) +end + +hold off; + +end % main function + +function paramCell = struct2opt(paramStruct) +% Converts structure to parameter-value pairs +% Example usage: +% formatting = struct() +% formatting.color = 'black'; +% formatting.fontweight = 'bold'; +% formatting.fontsize = 24; +% formatting = struct2opt(formatting); +% xlabel('Distance', formatting{:}); +% Adapted from: +% http://stackoverflow.com/questions/15013026/how-can-i-unpack-a-matlab-structure-into-function-arguments +% by user 'yuk' + +fname = fieldnames(paramStruct); +fval = struct2cell(paramStruct); +paramCell = [fname, fval]'; +paramCell = paramCell(:); + +end % struct2opt diff --git a/FS_BatchDff_NEW.m b/FS_BatchDff_NEW.m new file mode 100644 index 0000000..624655c --- /dev/null +++ b/FS_BatchDff_NEW.m @@ -0,0 +1,125 @@ +function FS_BatchDff_NEW(DIR, varargin) + +%run thorough directory and make Background Subtracted Movies in AVI format +% This Script is for 'unprocessed' videos + + +% WALIII +% For unprocessed videos +% 09.05.15 + +filt_rad=1; % gauss filter radius +filt_alpha=1; % gauss filter alpha +lims=3; % contrast prctile limits (i.e. clipping limits lims 1-lims) +cmap=colormap('jet'); +per=10; % baseline percentile (0 for min) +counter = 1; + +mat_dir='DFF_MOVIES'; +counter = 1; + +if exist(mat_dir,'dir') rmdir(mat_dir,'s'); +end +mkdir(mat_dir); + +outlier_flag=0; +if nargin<1 | isempty(DIR), DIR=pwd; +end +mov_listing=dir(fullfile(DIR,'*.mat')); +mov_listing={mov_listing(:).name}; +filenames=mov_listing; + +disp('Creating Dff movies'); + +[nblanks formatstring]=fb_progressbar(100); +fprintf(1,['Progress: ' blanks(nblanks)]); + +for i=1:length(mov_listing) +clear video; +clear NormIm; +clear dff2; +clear dff; +clear mov_data3; +clear mov_data2; +clear mov_data; +clear mov_data_16bit; +clear baseline; +clear test; +clear v; + +[path,file,ext]=fileparts(filenames{i}); +fprintf(1,formatstring,round((i/length(mov_listing))*100)); + +load(fullfile(DIR,mov_listing{i}),'video') +save_filename = [ fullfile(mat_dir,file) ]; +LastFrame = length(video.frames); +mov_data = video.frames; + + +%mov_data_16bit = zeros(512,512,LastFrame); +for frameIter = 1:LastFrame-3; + mov_data_16bit1 = uint16(mov_data(frameIter).cdata); + mov_data_16bit2 = uint16(mov_data(frameIter+1).cdata); + mov_data_16bit3 = uint16(mov_data(frameIter+2).cdata); + mov_data_16bit(:,:,frameIter) = uint16(mov_data_16bit1 + mov_data_16bit2 + mov_data_16bit3)/3; +end +clear mov_data_16bit1; clear mov_data_16bit2; clear mov_data_16bit3; + + +test = single(mov_data_16bit(:,:,12:end)); +[rows,columns,frames]=size(test); + +%%%=============[ FILTER Data ]==============%%% + +disp('Gaussian filtering the movie data...'); + +h=fspecial('gaussian',filt_rad,filt_alpha); +test=imfilter(test,h,'circular'); + +disp(['Converting to df/f using the ' num2str(per) ' percentile for the baseline...']); + +baseline=repmat(prctile(test,per,3),[1 1 frames]); + + h=fspecial('gaussian',20,40); + baseline = imfilter(baseline,h,'circular'); % filter baseline + +tot = (test-baseline); +%baseline(baseline<0)=1; +dff = (tot./(baseline)).*100; +dff2 = imresize(dff,1);% Scale Data + +H = prctile(mean(max(dff2(:,:,15:end))),99); +L = prctile(mean(mean(dff2(:,:,15:end))),50); + +clim = [double(L) double(H)]; + +NormIm(:,:,:) = mat2gray(dff2, clim); + +%figure(1); for iii = 7:size(NormIm,3); IM(:,:) = NormIm(:,:,iii); imagesc(IM); pause(0.05); end + + + +%% Write VIDEO + +v = VideoWriter(save_filename); +v.Quality = 80; +v.FrameRate = 30; + +open(v) + +for ii = 2:size(NormIm,3); +figure(1); +colormap(gray); +IM(:,:) = NormIm(:,:,ii); +writeVideo(v,IM) +imagesc(IM); +end +close(v) + +%% Save Data from aggregate +% Test = TotalX2; +%mov_data = video.frames; +%im_resize = 1; + +% save(save_filename,'test','mov_data','im_resize','-v7.3') +end \ No newline at end of file diff --git a/FastICA_25/.DS_Store b/FastICA_25/.DS_Store new file mode 100644 index 0000000..d9fdef3 Binary files /dev/null and b/FastICA_25/.DS_Store differ diff --git a/FastICA_25/CVS/Entries b/FastICA_25/CVS/Entries new file mode 100644 index 0000000..38977ad --- /dev/null +++ b/FastICA_25/CVS/Entries @@ -0,0 +1,20 @@ +/Contents.m/1.7/Wed Oct 19 13:05:33 2005// +/demosig.m/1.2/Sat Apr 5 14:23:57 2003// +/dispsig.m/1.2/Sat Apr 5 14:23:57 2003// +/fastica.m/1.14/Wed Oct 19 13:05:34 2005// +/fasticag.m/1.5/Wed Oct 19 13:05:34 2005// +/fpica.m/1.7/Thu Jun 16 12:52:55 2005// +/gui_adv.m/1.4/Tue Jul 27 13:09:26 2004// +/gui_advc.m/1.3/Mon Sep 8 11:28:58 2003// +/gui_cb.m/1.5/Wed Sep 10 10:33:41 2003// +/gui_cg.m/1.2/Sat Apr 5 14:23:57 2003// +/gui_help.m/1.6/Wed Oct 19 13:05:34 2005// +/gui_l.m/1.4/Tue Jul 27 13:09:26 2004// +/gui_lc.m/1.4/Thu Sep 11 12:01:19 2003// +/gui_s.m/1.4/Tue Jul 27 13:09:26 2004// +/gui_sc.m/1.3/Mon Sep 8 11:28:59 2003// +/icaplot.m/1.2/Sat Apr 5 14:23:58 2003// +/pcamat.m/1.5/Mon Dec 15 18:24:32 2003// +/remmean.m/1.2/Sat Apr 5 14:23:58 2003// +/whitenv.m/1.3/Sun Oct 12 09:04:43 2003// +D diff --git a/FastICA_25/CVS/Repository b/FastICA_25/CVS/Repository new file mode 100644 index 0000000..92b6bee --- /dev/null +++ b/FastICA_25/CVS/Repository @@ -0,0 +1 @@ +FastICA diff --git a/FastICA_25/CVS/Root b/FastICA_25/CVS/Root new file mode 100644 index 0000000..c2b4f37 --- /dev/null +++ b/FastICA_25/CVS/Root @@ -0,0 +1 @@ +/share/video/cvsroot diff --git a/FastICA_25/Contents.m b/FastICA_25/Contents.m new file mode 100644 index 0000000..fd6853f --- /dev/null +++ b/FastICA_25/Contents.m @@ -0,0 +1,40 @@ +% FastICA for Matlab 7.x and 6.x +% Version 2.5, October 19 2005 +% Copyright (c) Hugo Gävert, Jarmo Hurri, Jaakko Särelä, and Aapo Hyvärinen. +% +% Type fasticag to launch the graphical user interface +% +% Please refer to your Matlab documentation on how to add FastICA to your +% Matlab search path. (One place to start is the path-command) +% +% FastICA programs: +% FASTICAG - Graphical user interface for FastICA +% FASTICA - command line version of FastICA +% +% Separate functions used by FastICA programs. +% FPICA - main algorithm for calculating ICA +% WHITENV - function for whitening data +% PCAMAT - calculates the PCA for data +% REMMEAN - function for removing mean +% +% GUI_CB - needed by fasticag +% GUI_ADV - needed by fasticag +% GUI_ADVC - needed by fasticag +% GUI_L - needed by fasticag +% GUI_LC - needed by fasticag +% GUI_S - needed by fasticag +% GUI_SC - needed by fasticag +% GUI_CG - needed by fasticag +% GUI_HELP - needed by fasticag +% +% ICAPLOT - for plotting the signals +% (also used by fastica and fasticag) +% +% Misc. +% DEMOSIG - generates some test signals +% +% Deprecated +% dispsig - plots the data vectors +% replaced by icaplot + +% @(#)$Id: Contents.m,v 1.7 2005/10/19 13:05:33 jarmo Exp $ \ No newline at end of file diff --git a/FastICA_25/demosig.m b/FastICA_25/demosig.m new file mode 100644 index 0000000..d895063 --- /dev/null +++ b/FastICA_25/demosig.m @@ -0,0 +1,32 @@ +function [sig,mixedsig]=demosig(); +% +% function [sig,mixedsig]=demosig(); +% +% Returns artificially generated test signals, sig, and mixed +% signals, mixedsig. Signals are row vectors of +% matrices. Input mixedsig to FastICA to see how it works. + +% @(#)$Id: demosig.m,v 1.2 2003/04/05 14:23:57 jarmo Exp $ + +%create source signals (independent components) +N=500; %data size + +v=[0:N-1]; +sig=[]; +sig(1,:)=sin(v/2); %sinusoid +sig(2,:)=((rem(v,23)-11)/9).^5; %funny curve +sig(3,:)=((rem(v,27)-13)/9); %saw-tooth +sig(4,:)=((rand(1,N)<.5)*2-1).*log(rand(1,N)); %impulsive noise + +for t=1:4 +sig(t,:)=sig(t,:)/std(sig(t,:)); +end + +%remove mean (not really necessary) + +[sig mean]=remmean(sig); + +%create mixtures + +Aorig=rand(size(sig,1)); +mixedsig=(Aorig*sig); diff --git a/FastICA_25/dispsig.m b/FastICA_25/dispsig.m new file mode 100644 index 0000000..257458b --- /dev/null +++ b/FastICA_25/dispsig.m @@ -0,0 +1,15 @@ +function dispsig(signalMatrix, range, titlestr); +%DISPSIG - deprecated! +% +% Please use icaplot instead. +% +% See also ICAPLOT + +% @(#)$Id: dispsig.m,v 1.2 2003/04/05 14:23:57 jarmo Exp $ + +fprintf('\nNote: DISPSIG is now deprecated! Please use ICAPLOT.\n'); + +if nargin < 3, titlestr = ''; end +if nargin < 2, range = 1:size(signalMatrix, 1); end + +icaplot('dispsig',signalMatrix',0,range,range,titlestr); diff --git a/FastICA_25/fastica.m b/FastICA_25/fastica.m new file mode 100644 index 0000000..886f93f --- /dev/null +++ b/FastICA_25/fastica.m @@ -0,0 +1,519 @@ +function [Out1, Out2, Out3] = fastica(mixedsig, varargin) +%FASTICA - Fast Independent Component Analysis +% +% FastICA for Matlab 7.x and 6.x +% Version 2.5, October 19 2005 +% Copyright (c) Hugo Gävert, Jarmo Hurri, Jaakko Särelä, and Aapo Hyvärinen. +% +% FASTICA(mixedsig) estimates the independent components from given +% multidimensional signals. Each row of matrix mixedsig is one +% observed signal. FASTICA uses Hyvarinen's fixed-point algorithm, +% see http://www.cis.hut.fi/projects/ica/fastica/. Output from the +% function depends on the number output arguments: +% +% [icasig] = FASTICA (mixedsig); the rows of icasig contain the +% estimated independent components. +% +% [icasig, A, W] = FASTICA (mixedsig); outputs the estimated separating +% matrix W and the corresponding mixing matrix A. +% +% [A, W] = FASTICA (mixedsig); gives only the estimated mixing matrix +% A and the separating matrix W. +% +% Some optional arguments induce other output formats, see below. +% +% A graphical user interface for FASTICA can be launched by the +% command FASTICAG +% +% FASTICA can be called with numerous optional arguments. Optional +% arguments are given in parameter pairs, so that first argument is +% the name of the parameter and the next argument is the value for +% that parameter. Optional parameter pairs can be given in any order. +% +% OPTIONAL PARAMETERS: +% +% Parameter name Values and description +% +%====================================================================== +% --Basic parameters in fixed-point algorithm: +% +% 'approach' (string) The decorrelation approach used. Can be +% symmetric ('symm'), i.e. estimate all the +% independent component in parallel, or +% deflation ('defl'), i.e. estimate independent +% component one-by-one like in projection pursuit. +% Default is 'defl'. +% +% 'numOfIC' (integer) Number of independent components to +% be estimated. Default equals the dimension of data. +% +%====================================================================== +% --Choosing the nonlinearity: +% +% 'g' (string) Chooses the nonlinearity g used in +% the fixed-point algorithm. Possible values: +% +% Value of 'g': Nonlinearity used: +% 'pow3' (default) g(u)=u^3 +% 'tanh' g(u)=tanh(a1*u) +% 'gauss g(u)=u*exp(-a2*u^2/2) +% 'skew' g(u)=u^2 +% +% 'finetune' (string) Chooses the nonlinearity g used when +% fine-tuning. In addition to same values +% as for 'g', the possible value 'finetune' is: +% 'off' fine-tuning is disabled. +% +% 'a1' (number) Parameter a1 used when g='tanh'. +% Default is 1. +% 'a2' (number) Parameter a2 used when g='gaus'. +% Default is 1. +% +% 'mu' (number) Step size. Default is 1. +% If the value of mu is other than 1, then the +% program will use the stabilized version of the +% algorithm (see also parameter 'stabilization'). +% +% +% 'stabilization' (string) Values 'on' or 'off'. Default 'off'. +% This parameter controls wether the program uses +% the stabilized version of the algorithm or +% not. If the stabilization is on, then the value +% of mu can momentarily be halved if the program +% senses that the algorithm is stuck between two +% points (this is called a stroke). Also if there +% is no convergence before half of the maximum +% number of iterations has been reached then mu +% will be halved for the rest of the rounds. +% +%====================================================================== +% --Controlling convergence: +% +% 'epsilon' (number) Stopping criterion. Default is 0.0001. +% +% 'maxNumIterations' (integer) Maximum number of iterations. +% Default is 1000. +% +% 'maxFinetune' (integer) Maximum number of iterations in +% fine-tuning. Default 100. +% +% 'sampleSize' (number) [0 - 1] Percentage of samples used in +% one iteration. Samples are chosen in random. +% Default is 1 (all samples). +% +% 'initGuess' (matrix) Initial guess for A. Default is random. +% You can now do a "one more" like this: +% [ica, A, W] = fastica(mix, 'numOfIC',3); +% [ica2, A2, W2] = fastica(mix, 'initGuess', A, 'numOfIC', 4); +% +%====================================================================== +% --Graphics and text output: +% +% 'verbose' (string) Either 'on' or 'off'. Default is +% 'on': report progress of algorithm in text format. +% +% 'displayMode' (string) Plot running estimates of independent +% components: 'signals', 'basis', 'filters' or +% 'off'. Default is 'off'. +% +% 'displayInterval' Number of iterations between plots. +% Default is 1 (plot after every iteration). +% +%====================================================================== +% --Controlling reduction of dimension and whitening: +% +% Reduction of dimension is controlled by 'firstEig' and 'lastEig', or +% alternatively by 'interactivePCA'. +% +% 'firstEig' (integer) This and 'lastEig' specify the range for +% eigenvalues that are retained, 'firstEig' is +% the index of largest eigenvalue to be +% retained. Default is 1. +% +% 'lastEig' (integer) This is the index of the last (smallest) +% eigenvalue to be retained. Default equals the +% dimension of data. +% +% 'interactivePCA' (string) Either 'on' or 'off'. When set 'on', the +% eigenvalues are shown to the user and the +% range can be specified interactively. Default +% is 'off'. Can also be set to 'gui'. Then the user +% can use the same GUI that's in FASTICAG. +% +% If you already know the eigenvalue decomposition of the covariance +% matrix, you can avoid computing it again by giving it with the +% following options: +% +% 'pcaE' (matrix) Eigenvectors +% 'pcaD' (matrix) Eigenvalues +% +% If you already know the whitened data, you can give it directly to +% the algorithm using the following options: +% +% 'whiteSig' (matrix) Whitened signal +% 'whiteMat' (matrix) Whitening matrix +% 'dewhiteMat' (matrix) dewhitening matrix +% +% If values for all the 'whiteSig', 'whiteSig' and 'dewhiteMat' are +% supplied, they will be used in computing the ICA. PCA and whitening +% are not performed. Though 'mixedsig' is not used in the main +% algorithm it still must be entered - some values are still +% calculated from it. +% +% Performing preprocessing only is possible by the option: +% +% 'only' (string) Compute only PCA i.e. reduction of +% dimension ('pca') or only PCA plus whitening +% ('white'). Default is 'all': do ICA estimation +% as well. This option changes the output +% format accordingly. For example: +% +% [whitesig, WM, DWM] = FASTICA(mixedsig, +% 'only', 'white') +% returns the whitened signals, the whitening matrix +% (WM) and the dewhitening matrix (DWM). (See also +% WHITENV.) In FastICA the whitening matrix performs +% whitening and the reduction of dimension. Dewhitening +% matrix is the pseudoinverse of whitening matrix. +% +% [E, D] = FASTICA(mixedsig, 'only', 'pca') +% returns the eigenvector (E) and diagonal +% eigenvalue (D) matrices containing the +% selected subspaces. +% +%====================================================================== +% EXAMPLES +% +% [icasig] = FASTICA (mixedsig, 'approach', 'symm', 'g', 'tanh'); +% Do ICA with tanh nonlinearity and in parallel (like +% maximum likelihood estimation for supergaussian data). +% +% [icasig] = FASTICA (mixedsig, 'lastEig', 10, 'numOfIC', 3); +% Reduce dimension to 10, and estimate only 3 +% independent components. +% +% [icasig] = FASTICA (mixedsig, 'verbose', 'off', 'displayMode', 'off'); +% Don't output convergence reports and don't plot +% independent components. +% +% +% A graphical user interface for FASTICA can be launched by the +% command FASTICAG +% +% See also FASTICAG + +% @(#)$Id: fastica.m,v 1.14 2005/10/19 13:05:34 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Check some basic requirements of the data +if nargin == 0, + error ('You must supply the mixed data as input argument.'); +end + +if length (size (mixedsig)) > 2, + error ('Input data can not have more than two dimensions.'); +end + +if any (any (isnan (mixedsig))), + error ('Input data contains NaN''s.'); +end + +if ~isa (mixedsig, 'double') + fprintf ('Warning: converting input data into regular (double) precision.\n'); + mixedsig = double (mixedsig); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Remove the mean and check the data + +[mixedsig, mixedmean] = remmean(mixedsig); + +[Dim, NumOfSampl] = size(mixedsig); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Default values for optional parameters + +% All +verbose = 'on'; + +% Default values for 'pcamat' parameters +firstEig = 1; +lastEig = Dim; +interactivePCA = 'off'; + +% Default values for 'fpica' parameters +approach = 'defl'; +numOfIC = Dim; +g = 'pow3'; +finetune = 'off'; +a1 = 1; +a2 = 1; +myy = 1; +stabilization = 'off'; +epsilon = 0.0001; +maxNumIterations = 1000; +maxFinetune = 5; +initState = 'rand'; +guess = 0; +sampleSize = 1; +displayMode = 'off'; +displayInterval = 1; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Parameters for fastICA - i.e. this file + +b_verbose = 1; +jumpPCA = 0; +jumpWhitening = 0; +only = 3; +userNumOfIC = 0; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Read the optional parameters + +if (rem(length(varargin),2)==1) + error('Optional parameters should always go by pairs'); +else + for i=1:2:(length(varargin)-1) + if ~ischar (varargin{i}), + error (['Unknown type of optional parameter name (parameter' ... + ' names must be strings).']); + end + % change the value of parameter + switch lower (varargin{i}) + case 'stabilization' + stabilization = lower (varargin{i+1}); + case 'maxfinetune' + maxFinetune = varargin{i+1}; + case 'samplesize' + sampleSize = varargin{i+1}; + case 'verbose' + verbose = lower (varargin{i+1}); + % silence this program also + if strcmp (verbose, 'off'), b_verbose = 0; end + case 'firsteig' + firstEig = varargin{i+1}; + case 'lasteig' + lastEig = varargin{i+1}; + case 'interactivepca' + interactivePCA = lower (varargin{i+1}); + case 'approach' + approach = lower (varargin{i+1}); + case 'numofic' + numOfIC = varargin{i+1}; + % User has supplied new value for numOfIC. + % We'll use this information later on... + userNumOfIC = 1; + case 'g' + g = lower (varargin{i+1}); + case 'finetune' + finetune = lower (varargin{i+1}); + case 'a1' + a1 = varargin{i+1}; + case 'a2' + a2 = varargin{i+1}; + case {'mu', 'myy'} + myy = varargin{i+1}; + case 'epsilon' + epsilon = varargin{i+1}; + case 'maxnumiterations' + maxNumIterations = varargin{i+1}; + case 'initguess' + % no use setting 'guess' if the 'initState' is not set + initState = 'guess'; + guess = varargin{i+1}; + case 'displaymode' + displayMode = lower (varargin{i+1}); + case 'displayinterval' + displayInterval = varargin{i+1}; + case 'pcae' + % calculate if there are enought parameters to skip PCA + jumpPCA = jumpPCA + 1; + E = varargin{i+1}; + case 'pcad' + % calculate if there are enought parameters to skip PCA + jumpPCA = jumpPCA + 1; + D = varargin{i+1}; + case 'whitesig' + % calculate if there are enought parameters to skip PCA and whitening + jumpWhitening = jumpWhitening + 1; + whitesig = varargin{i+1}; + case 'whitemat' + % calculate if there are enought parameters to skip PCA and whitening + jumpWhitening = jumpWhitening + 1; + whiteningMatrix = varargin{i+1}; + case 'dewhitemat' + % calculate if there are enought parameters to skip PCA and whitening + jumpWhitening = jumpWhitening + 1; + dewhiteningMatrix = varargin{i+1}; + case 'only' + % if the user only wants to calculate PCA or... + switch lower (varargin{i+1}) + case 'pca' + only = 1; + case 'white' + only = 2; + case 'all' + only = 3; + end + + otherwise + % Hmmm, something wrong with the parameter string + error(['Unrecognized parameter: ''' varargin{i} '''']); + end; + end; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% print information about data +if b_verbose + fprintf('Number of signals: %d\n', Dim); + fprintf('Number of samples: %d\n', NumOfSampl); +end + +% Check if the data has been entered the wrong way, +% but warn only... it may be on purpose + +if Dim > NumOfSampl + if b_verbose + fprintf('Warning: '); + fprintf('The signal matrix may be oriented in the wrong way.\n'); + fprintf('In that case transpose the matrix.\n\n'); + end +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Calculating PCA + +% We need the results of PCA for whitening, but if we don't +% need to do whitening... then we dont need PCA... +if jumpWhitening == 3 + if b_verbose, + fprintf ('Whitened signal and corresponding matrises supplied.\n'); + fprintf ('PCA calculations not needed.\n'); + end; +else + + % OK, so first we need to calculate PCA + % Check to see if we already have the PCA data + if jumpPCA == 2, + if b_verbose, + fprintf ('Values for PCA calculations supplied.\n'); + fprintf ('PCA calculations not needed.\n'); + end; + else + % display notice if the user entered one, but not both, of E and D. + if (jumpPCA > 0) & (b_verbose), + fprintf ('You must suply all of these in order to jump PCA:\n'); + fprintf ('''pcaE'', ''pcaD''.\n'); + end; + + % Calculate PCA + [E, D]=pcamat(mixedsig, firstEig, lastEig, interactivePCA, verbose); + end +end + +% skip the rest if user only wanted PCA +if only > 1 + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Whitening the data + + % Check to see if the whitening is needed... + if jumpWhitening == 3, + if b_verbose, + fprintf ('Whitening not needed.\n'); + end; + else + + % Whitening is needed + % display notice if the user entered some of the whitening info, but not all. + if (jumpWhitening > 0) & (b_verbose), + fprintf ('You must suply all of these in order to jump whitening:\n'); + fprintf ('''whiteSig'', ''whiteMat'', ''dewhiteMat''.\n'); + end; + + % Calculate the whitening + [whitesig, whiteningMatrix, dewhiteningMatrix] = whitenv ... + (mixedsig, E, D, verbose); + end + +end % if only > 1 + +% skip the rest if user only wanted PCA and whitening +if only > 2 + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Calculating the ICA + + % Check some parameters + % The dimension of the data may have been reduced during PCA calculations. + % The original dimension is calculated from the data by default, and the + % number of IC is by default set to equal that dimension. + + Dim = size(whitesig, 1); + + % The number of IC's must be less or equal to the dimension of data + if numOfIC > Dim + numOfIC = Dim; + % Show warning only if verbose = 'on' and user supplied a value for 'numOfIC' + if (b_verbose & userNumOfIC) + fprintf('Warning: estimating only %d independent components\n', numOfIC); + fprintf('(Can''t estimate more independent components than dimension of data)\n'); + end + end + + % Calculate the ICA with fixed point algorithm. + [A, W] = fpica (whitesig, whiteningMatrix, dewhiteningMatrix, approach, ... + numOfIC, g, finetune, a1, a2, myy, stabilization, epsilon, ... + maxNumIterations, maxFinetune, initState, guess, sampleSize, ... + displayMode, displayInterval, verbose); + + % Check for valid return + if ~isempty(W) + % Add the mean back in. + if b_verbose + fprintf('Adding the mean back to the data.\n'); + end + icasig = W * mixedsig + (W * mixedmean) * ones(1, NumOfSampl); + %icasig = W * mixedsig; + if b_verbose & ... + (max(abs(W * mixedmean)) > 1e-9) & ... + (strcmp(displayMode,'signals') | strcmp(displayMode,'on')) + fprintf('Note that the plots don''t have the mean added.\n'); + end + else + icasig = []; + end + +end % if only > 2 + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% The output depends on the number of output parameters +% and the 'only' parameter. + +if only == 1 % only PCA + Out1 = E; + Out2 = D; +elseif only == 2 % only PCA & whitening + if nargout == 2 + Out1 = whiteningMatrix; + Out2 = dewhiteningMatrix; + else + Out1 = whitesig; + Out2 = whiteningMatrix; + Out3 = dewhiteningMatrix; + end +else % ICA + if nargout == 2 + Out1 = A; + Out2 = W; + else + Out1 = icasig; + Out2 = A; + Out3 = W; + end +end diff --git a/FastICA_25/fasticag.m b/FastICA_25/fasticag.m new file mode 100644 index 0000000..cf63ac1 --- /dev/null +++ b/FastICA_25/fasticag.m @@ -0,0 +1,667 @@ +function fasticag(mixedsig, InitialGuess) +%FASTICAG - Fast Independent Component Analysis, the Graphical User Interface +% +% FASTICAG gives a graphical user interface for performing independent +% component analysis by the FastICA package. No arguments are +% necessary in the function call. +% +% Optional arguments can be given in the form: +% FASTICAG(mixedsig, initialGuess) where the matrix mixedsig contains the +% multidimensional signals as row vectors, and initialGuess gives the +% initial value for the mixing matrix used in the algorithm. +% +% FASTICA uses the fixed-point algorithm developed by Aapo Hyvarinen, +% see http://www.cis.hut.fi/projects/ica/fastica/. The Matlab package +% was programmed by Hugo Gavert, Jarmo Hurri, Jaakko Sarela, and Aapo +% Hyvarinen. +% +% +% See also FASTICA + +% @(#)$Id: fasticag.m,v 1.5 2005/10/19 13:05:34 jarmo Exp $ + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Global values + +% Handle to this main figure +global hf_FastICA_MAIN; + +% Check to see if GUI is already running +% Can't have more than one copy - otherwise the global +% variables and handles can get mixed up. +if ~isempty(hf_FastICA_MAIN) + error('FastICA GUI already running!'); +end + + +% Handles to other controls in this main window +global ht_FastICA_mixedStatus; +global ht_FastICA_dim; +global ht_FastICA_numOfSamp; +global ht_FastICA_newDim; +global ht_FastICA_whiteStatus; +global ht_FastICA_icaStatus; +global hpm_FastICA_approach; +global he_FastICA_numOfIC; +global hpm_FastICA_g; +global hpm_FastICA_stabilization; + +% These global variables are used to store all the values +% I used to use the 'UserData' field of components, but +% that got too complex, so I decided to put everything +% in global variables +global g_FastICA_mixedsig; +global g_FastICA_pca_D; +global g_FastICA_pca_E; +global g_FastICA_white_sig; +global g_FastICA_white_wm; +global g_FastICA_white_dwm; +global g_FastICA_ica_sig; +global g_FastICA_ica_A; +global g_FastICA_ica_W; +global g_FastICA_initGuess; +global g_FastICA_approach; +global g_FastICA_numOfIC; +global g_FastICA_g; +global g_FastICA_finetune; +global g_FastICA_a1; +global g_FastICA_a2; +global g_FastICA_myy; +global g_FastICA_stabilization; +global g_FastICA_epsilon; +global g_FastICA_maxNumIte; +global g_FastICA_maxFinetune; +global g_FastICA_sampleSize; +global g_FastICA_initState; +global g_FastICA_displayMo; +global g_FastICA_displayIn; +global g_FastICA_verbose; + +% initial values for them: +% All the initial values are set here - even for +% variables that are not used in this file + +if nargin < 2 + g_FastICA_initGuess = 1; + % The user didn't enter initial guess so we default + % back to random initial state. + g_FastICA_initState = 1; % see below for string values +else + g_FastICA_initGuess = InitialGuess; + % If initial guess was entered, then the user probably + % wan't to use it, eh? + g_FastICA_initState = 2; % see below for string values +end + +if nargin < 1 + g_FastICA_mixedsig = []; +else + g_FastICA_mixedsig = mixedsig; % We'll remove mean +end % the first time we + % use this. + +% Global variable for stopping the ICA calculations +global g_FastICA_interrupt; + +g_FastICA_pca_D = []; +g_FastICA_pca_E = []; +g_FastICA_white_sig = []; +g_FastICA_white_wm = []; +g_FastICA_white_dwm = []; +g_FastICA_ica_sig = []; +g_FastICA_ica_A = []; +g_FastICA_ica_W = []; +g_FastICA_approach = 1; % see below for string values +g_FastICA_numOfIC = 0; +g_FastICA_g = 1; % see below for string values +g_FastICA_finetune = 5; % see below for string values +g_FastICA_a1 = 1; +g_FastICA_a2 = 1; +g_FastICA_myy = 1; +g_FastICA_stabilization = 2; % see below for string values +g_FastICA_epsilon = 0.0001; +g_FastICA_maxNumIte = 1000; +g_FastICA_maxFinetune = 100; +g_FastICA_sampleSize = 1; +g_FastICA_displayMo = 1; % see below for string values +g_FastICA_displayIn = 1; +g_FastICA_verbose = 1; % see below for string values + +% These are regarded as constants and are used to store +% the strings for the popup menus the current value is +% seen in the variables above +% D - refers to strings that are displayed +% V - refers to string values that are used in FPICA +global c_FastICA_appr_strD; +global c_FastICA_appr_strV; +global c_FastICA_g1_strD; +global c_FastICA_g1_strV; +global c_FastICA_g2_strD; +global c_FastICA_g2_strV; +global c_FastICA_finetune_strD; +global c_FastICA_finetune_strV; +global c_FastICA_stabili_strD; +global c_FastICA_stabili_strV; +global c_FastICA_iSta_strD; +global c_FastICA_iSta_strV; +global c_FastICA_dMod_strD; +global c_FastICA_dMod_strV; +global c_FastICA_verb_strD; +global c_FastICA_verb_strV; + +% All the values for these are set here - even for +% variables that are not used in this file + +c_FastICA_appr_strD = 'deflation|symmetric'; +c_FastICA_appr_strV = ['defl';'symm']; +% The 'g1' and 'g2' below correspond to the values of approach (1 or 2) +% Deflation and Symmetric used to have a bit different selection +% of available nonlinearities. +c_FastICA_g1_strD = 'pow3|tanh|gauss|skew'; +c_FastICA_g1_strV = ['pow3';'tanh';'gaus';'skew']; +c_FastICA_g2_strD = 'pow3|tanh|gauss|skew'; +c_FastICA_g2_strV = ['pow3';'tanh';'gaus';'skew']; +c_FastICA_finetune_strD = 'pow3|tanh|gauss|skew|off'; +c_FastICA_finetune_strV = ['pow3';'tanh';'gaus';'skew';'off ']; +c_FastICA_stabili_strD = 'on|off'; +c_FastICA_stabili_strV = ['on ';'off']; +c_FastICA_iSta_strD = 'random|guess'; +c_FastICA_iSta_strV = ['rand ';'guess']; +c_FastICA_dMod_strD = 'signals|basis|filters|off'; +c_FastICA_dMod_strV = ['signals';'basis ';'filters';'off ']; +c_FastICA_verb_strD = 'on|off'; +c_FastICA_verb_strV = ['on ';'off']; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Configuration options +FIGURENAME = 'FastICA'; +FIGURETAG = 'f_FastICA'; +SCREENSIZE = get(0,'ScreenSize'); +FIGURESIZE = [round(0.1*SCREENSIZE(3)) (SCREENSIZE(4)-round(0.1*SCREENSIZE(4))-370) 530 370]; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Create the figure +a = figure('Color',[0.8 0.8 0.8], ... + 'PaperType','a4letter', ... + 'Name', FIGURENAME, ... + 'NumberTitle', 'off', ... + 'Tag', FIGURETAG, ... + 'Position', FIGURESIZE, ... + 'MenuBar', 'none'); +% Resizing has to be denied after the window has been created - +% otherwise the window shows only as a tiny window in Windows XP. +set (a, 'Resize', 'off'); + +hf_FastICA_MAIN = a; + +set(hf_FastICA_MAIN, 'HandleVisibility', 'callback'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% From here on it get's ugly as I have not had time to clean it up + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Create the frames +pos_l=2; +pos_w=FIGURESIZE(3)-4; +pos_h=FIGURESIZE(4)-4; +pos_t=FIGURESIZE(4)-2-pos_h; +h_f_background = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_background'); + +pos_l=4; +pos_w=400; +pos_h=106; +pos_t=FIGURESIZE(4)-4-pos_h; +h_f_mixed = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_mixed'); + +pos_h=90; +pos_t=FIGURESIZE(4)-(106+4+2)-pos_h; +h_f_white = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_white'); + +pos_h=pos_t - 4 - 2; +pos_t=4; +h_f_ica = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_ica'); + +pos_w=120; +pos_l=FIGURESIZE(3)-(pos_w+2+2); +pos_h=FIGURESIZE(4)-2*4; +pos_t=FIGURESIZE(4)-(4)-pos_h; +h_f_side = uicontrol('Parent',a, ... + 'BackgroundColor',[0.5 0.5 0.5], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_side'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Controls in f_mixed +bgc = get(h_f_mixed, 'BackgroundColor'); + +pos_vspace = 6; +pos_hspace = 6; + +pos_frame=get(h_f_mixed, 'Position'); +pos_l = pos_frame(1) + 6; +pos_h = 16; +pos_t = pos_frame(2) + pos_frame(4) - pos_h - 6; +pos_w = 150; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Mixed signals:', ... + 'FontWeight', 'bold', ... + 'Style','text', ... + 'Tag','t_mixed'); + +pos_l = pos_l + pos_w; +pos_w = 120; +ht_FastICA_mixedStatus = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Not loaded yet', ... + 'Style','text', ... + 'Tag','t_mixedstatus'); + +% Vähän väliä +pos_t = pos_t - 8; + +pos_l = pos_frame(1) + 6; +pos_t = pos_t - pos_h; +pos_w = 150; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Number of signals:', ... + 'Style','text', ... + 'Tag','t_2'); + +pos_l = pos_l + pos_w; +pos_w = 50; +ht_FastICA_dim = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','', ... + 'Style','text', ... + 'Tag','t_dim'); + +pos_l = pos_frame(1) + 6; +pos_t = pos_t - pos_h; +pos_w = 150; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Number of samples:', ... + 'Style','text', ... + 'Tag','t_3'); + +pos_l = pos_l + pos_w; +pos_w = 50; +ht_FastICA_numOfSamp = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','', ... + 'Style','text', ... + 'Tag','t_numOfSamp'); + + +% Buttons +pos_l = pos_frame(1) + pos_hspace; +pos_w = 110; +pos_h = 30; +pos_t = pos_frame(2) + pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb Transpose', ... + 'Interruptible', 'off', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Transpose', ... + 'Tag','b_Transpose'); + +pos_w = 130; +pos_l = pos_frame(1) + pos_frame(3) - pos_hspace - pos_w; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb ShowMixed', ... + 'Interruptible', 'off', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Plot data', ... + 'Tag','b_ShowMixed'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Controls in f_white +pos_frame=get(h_f_white, 'Position'); +pos_l = pos_frame(1) + 6; +pos_h = 16; +pos_t = pos_frame(2) + pos_frame(4) - pos_h - 6; +pos_w = 150; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Dimension control:', ... + 'FontWeight', 'bold', ... + 'Style','text', ... + 'Tag','t_white'); + +pos_l = pos_l + pos_w; +pos_w = 120; +ht_FastICA_whiteStatus = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','', ... + 'Style','text', ... + 'Tag','t_whiteStatus'); + +% Vähän väliä +pos_t = pos_t - 8; + +pos_l = pos_frame(1) + 6; +pos_t = pos_t - pos_h; +pos_w = 150; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Reduced dimension:', ... + 'Style','text', ... + 'Tag','t_4'); + +pos_l = pos_l + pos_w; +pos_w = 50; +ht_FastICA_newDim = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','', ... + 'Style','text', ... + 'Tag','t_newDim'); + + +% buttons + +pos_l = pos_frame(1) + pos_hspace; +pos_w = 110; +pos_h = 30; +pos_t = pos_frame(2) + pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb DoPCA', ... + 'Interruptible', 'off', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Reduce dim.', ... + 'Tag','b_DoPCA'); + +pos_l = pos_l + pos_w + pos_hspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb OrigDim', ... + 'Interruptible', 'off', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Original dim.', ... + 'Tag','b_OrigDim'); + +pos_w = 130; +pos_h = 30; +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w; +pos_t = pos_frame(2) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb ShowWhite', ... + 'Interruptible', 'off', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Plot whitened', ... + 'Tag','b_ShowWhite'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Controls in f_ica +pos_frame=get(h_f_ica, 'Position'); +pos_l = pos_frame(1) + 6; +pos_h = 20; +pos_t = pos_frame(2) + pos_frame(4) - pos_h - 6; +pos_w = 150; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Fixed point ICA:', ... + 'FontWeight', 'bold', ... + 'Style','text', ... + 'Tag','t_white'); + +pos_l = pos_l + pos_w; +pos_w = 120; +ht_FastICA_icaStatus = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Not yet done', ... + 'Style','text', ... + 'Tag','t_icaStatus'); + +% Vähän väliä +pos_t = pos_t - 8; + +%pos_l = pos_frame(1) + 6; +pos_l = pos_frame(1) + 6 + 150; +pos_t = pos_t - pos_h; +%pos_w = 260; +pos_w = 120; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Approach:', ... + 'Style','text', ... + 'Tag','t_5'); + +pos_w = 100; +%pos_t = pos_t - 4; +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w; +hpm_FastICA_approach = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'Callback','gui_cb ChangeApproach', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String',c_FastICA_appr_strD, ... + 'Style','popupmenu', ... + 'Tag','pm_approach', ... + 'Value',g_FastICA_approach); + +%pos_t = pos_t - 4; +%pos_l = pos_frame(1) + 6; +pos_l = pos_frame(1) + 6 + 150; +pos_t = pos_t - pos_h; +%pos_w = 260; +pos_w = 120; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Number of ICs:', ... + 'Style','text', ... + 'Tag','t_6'); + +pos_w = 100; +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w; +he_FastICA_numOfIC = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'Callback','gui_cb ChangeNumOfIC', ... + 'HorizontalAlignment','right', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','0', ... + 'Style','edit', ... + 'Tag','e_numOfIC'); + +%pos_t = pos_t - 4; +%pos_l = pos_frame(1) + 6; +pos_l = pos_frame(1) + 6 + 150; +pos_t = pos_t - pos_h; +%pos_w = 260; +pos_w = 120; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Nonlinearity (g):', ... + 'Style','text', ... + 'Tag','t_71'); + +%pos_t = pos_t - 4; +pos_w = 100; +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w; +hpm_FastICA_g = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'Callback','gui_cb ChangeG', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String',c_FastICA_g1_strD, ... + 'Style','popupmenu', ... + 'Tag','pm_g', ... + 'Value',g_FastICA_g); + +%pos_t = pos_t - 4; +%pos_l = pos_frame(1) + 6; +pos_l = pos_frame(1) + 6 + 150; +pos_t = pos_t - pos_h; +%pos_w = 260; +pos_w = 120; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Stabilization:', ... + 'Style','text', ... + 'Tag','t_71a'); + +%pos_t = pos_t - 4; +pos_w = 100; +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w; +hpm_FastICA_stabilization = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'Callback','gui_cb ChangeStab', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String',c_FastICA_stabili_strD, ... + 'Style','popupmenu', ... + 'Tag','pm_stab', ... + 'Value',g_FastICA_stabilization); + + + +pos_l = pos_frame(1) + pos_vspace; +pos_w = 110; +pos_h = 30; +pos_t = pos_frame(2) + pos_hspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb AdvOpt', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Adv. options >>', ... + 'Tag','b_advOpt'); + +pos_w = 130; +pos_h = 30; +pos_l = pos_frame(1) + pos_frame(3) - pos_vspace - pos_w; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb ShowICASig', ... + 'Interruptible', 'on', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Plot ICs', ... + 'Tag','b_ShowICASig'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Controls in f_side +pos_vspace = 6; +pos_hspace = 10; +pos_temp=get(h_f_side, 'Position'); +pos_l=pos_temp(1)+pos_hspace; +pos_w=100; +pos_h=30; +pos_t=pos_temp(2)+pos_temp(4)-pos_vspace-pos_h; + +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb LoadData', ... + 'Interruptible', 'off', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Load data', ... + 'Tag','b_LoadData'); + + +pos_t=pos_t-pos_h-pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb DoFPICA', ... + 'Interruptible', 'on', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Do ICA', ... + 'Tag','b_DoFPICA'); + +pos_t=pos_t-pos_h-pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb SaveData', ... + 'Interruptible', 'off', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Save results', ... + 'Tag','b_SaveData'); + +pos_t=pos_t-pos_h-pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb Quit', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Quit', ... + 'Tag','b_Quit'); + +pos_t=pos_t-pos_h-pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb Interrupt', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Interrupt', ... + 'Visible','off', ... + 'Tag','b_Interrupt'); + +pos_t = pos_frame(2) + pos_vspace + pos_h + pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb About', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','About...', ... + 'Tag','b_About'); + +pos_t = pos_frame(2) + pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_cb Help', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Help', ... + 'Tag','b_Help'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Do rest of the initialization... + gui_cb InitAll; + diff --git a/FastICA_25/fpica.m b/FastICA_25/fpica.m new file mode 100644 index 0000000..325b601 --- /dev/null +++ b/FastICA_25/fpica.m @@ -0,0 +1,905 @@ +function [A, W] = fpica(X, whiteningMatrix, dewhiteningMatrix, approach, ... + numOfIC, g, finetune, a1, a2, myy, stabilization, ... + epsilon, maxNumIterations, maxFinetune, initState, ... + guess, sampleSize, displayMode, displayInterval, ... + s_verbose); +%FPICA - Fixed point ICA. Main algorithm of FASTICA. +% +% [A, W] = fpica(whitesig, whiteningMatrix, dewhiteningMatrix, approach, +% numOfIC, g, finetune, a1, a2, mu, stabilization, epsilon, +% maxNumIterations, maxFinetune, initState, guess, sampleSize, +% displayMode, displayInterval, verbose); +% +% Perform independent component analysis using Hyvarinen's fixed point +% algorithm. Outputs an estimate of the mixing matrix A and its inverse W. +% +% whitesig :the whitened data as row vectors +% whiteningMatrix :can be obtained with function whitenv +% dewhiteningMatrix :can be obtained with function whitenv +% approach [ 'symm' | 'defl' ] :the approach used (deflation or symmetric) +% numOfIC [ 0 - Dim of whitesig ] :number of independent components estimated +% g [ 'pow3' | 'tanh' | :the nonlinearity used +% 'gaus' | 'skew' ] +% finetune [same as g + 'off'] :the nonlinearity used in finetuning. +% a1 :parameter for tuning 'tanh' +% a2 :parameter for tuning 'gaus' +% mu :step size in stabilized algorithm +% stabilization [ 'on' | 'off' ] :if mu < 1 then automatically on +% epsilon :stopping criterion +% maxNumIterations :maximum number of iterations +% maxFinetune :maximum number of iteretions for finetuning +% initState [ 'rand' | 'guess' ] :initial guess or random initial state. See below +% guess :initial guess for A. Ignored if initState = 'rand' +% sampleSize [ 0 - 1 ] :percentage of the samples used in one iteration +% displayMode [ 'signals' | 'basis' | :plot running estimate +% 'filters' | 'off' ] +% displayInterval :number of iterations we take between plots +% verbose [ 'on' | 'off' ] :report progress in text format +% +% EXAMPLE +% [E, D] = pcamat(vectors); +% [nv, wm, dwm] = whitenv(vectors, E, D); +% [A, W] = fpica(nv, wm, dwm); +% +% +% This function is needed by FASTICA and FASTICAG +% +% See also FASTICA, FASTICAG, WHITENV, PCAMAT + +% @(#)$Id: fpica.m,v 1.7 2005/06/16 12:52:55 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Global variable for stopping the ICA calculations from the GUI +global g_FastICA_interrupt; +if isempty(g_FastICA_interrupt) + clear global g_FastICA_interrupt; + interruptible = 0; +else + interruptible = 1; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Default values + +if nargin < 3, error('Not enough arguments!'); end +[vectorSize, numSamples] = size(X); +if nargin < 20, s_verbose = 'on'; end +if nargin < 19, displayInterval = 1; end +if nargin < 18, displayMode = 'on'; end +if nargin < 17, sampleSize = 1; end +if nargin < 16, guess = 1; end +if nargin < 15, initState = 'rand'; end +if nargin < 14, maxFinetune = 100; end +if nargin < 13, maxNumIterations = 1000; end +if nargin < 12, epsilon = 0.0001; end +if nargin < 11, stabilization = 'on'; end +if nargin < 10, myy = 1; end +if nargin < 9, a2 = 1; end +if nargin < 8, a1 = 1; end +if nargin < 7, finetune = 'off'; end +if nargin < 6, g = 'pow3'; end +if nargin < 5, numOfIC = vectorSize; end % vectorSize = Dim +if nargin < 4, approach = 'defl'; end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Checking the data + +if ~isreal(X) + error('Input has an imaginary part.'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Checking the value for verbose + +switch lower(s_verbose) + case 'on' + b_verbose = 1; + case 'off' + b_verbose = 0; + otherwise + error(sprintf('Illegal value [ %s ] for parameter: ''verbose''\n', s_verbose)); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Checking the value for approach + +switch lower(approach) + case 'symm' + approachMode = 1; + case 'defl' + approachMode = 2; + otherwise + error(sprintf('Illegal value [ %s ] for parameter: ''approach''\n', approach)); +end +if b_verbose, fprintf('Used approach [ %s ].\n', approach); end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Checking the value for numOfIC + +if vectorSize < numOfIC + error('Must have numOfIC <= Dimension!'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Checking the sampleSize +if sampleSize > 1 + sampleSize = 1; + if b_verbose + fprintf('Warning: Setting ''sampleSize'' to 1.\n'); + end +elseif sampleSize < 1 + if (sampleSize * numSamples) < 1000 + sampleSize = min(1000/numSamples, 1); + if b_verbose + fprintf('Warning: Setting ''sampleSize'' to %0.3f (%d samples).\n', ... + sampleSize, floor(sampleSize * numSamples)); + end + end +end +if b_verbose + if b_verbose & (sampleSize < 1) + fprintf('Using about %0.0f%% of the samples in random order in every step.\n',sampleSize*100); + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Checking the value for nonlinearity. + +switch lower(g) + case 'pow3' + gOrig = 10; + case 'tanh' + gOrig = 20; + case {'gaus', 'gauss'} + gOrig = 30; + case 'skew' + gOrig = 40; + otherwise + error(sprintf('Illegal value [ %s ] for parameter: ''g''\n', g)); +end +if sampleSize ~= 1 + gOrig = gOrig + 2; +end +if myy ~= 1 + gOrig = gOrig + 1; +end + +if b_verbose, + fprintf('Used nonlinearity [ %s ].\n', g); +end + +finetuningEnabled = 1; +switch lower(finetune) + case 'pow3' + gFine = 10 + 1; + case 'tanh' + gFine = 20 + 1; + case {'gaus', 'gauss'} + gFine = 30 + 1; + case 'skew' + gFine = 40 + 1; + case 'off' + if myy ~= 1 + gFine = gOrig; + else + gFine = gOrig + 1; + end + finetuningEnabled = 0; + otherwise + error(sprintf('Illegal value [ %s ] for parameter: ''finetune''\n', ... + finetune)); +end + +if b_verbose & finetuningEnabled + fprintf('Finetuning enabled (nonlinearity: [ %s ]).\n', finetune); +end + +switch lower(stabilization) + case 'on' + stabilizationEnabled = 1; + case 'off' + if myy ~= 1 + stabilizationEnabled = 1; + else + stabilizationEnabled = 0; + end + otherwise + error(sprintf('Illegal value [ %s ] for parameter: ''stabilization''\n', ... + stabilization)); +end + +if b_verbose & stabilizationEnabled + fprintf('Using stabilized algorithm.\n'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Some other parameters +myyOrig = myy; +% When we start fine-tuning we'll set myy = myyK * myy +myyK = 0.01; +% How many times do we try for convergence until we give up. +failureLimit = 5; + + +usedNlinearity = gOrig; +stroke = 0; +notFine = 1; +long = 0; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Checking the value for initial state. + +switch lower(initState) + case 'rand' + initialStateMode = 0; + case 'guess' + if size(guess,1) ~= size(whiteningMatrix,2) + initialStateMode = 0; + if b_verbose + fprintf('Warning: size of initial guess is incorrect. Using random initial guess.\n'); + end + else + initialStateMode = 1; + if size(guess,2) < numOfIC + if b_verbose + fprintf('Warning: initial guess only for first %d components. Using random initial guess for others.\n', size(guess,2)); + end + guess(:, size(guess, 2) + 1:numOfIC) = ... + rand(vectorSize,numOfIC-size(guess,2))-.5; + elseif size(guess,2)>numOfIC + guess=guess(:,1:numOfIC); + fprintf('Warning: Initial guess too large. The excess column are dropped.\n'); + end + if b_verbose, fprintf('Using initial guess.\n'); end + end + otherwise + error(sprintf('Illegal value [ %s ] for parameter: ''initState''\n', initState)); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Checking the value for display mode. + +switch lower(displayMode) + case {'off', 'none'} + usedDisplay = 0; + case {'on', 'signals'} + usedDisplay = 1; + if (b_verbose & (numSamples > 10000)) + fprintf('Warning: Data vectors are very long. Plotting may take long time.\n'); + end + if (b_verbose & (numOfIC > 25)) + fprintf('Warning: There are too many signals to plot. Plot may not look good.\n'); + end + case 'basis' + usedDisplay = 2; + if (b_verbose & (numOfIC > 25)) + fprintf('Warning: There are too many signals to plot. Plot may not look good.\n'); + end + case 'filters' + usedDisplay = 3; + if (b_verbose & (vectorSize > 25)) + fprintf('Warning: There are too many signals to plot. Plot may not look good.\n'); + end + otherwise + error(sprintf('Illegal value [ %s ] for parameter: ''displayMode''\n', displayMode)); +end + +% The displayInterval can't be less than 1... +if displayInterval < 1 + displayInterval = 1; +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +if b_verbose, fprintf('Starting ICA calculation...\n'); end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% SYMMETRIC APPROACH +if approachMode == 1, + + % set some parameters more... + usedNlinearity = gOrig; + stroke = 0; + notFine = 1; + long = 0; + + A = zeros(vectorSize, numOfIC); % Dewhitened basis vectors. + if initialStateMode == 0 + % Take random orthonormal initial vectors. + B = orth (randn (vectorSize, numOfIC)); + elseif initialStateMode == 1 + % Use the given initial vector as the initial state + B = whiteningMatrix * guess; + end + + BOld = zeros(size(B)); + BOld2 = zeros(size(B)); + + % This is the actual fixed-point iteration loop. + for round = 1:maxNumIterations + 1, + if round == maxNumIterations + 1, + fprintf('No convergence after %d steps\n', maxNumIterations); + fprintf('Note that the plots are probably wrong.\n'); + if ~isempty(B) + % Symmetric orthogonalization. + B = B * real(inv(B' * B)^(1/2)); + + W = B' * whiteningMatrix; + A = dewhiteningMatrix * B; + else + W = []; + A = []; + end + return; + end + + if (interruptible & g_FastICA_interrupt) + if b_verbose + fprintf('\n\nCalculation interrupted by the user\n'); + end + if ~isempty(B) + W = B' * whiteningMatrix; + A = dewhiteningMatrix * B; + else + W = []; + A = []; + end + return; + end + + + % Symmetric orthogonalization. + B = B * real(inv(B' * B)^(1/2)); + + % Test for termination condition. Note that we consider opposite + % directions here as well. + minAbsCos = min(abs(diag(B' * BOld))); + minAbsCos2 = min(abs(diag(B' * BOld2))); + + if (1 - minAbsCos < epsilon) + if finetuningEnabled & notFine + if b_verbose, fprintf('Initial convergence, fine-tuning: \n'); end; + notFine = 0; + usedNlinearity = gFine; + myy = myyK * myyOrig; + BOld = zeros(size(B)); + BOld2 = zeros(size(B)); + + else + if b_verbose, fprintf('Convergence after %d steps\n', round); end + + % Calculate the de-whitened vectors. + A = dewhiteningMatrix * B; + break; + end + elseif stabilizationEnabled + if (~stroke) & (1 - minAbsCos2 < epsilon) + if b_verbose, fprintf('Stroke!\n'); end; + stroke = myy; + myy = .5*myy; + if mod(usedNlinearity,2) == 0 + usedNlinearity = usedNlinearity + 1; + end + elseif stroke + myy = stroke; + stroke = 0; + if (myy == 1) & (mod(usedNlinearity,2) ~= 0) + usedNlinearity = usedNlinearity - 1; + end + elseif (~long) & (round>maxNumIterations/2) + if b_verbose, fprintf('Taking long (reducing step size)\n'); end; + long = 1; + myy = .5*myy; + if mod(usedNlinearity,2) == 0 + usedNlinearity = usedNlinearity + 1; + end + end + end + + BOld2 = BOld; + BOld = B; + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Show the progress... + if b_verbose + if round == 1 + fprintf('Step no. %d\n', round); + else + fprintf('Step no. %d, change in value of estimate: %.3g \n', round, 1 - minAbsCos); + end + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Also plot the current state... + switch usedDisplay + case 1 + if rem(round, displayInterval) == 0, + % There was and may still be other displaymodes... + % 1D signals + icaplot('dispsig',(X'*B)'); + drawnow; + end + case 2 + if rem(round, displayInterval) == 0, + % ... and now there are :-) + % 1D basis + A = dewhiteningMatrix * B; + icaplot('dispsig',A'); + drawnow; + end + case 3 + if rem(round, displayInterval) == 0, + % ... and now there are :-) + % 1D filters + W = B' * whiteningMatrix; + icaplot('dispsig',W); + drawnow; + end + otherwise + end + + switch usedNlinearity + % pow3 + case 10 + B = (X * (( X' * B) .^ 3)) / numSamples - 3 * B; + case 11 + % optimoitu - epsilonin kokoisia eroja + % tämä on optimoitu koodi, katso vanha koodi esim. + % aikaisemmista versioista kuten 2.0 beta3 + Y = X' * B; + Gpow3 = Y .^ 3; + Beta = sum(Y .* Gpow3); + D = diag(1 ./ (Beta - 3 * numSamples)); + B = B + myy * B * (Y' * Gpow3 - diag(Beta)) * D; + case 12 + Xsub=X(:, getSamples(numSamples, sampleSize)); + B = (Xsub * (( Xsub' * B) .^ 3)) / size(Xsub,2) - 3 * B; + case 13 + % Optimoitu + Ysub=X(:, getSamples(numSamples, sampleSize))' * B; + Gpow3 = Ysub .^ 3; + Beta = sum(Ysub .* Gpow3); + D = diag(1 ./ (Beta - 3 * size(Ysub', 2))); + B = B + myy * B * (Ysub' * Gpow3 - diag(Beta)) * D; + + % tanh + case 20 + hypTan = tanh(a1 * X' * B); + B = X * hypTan / numSamples - ... + ones(size(B,1),1) * sum(1 - hypTan .^ 2) .* B / numSamples * ... + a1; + case 21 + % optimoitu - epsilonin kokoisia + Y = X' * B; + hypTan = tanh(a1 * Y); + Beta = sum(Y .* hypTan); + D = diag(1 ./ (Beta - a1 * sum(1 - hypTan .^ 2))); + B = B + myy * B * (Y' * hypTan - diag(Beta)) * D; + case 22 + Xsub=X(:, getSamples(numSamples, sampleSize)); + hypTan = tanh(a1 * Xsub' * B); + B = Xsub * hypTan / size(Xsub, 2) - ... + ones(size(B,1),1) * sum(1 - hypTan .^ 2) .* B / size(Xsub, 2) * a1; + case 23 + % Optimoitu + Y = X(:, getSamples(numSamples, sampleSize))' * B; + hypTan = tanh(a1 * Y); + Beta = sum(Y .* hypTan); + D = diag(1 ./ (Beta - a1 * sum(1 - hypTan .^ 2))); + B = B + myy * B * (Y' * hypTan - diag(Beta)) * D; + + % gauss + case 30 + U = X' * B; + Usquared=U .^ 2; + ex = exp(-a2 * Usquared / 2); + gauss = U .* ex; + dGauss = (1 - a2 * Usquared) .*ex; + B = X * gauss / numSamples - ... + ones(size(B,1),1) * sum(dGauss)... + .* B / numSamples ; + case 31 + % optimoitu + Y = X' * B; + ex = exp(-a2 * (Y .^ 2) / 2); + gauss = Y .* ex; + Beta = sum(Y .* gauss); + D = diag(1 ./ (Beta - sum((1 - a2 * (Y .^ 2)) .* ex))); + B = B + myy * B * (Y' * gauss - diag(Beta)) * D; + case 32 + Xsub=X(:, getSamples(numSamples, sampleSize)); + U = Xsub' * B; + Usquared=U .^ 2; + ex = exp(-a2 * Usquared / 2); + gauss = U .* ex; + dGauss = (1 - a2 * Usquared) .*ex; + B = Xsub * gauss / size(Xsub,2) - ... + ones(size(B,1),1) * sum(dGauss)... + .* B / size(Xsub,2) ; + case 33 + % Optimoitu + Y = X(:, getSamples(numSamples, sampleSize))' * B; + ex = exp(-a2 * (Y .^ 2) / 2); + gauss = Y .* ex; + Beta = sum(Y .* gauss); + D = diag(1 ./ (Beta - sum((1 - a2 * (Y .^ 2)) .* ex))); + B = B + myy * B * (Y' * gauss - diag(Beta)) * D; + + % skew + case 40 + B = (X * ((X' * B) .^ 2)) / numSamples; + case 41 + % Optimoitu + Y = X' * B; + Gskew = Y .^ 2; + Beta = sum(Y .* Gskew); + D = diag(1 ./ (Beta)); + B = B + myy * B * (Y' * Gskew - diag(Beta)) * D; + case 42 + Xsub=X(:, getSamples(numSamples, sampleSize)); + B = (Xsub * ((Xsub' * B) .^ 2)) / size(Xsub,2); + case 43 + % Uusi optimoitu + Y = X(:, getSamples(numSamples, sampleSize))' * B; + Gskew = Y .^ 2; + Beta = sum(Y .* Gskew); + D = diag(1 ./ (Beta)); + B = B + myy * B * (Y' * Gskew - diag(Beta)) * D; + + otherwise + error('Code for desired nonlinearity not found!'); + end + end + + + % Calculate ICA filters. + W = B' * whiteningMatrix; + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Also plot the last one... + switch usedDisplay + case 1 + % There was and may still be other displaymodes... + % 1D signals + icaplot('dispsig',(X'*B)'); + drawnow; + case 2 + % ... and now there are :-) + % 1D basis + icaplot('dispsig',A'); + drawnow; + case 3 + % ... and now there are :-) + % 1D filters + icaplot('dispsig',W); + drawnow; + otherwise + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% DEFLATION APPROACH +if approachMode == 2 + + B = zeros(vectorSize); + + % The search for a basis vector is repeated numOfIC times. + round = 1; + + numFailures = 0; + + while round <= numOfIC, + myy = myyOrig; + usedNlinearity = gOrig; + stroke = 0; + notFine = 1; + long = 0; + endFinetuning = 0; + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Show the progress... + if b_verbose, fprintf('IC %d ', round); end + + % Take a random initial vector of lenght 1 and orthogonalize it + % with respect to the other vectors. + if initialStateMode == 0 + w = randn (vectorSize, 1); + elseif initialStateMode == 1 + w=whiteningMatrix*guess(:,round); + end + w = w - B * B' * w; + w = w / norm(w); + + wOld = zeros(size(w)); + wOld2 = zeros(size(w)); + + % This is the actual fixed-point iteration loop. + % for i = 1 : maxNumIterations + 1 + i = 1; + gabba = 1; + while i <= maxNumIterations + gabba + if (usedDisplay > 0) + drawnow; + end + if (interruptible & g_FastICA_interrupt) + if b_verbose + fprintf('\n\nCalculation interrupted by the user\n'); + end + return; + end + + % Project the vector into the space orthogonal to the space + % spanned by the earlier found basis vectors. Note that we can do + % the projection with matrix B, since the zero entries do not + % contribute to the projection. + w = w - B * B' * w; + w = w / norm(w); + + if notFine + if i == maxNumIterations + 1 + if b_verbose + fprintf('\nComponent number %d did not converge in %d iterations.\n', round, maxNumIterations); + end + round = round - 1; + numFailures = numFailures + 1; + if numFailures > failureLimit + if b_verbose + fprintf('Too many failures to converge (%d). Giving up.\n', numFailures); + end + if round == 0 + A=[]; + W=[]; + end + return; + end + % numFailures > failurelimit + break; + end + % i == maxNumIterations + 1 + else + % if notFine + if i >= endFinetuning + wOld = w; % So the algorithm will stop on the next test... + end + end + % if notFine + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Show the progress... + if b_verbose, fprintf('.'); end; + + + % Test for termination condition. Note that the algorithm has + % converged if the direction of w and wOld is the same, this + % is why we test the two cases. + if norm(w - wOld) < epsilon | norm(w + wOld) < epsilon + if finetuningEnabled & notFine + if b_verbose, fprintf('Initial convergence, fine-tuning: '); end; + notFine = 0; + gabba = maxFinetune; + wOld = zeros(size(w)); + wOld2 = zeros(size(w)); + usedNlinearity = gFine; + myy = myyK * myyOrig; + + endFinetuning = maxFinetune + i; + + else + numFailures = 0; + % Save the vector + B(:, round) = w; + + % Calculate the de-whitened vector. + A(:,round) = dewhiteningMatrix * w; + % Calculate ICA filter. + W(round,:) = w' * whiteningMatrix; + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Show the progress... + if b_verbose, fprintf('computed ( %d steps ) \n', i); end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Also plot the current state... + switch usedDisplay + case 1 + if rem(round, displayInterval) == 0, + % There was and may still be other displaymodes... + % 1D signals + temp = X'*B; + icaplot('dispsig',temp(:,1:numOfIC)'); + drawnow; + end + case 2 + if rem(round, displayInterval) == 0, + % ... and now there are :-) + % 1D basis + icaplot('dispsig',A'); + drawnow; + end + case 3 + if rem(round, displayInterval) == 0, + % ... and now there are :-) + % 1D filters + icaplot('dispsig',W); + drawnow; + end + end + % switch usedDisplay + break; % IC ready - next... + end + %if finetuningEnabled & notFine + elseif stabilizationEnabled + if (~stroke) & (norm(w - wOld2) < epsilon | norm(w + wOld2) < ... + epsilon) + stroke = myy; + if b_verbose, fprintf('Stroke!'); end; + myy = .5*myy; + if mod(usedNlinearity,2) == 0 + usedNlinearity = usedNlinearity + 1; + end + elseif stroke + myy = stroke; + stroke = 0; + if (myy == 1) & (mod(usedNlinearity,2) ~= 0) + usedNlinearity = usedNlinearity - 1; + end + elseif (notFine) & (~long) & (i > maxNumIterations / 2) + if b_verbose, fprintf('Taking long (reducing step size) '); end; + long = 1; + myy = .5*myy; + if mod(usedNlinearity,2) == 0 + usedNlinearity = usedNlinearity + 1; + end + end + end + + wOld2 = wOld; + wOld = w; + + switch usedNlinearity + % pow3 + case 10 + w = (X * ((X' * w) .^ 3)) / numSamples - 3 * w; + case 11 + EXGpow3 = (X * ((X' * w) .^ 3)) / numSamples; + Beta = w' * EXGpow3; + w = w - myy * (EXGpow3 - Beta * w) / (3 - Beta); + case 12 + Xsub=X(:,getSamples(numSamples, sampleSize)); + w = (Xsub * ((Xsub' * w) .^ 3)) / size(Xsub, 2) - 3 * w; + case 13 + Xsub=X(:,getSamples(numSamples, sampleSize)); + EXGpow3 = (Xsub * ((Xsub' * w) .^ 3)) / size(Xsub, 2); + Beta = w' * EXGpow3; + w = w - myy * (EXGpow3 - Beta * w) / (3 - Beta); + % tanh + case 20 + hypTan = tanh(a1 * X' * w); + w = (X * hypTan - a1 * sum(1 - hypTan .^ 2)' * w) / numSamples; + case 21 + hypTan = tanh(a1 * X' * w); + Beta = w' * X * hypTan; + w = w - myy * ((X * hypTan - Beta * w) / ... + (a1 * sum((1-hypTan .^2)') - Beta)); + case 22 + Xsub=X(:,getSamples(numSamples, sampleSize)); + hypTan = tanh(a1 * Xsub' * w); + w = (Xsub * hypTan - a1 * sum(1 - hypTan .^ 2)' * w) / size(Xsub, 2); + case 23 + Xsub=X(:,getSamples(numSamples, sampleSize)); + hypTan = tanh(a1 * Xsub' * w); + Beta = w' * Xsub * hypTan; + w = w - myy * ((Xsub * hypTan - Beta * w) / ... + (a1 * sum((1-hypTan .^2)') - Beta)); + % gauss + case 30 + % This has been split for performance reasons. + u = X' * w; + u2=u.^2; + ex=exp(-a2 * u2/2); + gauss = u.*ex; + dGauss = (1 - a2 * u2) .*ex; + w = (X * gauss - sum(dGauss)' * w) / numSamples; + case 31 + u = X' * w; + u2=u.^2; + ex=exp(-a2 * u2/2); + gauss = u.*ex; + dGauss = (1 - a2 * u2) .*ex; + Beta = w' * X * gauss; + w = w - myy * ((X * gauss - Beta * w) / ... + (sum(dGauss)' - Beta)); + case 32 + Xsub=X(:,getSamples(numSamples, sampleSize)); + u = Xsub' * w; + u2=u.^2; + ex=exp(-a2 * u2/2); + gauss = u.*ex; + dGauss = (1 - a2 * u2) .*ex; + w = (Xsub * gauss - sum(dGauss)' * w) / size(Xsub, 2); + case 33 + Xsub=X(:,getSamples(numSamples, sampleSize)); + u = Xsub' * w; + u2=u.^2; + ex=exp(-a2 * u2/2); + gauss = u.*ex; + dGauss = (1 - a2 * u2) .*ex; + Beta = w' * Xsub * gauss; + w = w - myy * ((Xsub * gauss - Beta * w) / ... + (sum(dGauss)' - Beta)); + % skew + case 40 + w = (X * ((X' * w) .^ 2)) / numSamples; + case 41 + EXGskew = (X * ((X' * w) .^ 2)) / numSamples; + Beta = w' * EXGskew; + w = w - myy * (EXGskew - Beta*w)/(-Beta); + case 42 + Xsub=X(:,getSamples(numSamples, sampleSize)); + w = (Xsub * ((Xsub' * w) .^ 2)) / size(Xsub, 2); + case 43 + Xsub=X(:,getSamples(numSamples, sampleSize)); + EXGskew = (Xsub * ((Xsub' * w) .^ 2)) / size(Xsub, 2); + Beta = w' * EXGskew; + w = w - myy * (EXGskew - Beta*w)/(-Beta); + + otherwise + error('Code for desired nonlinearity not found!'); + end + + % Normalize the new w. + w = w / norm(w); + i = i + 1; + end + round = round + 1; + end + if b_verbose, fprintf('Done.\n'); end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % Also plot the ones that may not have been plotted. + if (usedDisplay > 0) & (rem(round-1, displayInterval) ~= 0) + switch usedDisplay + case 1 + % There was and may still be other displaymodes... + % 1D signals + temp = X'*B; + icaplot('dispsig',temp(:,1:numOfIC)'); + drawnow; + case 2 + % ... and now there are :-) + % 1D basis + icaplot('dispsig',A'); + drawnow; + case 3 + % ... and now there are :-) + % 1D filters + icaplot('dispsig',W); + drawnow; + otherwise + end + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% In the end let's check the data for some security +if ~isreal(A) + if b_verbose, fprintf('Warning: removing the imaginary part from the result.\n'); end + A = real(A); + W = real(W); +end + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Subfunction +% Calculates tanh simplier and faster than Matlab tanh. +function y=tanh(x) +y = 1 - 2 ./ (exp(2 * x) + 1); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function Samples = getSamples(max, percentage) +Samples = find(rand(1, max) < percentage); diff --git a/FastICA_25/gui_adv.m b/FastICA_25/gui_adv.m new file mode 100644 index 0000000..1f31689 --- /dev/null +++ b/FastICA_25/gui_adv.m @@ -0,0 +1,441 @@ +function gui_adv(x, y) +% +% This file is needed by FASTICAG + +% This is the advanced options -dialog + +% @(#)$Id: gui_adv.m,v 1.4 2004/07/27 13:09:26 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Global variables + +% Handle to the window +global hf_FastICA_AdvOpt; + +% Handles to some of the controls in window +global hpm_FastICA_finetune; +global he_FastICA_a1; +global he_FastICA_a2; +global he_FastICA_myy; +global he_FastICA_epsilon; +global he_FastICA_maxIterations; +global he_FastICA_maxFinetune; +global he_FastICA_sampleSize +global hpm_FastICA_initState; +global hb_FastICA_initGuess; +global ht_FastICA_initGuess; +global hpm_FastICA_displayMode; +global he_FastICA_displayInterval; +global hpm_FastICA_verbose; + +% Some of the main variables needed +global g_FastICA_initGuess; +global g_FastICA_finetune; +global g_FastICA_a1; +global g_FastICA_a2; +global g_FastICA_myy; +global g_FastICA_epsilon; +global g_FastICA_maxNumIte; +global g_FastICA_maxFinetune; +global g_FastICA_initState; +global g_FastICA_sampleSize; +global g_FastICA_displayMo; +global g_FastICA_displayIn; +global g_FastICA_verbose; + +global c_FastICA_appr_strD; +global c_FastICA_appr_strV; +global c_FastICA_finetune_strD; +global c_FastICA_finetune_strV; +global c_FastICA_iSta_strD; +global c_FastICA_iSta_strV; +global c_FastICA_dMod_strD; +global c_FastICA_dMod_strV; +global c_FastICA_verb_strD; +global c_FastICA_verb_strV; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Configuration options +FIGURENAME = 'FastICA: advanced options'; +FIGURETAG = 'f_FastICAAdvOpt'; +FIGURESIZE = [x y 450 280]; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Check to see if this figure is already open - it should not! +% Can't have more than one copy - otherwise the global +% variables and handles can get mixed up. +if ~isempty(findobj('Tag',FIGURETAG)) + error('Error: advanced options dialog already open!'); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Initialize some of the controls' values + +% Did we already load some initial guess +pm_initState_Value = g_FastICA_initState; +if isempty(g_FastICA_initGuess) | (g_FastICA_initGuess == 1) + t_initGuess_String = 'Not loaded'; +else + t_initGuess_String = 'Loaded'; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Create the figure +a = figure('Color',[0.8 0.8 0.8], ... + 'PaperType','a4letter', ... + 'Name', FIGURENAME, ... + 'NumberTitle', 'off', ... + 'Tag', FIGURETAG, ... + 'Position', FIGURESIZE, ... + 'MenuBar', 'none'); +set (a, 'Resize', 'off'); + +hf_FastICA_AdvOpt = a; + +set(hf_FastICA_AdvOpt, 'HandleVisibility', 'callback'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% From here on it get's ugly as I have not had time to clean it up + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Create the frames +pos_l=2; +pos_w=FIGURESIZE(3)-4; +pos_h=FIGURESIZE(4)-4; +pos_t=2; +h_f_adv_background = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_adv_background'); + +pos_w=120; +pos_l=FIGURESIZE(3)-(pos_w+2+2); +pos_h=FIGURESIZE(4)-2*4; +pos_t=4; +h_f_adv_side = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_adv_side'); + +pos_l=4; +pos_w=FIGURESIZE(3)-8-pos_w-2; +pos_h=FIGURESIZE(4)-8; +pos_t=4; +h_f_advopt = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_advopt'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Controls in f_advopt +bgc = get(h_f_advopt, 'BackgroundColor'); + +pos_w1=230; +pos_w2=70; + +pos_frame=get(h_f_advopt, 'Position'); +pos_h = 20; +pos_t = pos_frame(2) + pos_frame(4) - pos_h - 6; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','Fine-tune (g)', ... + 'Style','text', ... + 'Tag','t_727'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +hpm_FastICA_finetune = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',c_FastICA_finetune_strD, ... + 'Style','popupmenu', ... + 'Tag','pm_finetune', ... + 'Value',g_FastICA_finetune); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','Parameter a1 (g = ''tanh'')', ... + 'Style','text', ... + 'Tag','t_22'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +he_FastICA_a1 = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','right', ... + 'Callback','gui_advc Checka1', ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',num2str(g_FastICA_a1), ... + 'Style','edit', ... + 'Tag','e_a1'); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','Parameter a2 (g = ''gauss'')', ... + 'Style','text', ... + 'Tag','t_222'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +he_FastICA_a2 = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','right', ... + 'Callback','gui_advc Checka2', ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',num2str(g_FastICA_a2), ... + 'Style','edit', ... + 'Tag','e_a2'); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','mu (step size)', ... + 'Style','text', ... + 'Tag','t_223'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +he_FastICA_myy = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','right', ... + 'Callback','gui_advc CheckMyy', ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',num2str(g_FastICA_myy), ... + 'Style','edit', ... + 'Tag','e_myy'); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','epsilon (stopping criterion)', ... + 'Style','text', ... + 'Tag','t_23'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +he_FastICA_epsilon = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','right', ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',num2str(g_FastICA_epsilon), ... + 'Style','edit', ... + 'Tag','e_epsilon'); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','Maximum number of iterations', ... + 'Style','text', ... + 'Tag','t_24'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +he_FastICA_maxIterations = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','right', ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',num2str(g_FastICA_maxNumIte), ... + 'Style','edit', ... + 'Tag','e_maxIterations'); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','Maximum iterations in fine-tuning', ... + 'Style','text', ... + 'Tag','t_2412'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +he_FastICA_maxFinetune = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','right', ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',num2str(g_FastICA_maxFinetune), ... + 'Style','edit', ... + 'Tag','e_maxFinetune'); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','Sample size (proportion)', ... + 'Style','text', ... + 'Tag','t_224'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +he_FastICA_sampleSize = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','right', ... + 'Callback','gui_advc CheckSampleSize', ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',num2str(g_FastICA_sampleSize), ... + 'Style','edit', ... + 'Tag','e_sampleSize'); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','Initial state', ... + 'Style','text', ... + 'Tag','t_25'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +hpm_FastICA_initState = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',c_FastICA_iSta_strD, ... + 'Style','popupmenu', ... + 'Tag','pm_initState', ... + 'Value',pm_initState_Value); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +hb_FastICA_initGuess = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_advc loadGuess', ... + 'Position',[pos_l pos_t (pos_w1-60) pos_h], ... + 'String','Load initial guess', ... + 'UserData', g_FastICA_initGuess, ... + 'Tag','b_LoadGuess'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +ht_FastICA_initGuess = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[(pos_l) pos_t (pos_w2) pos_h], ... + 'String',t_initGuess_String, ... + 'Style','text', ... + 'Tag','t_initGuess'); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','Display mode', ... + 'Style','text', ... + 'Tag','t_27'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +hpm_FastICA_displayMode = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',c_FastICA_dMod_strD, ... + 'Style','popupmenu', ... + 'Tag','pm_displayMode', ... + 'Value',g_FastICA_displayMo); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','Iterations between displays', ... + 'Style','text', ... + 'Tag','t_28'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +he_FastICA_displayInterval = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','right', ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',num2str(g_FastICA_displayIn), ... + 'Style','edit', ... + 'Tag','e_displayInterval'); + +pos_t = pos_t - pos_h; +pos_l = pos_frame(1) + 6; +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w1 pos_h], ... + 'String','Verbose', ... + 'Style','text', ... + 'Tag','t_29'); + +pos_l = pos_frame(1) + pos_frame(3) - 6 - pos_w2; +hpm_FastICA_verbose = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'Position',[pos_l pos_t pos_w2 pos_h], ... + 'String',c_FastICA_verb_strD, ... + 'Style','popupmenu', ... + 'Tag','pm_verbose', ... + 'Value',g_FastICA_verbose); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Controls in f_adv_side +pos_vspace = 6; +pos_hspace = 10; +pos_frame = get(h_f_adv_side, 'Position'); +pos_w = 100; +pos_h = 30; +pos_l = pos_frame(1) + pos_hspace; +pos_t = pos_frame(2) + pos_frame(4) - pos_h - pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_advc OK', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','OK', ... + 'Tag','b_advOK'); + +pos_t=pos_t-pos_h-pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_advc Cancel', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Cancel', ... + 'Tag','b_advCancel'); + +pos_t=pos_t-pos_h-pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_advc Default', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Default', ... + 'Tag','b_advDefault'); + +pos_t=pos_t-pos_h-pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_advc Apply', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Apply', ... + 'Tag','b_advApply'); + +pos_t = pos_frame(2) + pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_advc Help', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Help', ... + 'Tag','b_advHelp'); + diff --git a/FastICA_25/gui_advc.m b/FastICA_25/gui_advc.m new file mode 100644 index 0000000..86a74fc --- /dev/null +++ b/FastICA_25/gui_advc.m @@ -0,0 +1,256 @@ +function gui_advc (action) +% +% This file is needed by FASTICAG + +% This file holds the callbacks for advanced options -dialog + +% @(#)$Id: gui_advc.m,v 1.3 2003/09/08 11:28:58 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Global variables + +% Handle to the window +global hf_FastICA_AdvOpt; + +% Handles to some of the controls in window +global hpm_FastICA_finetune; +global he_FastICA_a1; +global he_FastICA_a2; +global he_FastICA_myy; +global he_FastICA_epsilon; +global he_FastICA_maxIterations; +global he_FastICA_maxFinetune; +global he_FastICA_sampleSize; +global hpm_FastICA_initState; +global hb_FastICA_initGuess; +global ht_FastICA_initGuess; +global hpm_FastICA_displayMode; +global he_FastICA_displayInterval; +global hpm_FastICA_verbose; + +% Needed handles to the main window +global hf_FastICA_MAIN; +global ht_FastICA_icaStatus; +global ht_FastICA_numOfSamp; +global hpm_FastICA_stabilization; + +% Some of the main variables needed +global g_FastICA_initGuess; +global g_FastICA_numOfIC; +global g_FastICA_finetune; +global g_FastICA_a1; +global g_FastICA_a2; +global g_FastICA_myy; +global g_FastICA_epsilon; +global g_FastICA_maxNumIte; +global g_FastICA_maxFinetune; +global g_FastICA_initState; +global g_FastICA_sampleSize; +global g_FastICA_displayMo; +global g_FastICA_displayIn; +global g_FastICA_verbose; + +global c_FastICA_iSta_strV; + +% What is the load type of load dialog +global g_FastICA_loadType; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% This should not take long... +watchonInFigure = watchon; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch action +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Checka1' + + e_a1_val = str2num(get(he_FastICA_a1, 'String')); + if e_a1_val <= 0 + set(he_FastICA_a1, 'String', '0.1'); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Checka2' + + e_a2_val = str2num(get(he_FastICA_a2, 'String')); + if e_a2_val <= 0 + set(he_FastICA_a2, 'String', '0.1'); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'CheckMyy' + + e_myy_val = str2num(get(he_FastICA_myy, 'String')); + if e_myy_val <= 0 + set(he_FastICA_myy, 'String', '0.1'); + elseif e_myy_val > 1 + set(he_FastICA_myy, 'String', '1'); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'CheckSampleSize' + + e_sampleSize_val = str2num(get(he_FastICA_sampleSize, 'String')); + if e_sampleSize_val > 1 + set(he_FastICA_sampleSize, 'String', '1'); + else + numOfSamp = str2num(get(ht_FastICA_numOfSamp, 'String')); + if numOfSamp < 1000 + set(he_FastICA_sampleSize, 'String', '1'); + fprintf('Can''t reduce sample size. Already less than 1000 samples.\n'); + elseif (e_sampleSize_val * numOfSamp) < 1000 + fprintf('Can''t reduce sample size to less than 1000 samples.\n'); + set(he_FastICA_sampleSize, 'String', sprintf('%0.3f',1000/numOfSamp)); + end + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'loadGuess' + + handle = findobj('Tag','f_FastICALoad'); % Check if the window is already + if isempty(handle) % open. If not then open it. + pos = get(hf_FastICA_MAIN, 'Position'); + gui_l(pos(1), pos(2)); + else + if strcmp(g_FastICA_loadType, 'guess') % Check if it was the same load + figure(handle); % window. If it wasn't then + else % close the other window first + close(handle); % and then open the load window + fprintf('''Load data'' -dialog closed!\n'); + pos = get(hf_FastICA_MAIN, 'Position'); + gui_l(pos(1), pos(2)); + end + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'OK' + + gui_advc Apply; + + close(hf_FastICA_AdvOpt); + + % Use return to avoid reaching the watchoff statement at the end + % (There used to be a 'break' statement here, but it resulted in + % errors in more recent version of Matlab -- jarmo) + return; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Apply' + + newValues = 0; + + val = g_FastICA_finetune; + g_FastICA_finetune = get(hpm_FastICA_finetune, 'Value'); + if (g_FastICA_finetune ~= val) + newValues = 1; + end + + val = g_FastICA_a1; + g_FastICA_a1 = str2num(get(he_FastICA_a1, 'String')); + if (g_FastICA_a1 ~= val) + newValues = 1; + end + + val = g_FastICA_a2; + g_FastICA_a2 = str2num(get(he_FastICA_a2, 'String')); + if (g_FastICA_a2 ~= val) + newValues = 1; + end + + val = g_FastICA_myy; + g_FastICA_myy = str2num(get(he_FastICA_myy, 'String')); + if (g_FastICA_myy ~= val) + newValues = 1; + end + + % If myy < 1 then will use stabilazed code, and we don't care + % about the parameter stabilization :-) + if (g_FastICA_myy == 1) + set(hpm_FastICA_stabilization, 'Enable', 'on'); + else + set(hpm_FastICA_stabilization, 'Enable', 'off'); + end + + val = g_FastICA_epsilon; + g_FastICA_epsilon = str2num(get(he_FastICA_epsilon, 'String')); + if (g_FastICA_epsilon ~= val) + newValues = 1; + end + + val = g_FastICA_maxNumIte; + g_FastICA_maxNumIte = str2num(get(he_FastICA_maxIterations, 'String')); + if (g_FastICA_maxNumIte ~= val) + newValues = 1; + end + + val = g_FastICA_maxFinetune; + g_FastICA_maxFinetune = str2num(get(he_FastICA_maxFinetune, 'String')); + if (g_FastICA_maxFinetune ~= val) + newValues = 1; + end + + val = g_FastICA_sampleSize; + g_FastICA_sampleSize = str2num(get(he_FastICA_sampleSize, 'String')); + if (g_FastICA_sampleSize ~= val) + newValues = 1; + end + + val = g_FastICA_initState; + g_FastICA_initState = get(hpm_FastICA_initState, 'Value'); + if (g_FastICA_initState ~= val) + newValues = 1; + end + + val = g_FastICA_initGuess; + g_FastICA_initGuess = get(hb_FastICA_initGuess, 'UserData'); + if min(size(val) == size(g_FastICA_initGuess)) == 0 + newValues = 1; + else + if (g_FastICA_initGuess ~= val) + newValues = 1; + end + end + + g_FastICA_displayMo = get(hpm_FastICA_displayMode, 'Value'); + g_FastICA_displayIn = str2num(get(he_FastICA_displayInterval, 'String')); + g_FastICA_verbose = get(hpm_FastICA_verbose, 'Value'); + + if newValues == 1 + gui_cb NullICA; + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Cancel' + + close(hf_FastICA_AdvOpt); + + % Use return to avoid reaching the watchoff statement at the end + % (There used to be a 'break' statement here, but it resulted in + % errors in more recent version of Matlab -- jarmo) + return; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Default' + + % set default values to controls + set(hpm_FastICA_finetune, 'Value',5); + set(he_FastICA_a1, 'String','1'); + set(he_FastICA_a2, 'String','1'); + set(he_FastICA_myy, 'String','1'); + set(he_FastICA_epsilon, 'String','0.0001'); + set(he_FastICA_maxIterations, 'String','1000'); + set(he_FastICA_sampleSize, 'String','1'); + set(hpm_FastICA_initState, 'Value',1); + set(hpm_FastICA_displayMode, 'Value',1); + set(he_FastICA_displayInterval, 'String','1'); + set(hpm_FastICA_verbose, 'Value',1); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Help' + + gui_help('gui_advc'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +end % switch + +watchoff (watchonInFigure); \ No newline at end of file diff --git a/FastICA_25/gui_cb.m b/FastICA_25/gui_cb.m new file mode 100644 index 0000000..80a2ee0 --- /dev/null +++ b/FastICA_25/gui_cb.m @@ -0,0 +1,581 @@ +function gui_cb(action) +% +% This file is used by FASTICAG + +% This file holds the callbacks to the main window + +% @(#)$Id: gui_cb.m,v 1.5 2003/09/10 10:33:41 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Global variables + +% Handle to the main figure +global hf_FastICA_MAIN; + +% Handles for needed controls in main figure; +global ht_FastICA_mixedStatus; +global ht_FastICA_dim; +global ht_FastICA_numOfSamp; +global ht_FastICA_newDim; +global ht_FastICA_whiteStatus; +global ht_FastICA_icaStatus; +global hpm_FastICA_approach; +global he_FastICA_numOfIC; +global hpm_FastICA_g; +global hpm_FastICA_stabilization; + +% Main values are stored here +global g_FastICA_mixedsig; +global g_FastICA_mixedmean; +global g_FastICA_pca_D; +global g_FastICA_pca_E; +global g_FastICA_white_sig; +global g_FastICA_white_wm; +global g_FastICA_white_dwm; +global g_FastICA_ica_sig; +global g_FastICA_ica_A; +global g_FastICA_ica_W; +global g_FastICA_initGuess; +global g_FastICA_approach; +global g_FastICA_numOfIC; +global g_FastICA_g; +global g_FastICA_finetune; +global g_FastICA_a1; +global g_FastICA_a2; +global g_FastICA_myy; +global g_FastICA_stabilization; +global g_FastICA_epsilon; +global g_FastICA_maxNumIte; +global g_FastICA_maxFinetune; +global g_FastICA_sampleSize; +global g_FastICA_initState; +global g_FastICA_displayMo; +global g_FastICA_displayIn; +global g_FastICA_verbose; + +% String values are here +global c_FastICA_appr_strV; +global c_FastICA_g1_strD; +global c_FastICA_g1_strV; +global c_FastICA_g2_strD; +global c_FastICA_g2_strV; +global c_FastICA_finetune_strD; +global c_FastICA_finetune_strV; +global c_FastICA_stabili_strV; +global c_FastICA_iSta_strV; +global c_FastICA_dMod_strV; +global c_FastICA_verb_strV; + +% What is the load type of load dialog +global g_FastICA_loadType; + +% Global variable for stopping the ICA calculations +global g_FastICA_interrupt; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% What ever we do, it will take some time... not much, but some :-) +watchonInFigure = watchon; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch action +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'InitAll' + + % If the data is already loaded, then get the information from data + % and show to the user (also set g_FastICA_numOfIC) + if ~isempty(g_FastICA_mixedsig) + set(ht_FastICA_mixedStatus, 'String', ''); + [dim, numofsamp] = size(g_FastICA_mixedsig); + set(ht_FastICA_dim, 'String', int2str(dim)); + set(ht_FastICA_numOfSamp, 'String', int2str(numofsamp)); + set(ht_FastICA_newDim, 'String', int2str(dim)); + set(he_FastICA_numOfIC, 'String', int2str(dim)); + g_FastICA_numOfIC = dim; + g_FastICA_mixedmean = []; + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'LoadData' + + handle = findobj('Tag','f_FastICALoad'); % Check if the window is already + if isempty(handle) % open. If not then open it. + pos = get(hf_FastICA_MAIN, 'Position'); + % Based on the feedback obtained from some users, it seems + % that at least in some systems, pos can sometimes be empty. A + % similar check is done a few lines below. + if ~isempty (pos), + gui_l(pos(1), pos(2)); + else + gui_l (0, 0); + end + else + if strcmp(g_FastICA_loadType, 'data') % Check if it was the same load + figure(handle); % window. If it wasn't then + else % close the other window first + close(handle); % and then open the load window + fprintf('''Load initial guess'' -dialog closed!\n'); + pos = get(hf_FastICA_MAIN, 'Position'); + if ~isempty (pos), + gui_l(pos(1), pos(2)); + else + gui_l (0, 0); + end + end + end + + % gui_cb NewData; - is called from the load function if not canceled... + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'NewData' + + % New data is loaded or the old data changed. We need to find out + % somethings about the new data... and do some other stuff also... + [dim, numofsamp] = size(g_FastICA_mixedsig); + set(ht_FastICA_dim, 'String', dim); + set(ht_FastICA_newDim, 'String', dim); + set(ht_FastICA_numOfSamp, 'String', numofsamp); + set(he_FastICA_numOfIC, 'String', int2str(dim)); + + g_FastICA_numOfIC = dim; % Default for numOfIC = the new dimension + % PCA needs to be calculated again. + g_FastICA_pca_E = []; % We use this to check if PCA is calculated + gui_cb NullWhite; % Whitening needs to be done again also + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'NullWhite' + + % Whitening needs to done again next time it's needed + g_FastICA_white_sig = []; % We use this to check if whitening is calculated + gui_cb NullICA; % The FPICA must be calculated again + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'NullICA' + + % If IC's are needed they have to bee calculated again + g_FastICA_ica_sig = []; % We use this to check if FPICA is calculated + set(ht_FastICA_icaStatus,'String','Not yet done'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Transpose' + + if isempty(g_FastICA_mixedmean) + g_FastICA_mixedsig = g_FastICA_mixedsig'; + else + g_FastICA_mixedsig = (g_FastICA_mixedsig + ... + g_FastICA_mixedmean * ... + ones(1,size(g_FastICA_mixedsig, 2)))'; + g_FastICA_mixedmean = []; + end + gui_cb NewData; % Data has been changed + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'DoPCA' + + if ~isempty(g_FastICA_mixedsig) + % We'll remove mean of the data here also just in case... + if isempty(g_FastICA_mixedmean) + [g_FastICA_mixedsig, g_FastICA_mixedmean] = remmean(g_FastICA_mixedsig); + end + + % Do PCA interactively: ask the user for eigenvalues + [g_FastICA_pca_E, g_FastICA_pca_D] = pcamat(g_FastICA_mixedsig, ... + 0, 0, 'gui', ... + deblank(c_FastICA_verb_strV(g_FastICA_verbose,:))); + + newdim = size(g_FastICA_pca_D, 1); + set(ht_FastICA_newDim, 'String', int2str(newdim)); + set(he_FastICA_numOfIC, 'String', int2str(newdim)); + g_FastICA_numOfIC = newdim; + gui_cb NullWhite; % Whitening needs to be done again also + % but we'll do it when it's needed. + else + fprintf('Data not loaded yet!\n\n'); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'OrigDim' + + gui_cb NewData; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'ShowMixed' + + if ~isempty(g_FastICA_mixedsig) + handle = findobj('Tag','f_FastICA_mix'); % Check if the window is already + if isempty(handle) % open. If not then open it. + figure('Tag', 'f_FastICA_mix', ... + 'Name', 'FastICA: Plot data', ... + 'NumberTitle', 'off'); + else + figure(handle); + clf; % clear the figure for next plots + end + if isempty(g_FastICA_mixedmean) + icaplot('dispsig',g_FastICA_mixedsig, 0, 0, 0, 'Mixed signals'); + else + icaplot('dispsig',g_FastICA_mixedsig + g_FastICA_mixedmean * ... + ones(1, size(g_FastICA_mixedsig, 2)), 0, 0, 0, 'Mixed signals'); + end + else + fprintf('Data not loaded yet!\n\n'); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'ShowWhite' + + if ~isempty(g_FastICA_mixedsig) + if isempty(g_FastICA_white_sig) % if whitening is not done, we need to + gui_cb Whiten; % do it before we can display the + end % whitened signals + + handle = findobj('Tag','f_FastICA_white'); % Check if the window is already + if isempty(handle) % open. If not then open it. + figure('Tag', 'f_FastICA_white', ... + 'Name', 'FastICA: Plot whitened', ... + 'NumberTitle', 'off'); + else + figure(handle); + clf; % clear the figure for next plots + end + icaplot('dispsig',g_FastICA_white_sig,0,0,0,'Whitened signals'); + else + fprintf('Data not loaded yet!\n\n'); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Whiten' + + set(ht_FastICA_whiteStatus,'String','Computing...'); + + % If PCA is not calculated, we'll have to calculate it now, + % we'll do it without guestions - we don't reduce the dimension + % here - but PCAMAT might reduce the dimension automatically. + if isempty(g_FastICA_pca_E) + % We'll remove mean of the data here also just in case... + if isempty(g_FastICA_mixedmean) + [g_FastICA_mixedsig, g_FastICA_mixedmean] = remmean(g_FastICA_mixedsig); + end + + [g_FastICA_pca_E, g_FastICA_pca_D] = pcamat(g_FastICA_mixedsig, 1, ... + size(g_FastICA_mixedsig, ... + 1), 'off', ... + deblank(c_FastICA_verb_strV(g_FastICA_verbose,:))); + + % Check if the dimension was reduced automatically + newdim = size(g_FastICA_pca_D, 1); + set(ht_FastICA_newDim, 'String', int2str(newdim)); + % Check if the numOfIC now has illegal value entered + % We do that by telling the program that there is new value + % entered for NumOfIC. + gui_cb ChangeNumOfIC; + end + + % And now we can calculate whitening... + [g_FastICA_white_sig, g_FastICA_white_wm, g_FastICA_white_dwm] = ... + whitenv(g_FastICA_mixedsig, g_FastICA_pca_E, g_FastICA_pca_D, deblank(c_FastICA_verb_strV(g_FastICA_verbose,:))); + + set (ht_FastICA_whiteStatus,'String',''); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'ChangeApproach' + + % Get the old value for g + eval(['g_str = c_FastICA_g' int2str(g_FastICA_approach) '_strV;']); + old_g = deblank(g_str(g_FastICA_g,:)); + + % Get and set the new value for approach + g_FastICA_approach = get(hpm_FastICA_approach, 'Value'); + + % The possible values for g depend on the value of approach... + eval(['g_str = c_FastICA_g' int2str(g_FastICA_approach) '_strD;']); + set(hpm_FastICA_g, 'String', g_str); + + % Match the old g value from the new g values so that if the + % old_g can be found from the new values (anywhere), then set new g + % to that value, and if it's not found then set the new value to 1. + match = 0; + eval(['g_str = c_FastICA_g' int2str(g_FastICA_approach) '_strV;']); + for i=1:size(g_str,1) + if strcmp(old_g, deblank(g_str(i,:))) + match = i; + end + end + if match == 0 + match = 1; % the old g is not availabe anymore, set g = 1. + end + g_FastICA_g = match; + set(hpm_FastICA_g, 'Value', match); + + gui_cb NullICA; % The options are changed so we must calculate ICA again + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'ChangeNumOfIC' + + % Get the new value... and store it later on after some checks + numofic = str2num(get(he_FastICA_numOfIC, 'String')); + + % The number of IC can't be less than 1 or more than the reduced dimension. + numoficmax = str2num(get(ht_FastICA_newDim, 'String')); + if numofic < 1 + set(he_FastICA_numOfIC, 'String', '1'); + g_FastICA_numOfIC = 1; + elseif numofic > numoficmax + set(he_FastICA_numOfIC, 'String', int2str (numoficmax)); + g_FastICA_numOfIC = numoficmax; + else + g_FastICA_numOfIC = numofic; + end + + gui_cb NullICA; % The options are changed so we must calculate ICA again + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'ChangeG' + + % Get the new value for g. + g_FastICA_g = get(hpm_FastICA_g, 'Value'); + + gui_cb NullICA; % The options are changed so we must calculate ICA again + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'ChangeStab' + + % Get the new value for g. + g_FastICA_stabilization = get(hpm_FastICA_stabilization, 'Value'); + + gui_cb NullICA; % The options are changed so we must calculate ICA again + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'AdvOpt' + + handle = findobj('Tag','f_FastICAAdvOpt'); + if isempty(handle) % Check to see if the window is + pos = get(hf_FastICA_MAIN, 'Position'); % already open... + if ~isempty (pos), + gui_adv(pos(1), pos(2)); + else + gui_adv(0, 0); + end + else + figure(handle) + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'ShowICASig' + + if ~isempty(g_FastICA_mixedsig) + % If the IC's are not already calculated, we'll do it now + if isempty(g_FastICA_ica_sig) + gui_cb DoFPICA; + end + + % The signals may have been already displaued by the FPICA function + % BUT the FPICA may also have shown either the basis of the filters + % so the signals still need to be shown - besides the mean was added + % in only later after FPICA + + % Also notice that in this version if there was something wrong in FPICA + % Then the results are []. - We don't try to plot them! + if ~isempty(g_FastICA_ica_sig') + handle = findobj('Tag','f_FastICA_ica'); % Check if the window is already + if isempty(handle) % open. If not then open it. + figure('Tag', 'f_FastICA_ica', ... + 'Name', 'FastICA: Plot ICs', ... + 'NumberTitle', 'off'); + else + figure(handle); + clf; % clear the figure for next plots + end + + icaplot('dispsig', g_FastICA_ica_sig, 0, ... + 0, 0, 'Independent components'); + end + else + fprintf('Data not loaded yet!\n\n'); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'DoFPICA' + + gui_cb DisableButtons; + g_FastICA_interrupt = 0; + + if ~isempty(g_FastICA_mixedsig) + if isempty(g_FastICA_white_sig) % We need the whitened signal here + gui_cb Whiten; + end + + set(ht_FastICA_icaStatus,'String','Computing...'); + + % The possible values for g depend on approach + eval(['g_str = c_FastICA_g' int2str(g_FastICA_approach) '_strV;']); + + % We'll contruct a command string which we'll later on evaluate... + % This is where the Fixed point algorithm is used. + command_str = ['[g_FastICA_ica_A,g_FastICA_ica_W]=' ... + 'fpica(g_FastICA_white_sig,' ... + 'g_FastICA_white_wm,' ... + 'g_FastICA_white_dwm,' ... + '''' deblank(c_FastICA_appr_strV(g_FastICA_approach,:)) ... + ''',' ... + 'g_FastICA_numOfIC,' ... + '''' deblank(g_str(g_FastICA_g,:)) ''',' ... + '''' ... + deblank(c_FastICA_finetune_strV(g_FastICA_finetune,:)) ... + ''',' ... + 'g_FastICA_a1,' ... + 'g_FastICA_a2,' ... + 'g_FastICA_myy,' ... + '''' ... + deblank(c_FastICA_stabili_strV(g_FastICA_stabilization,:)) ... + ''',' ... + 'g_FastICA_epsilon,' ... + 'g_FastICA_maxNumIte,' ... + 'g_FastICA_maxFinetune,' ... + '''' deblank(c_FastICA_iSta_strV(g_FastICA_initState,:)) ... + ''',' ... + 'g_FastICA_initGuess,' ... + 'g_FastICA_sampleSize,' ... + '''' deblank(c_FastICA_dMod_strV(g_FastICA_displayMo,:)) ... + ''',' ... + 'g_FastICA_displayIn,' ... + '''' deblank(c_FastICA_verb_strV(g_FastICA_verbose,:)) ... + ''');']; + + + % If the user wants to plot while computing... + % let's at least plot it to the right figure then + if ~strcmp(deblank(c_FastICA_dMod_strV(g_FastICA_displayMo,:)),'off') + handle = findobj('Tag','f_FastICA_ica'); % Check if the window is already + if isempty(handle) % open. If not then open it. + figure('Tag', 'f_FastICA_ica', ... + 'Name', 'FastICA: Plot ICs', ... + 'NumberTitle', 'off'); + else + figure(handle); + clf; % clear the figure for next plots + end + end + + % ... and so let's do it... + eval(command_str); + + % Also notice that in this version if there was something wrong in FPICA + % Then the results are []. + if ~isempty(g_FastICA_ica_W) + % Add the mean back in. + g_FastICA_ica_sig = g_FastICA_ica_W * g_FastICA_mixedsig ... + + (g_FastICA_ica_W * g_FastICA_mixedmean) ... + * ones(1,size(g_FastICA_mixedsig, 2)); + set (ht_FastICA_icaStatus,'String','Done'); + else + gui_cb NullICA; % set icasig=[] and do what ever needs to be done then + end + + if ~(g_FastICA_interrupt) + gui_cb EnableButtons; + end + else + fprintf('Data not loaded yet!\n\n'); + end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Interrupt' + g_FastICA_interrupt = 1; + set(ht_FastICA_icaStatus,'String','Interrupted'); + gui_cb EnableButtons; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'DisableButtons' + set(findobj('Tag','b_Transpose'),'Enable','off'); + set(findobj('Tag','b_ShowMixed'),'Enable','off'); + set(findobj('Tag','b_DoPCA'),'Enable','off'); + set(findobj('Tag','b_OrigDim'),'Enable','off'); + set(findobj('Tag','b_ShowWhite'),'Enable','off'); + set(findobj('Tag','b_advOpt'),'Enable','off'); + set(findobj('Tag','b_ShowICASig'),'Enable','off'); + set(findobj('Tag','b_LoadData'),'Enable','off'); + set(findobj('Tag','b_DoFPICA'),'Enable','off'); + set(findobj('Tag','b_SaveData'),'Enable','off'); + set(findobj('Tag','b_Quit'),'Enable','off'); + set(findobj('Tag','b_Interrupt'),'Visible','on'); + drawnow; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'EnableButtons' + set(findobj('Tag','b_Transpose'),'Enable','on'); + set(findobj('Tag','b_ShowMixed'),'Enable','on'); + set(findobj('Tag','b_DoPCA'),'Enable','on'); + set(findobj('Tag','b_OrigDim'),'Enable','on'); + set(findobj('Tag','b_ShowWhite'),'Enable','on'); + set(findobj('Tag','b_advOpt'),'Enable','on'); + set(findobj('Tag','b_ShowICASig'),'Enable','on'); + set(findobj('Tag','b_LoadData'),'Enable','on'); + set(findobj('Tag','b_DoFPICA'),'Enable','on'); + set(findobj('Tag','b_SaveData'),'Enable','on'); + set(findobj('Tag','b_Quit'),'Enable','on'); + set(findobj('Tag','b_Interrupt'),'Visible','off'); + drawnow; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'SaveData' + + handle = findobj('Tag','f_FastICASave'); % Check if the window is already + if isempty(handle) % open. If not then open it. + pos = get(hf_FastICA_MAIN, 'Position'); + if ~isempty (pos), + gui_s(pos(1), pos(2)); + else + gui_s(0, 0); + end + else + figure(handle); % window. If it wasn't then + end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Quit' + + % We'll close the other dialogs if they are open. + Tags = ['f_FastICALoad ' + 'f_FastICAAdvOpt' + 'f_FastICASave ' + 'f_FastICA_mix ' + 'f_FastICA_white' + 'f_FastICA_ica ']; + for i=1:size(Tags,1) + handle = findobj('Tag', deblank(Tags(i,:))); + if ~isempty(handle) + close(handle); + end + end + + % Close this window + close(hf_FastICA_MAIN); + + % Clear the used global variables. + gui_cg; + + % Use return to avoid reaching the watchoff statement at the end + % (There used to be a 'break' statement here, but it resulted in + % errors in more recent version of Matlab -- jarmo) + return; + % ... and we're done. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'About' + + gui_help('gui_cb_about'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Help' + + gui_help('gui_cb_help'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +end % switch + +watchoff (watchonInFigure); diff --git a/FastICA_25/gui_cg.m b/FastICA_25/gui_cg.m new file mode 100644 index 0000000..e66cf81 --- /dev/null +++ b/FastICA_25/gui_cg.m @@ -0,0 +1,84 @@ +function gui_cg() +% +% This function is needed by FASTICAG + +% This file just removes the global variables +% that are used in FASTICAG from the memory + +% @(#)$Id: gui_cg.m,v 1.2 2003/04/05 14:23:57 jarmo Exp $ + +clear global c_FastICA_appr_strD; +clear global c_FastICA_appr_strV; +clear global c_FastICA_dMod_strD; +clear global c_FastICA_dMod_strV; +clear global c_FastICA_finetune_strD; +clear global c_FastICA_finetune_strV; +clear global c_FastICA_g1_strD; +clear global c_FastICA_g1_strV; +clear global c_FastICA_g2_strD; +clear global c_FastICA_g2_strV; +clear global c_FastICA_iSta_strD; +clear global c_FastICA_iSta_strV; +clear global c_FastICA_stabili_strD; +clear global c_FastICA_stabili_strV; +clear global c_FastICA_verb_strD; +clear global c_FastICA_verb_strV; +clear global g_FastICA_a1; +clear global g_FastICA_a2; +clear global g_FastICA_approach; +clear global g_FastICA_displayIn; +clear global g_FastICA_displayMo; +clear global g_FastICA_epsilon; +clear global g_FastICA_finetune; +clear global g_FastICA_g; +clear global g_FastICA_ica_A; +clear global g_FastICA_ica_W; +clear global g_FastICA_ica_sig; +clear global g_FastICA_initGuess; +clear global g_FastICA_initState; +clear global g_FastICA_interrupt; +clear global g_FastICA_loadType; +clear global g_FastICA_maxFinetune; +clear global g_FastICA_maxNumIte; +clear global g_FastICA_mixedmean; +clear global g_FastICA_mixedsig; +clear global g_FastICA_myy; +clear global g_FastICA_numOfIC; +clear global g_FastICA_pca_D; +clear global g_FastICA_pca_E; +clear global g_FastICA_sampleSize; +clear global g_FastICA_stabilization; +clear global g_FastICA_verbose; +clear global g_FastICA_white_dwm; +clear global g_FastICA_white_sig; +clear global g_FastICA_white_wm; +clear global hb_FastICA_initGuess; +clear global he_FastICA_a1; +clear global he_FastICA_a2; +clear global he_FastICA_displayInterval; +clear global he_FastICA_epsilon; +clear global he_FastICA_file; +clear global he_FastICA_suffix; +clear global he_FastICA_maxFinetune; +clear global he_FastICA_maxIterations; +clear global he_FastICA_myy; +clear global he_FastICA_numOfIC; +clear global he_FastICA_sampleSize; +clear global hf_FastICA_MAIN; +clear global hf_FastICA_AdvOpt; +clear global hf_FastICA_Load; +clear global hf_FastICA_Save; +clear global hpm_FastICA_approach; +clear global hpm_FastICA_displayMode; +clear global hpm_FastICA_finetune; +clear global hpm_FastICA_g; +clear global hpm_FastICA_initState; +clear global hpm_FastICA_stabilization; +clear global hpm_FastICA_verbose; +clear global ht_FastICA_dim; +clear global ht_FastICA_icaStatus; +clear global ht_FastICA_initGuess; +clear global ht_FastICA_mixedStatus; +clear global ht_FastICA_newDim; +clear global ht_FastICA_numOfSamp; +clear global ht_FastICA_whiteStatus; diff --git a/FastICA_25/gui_help.m b/FastICA_25/gui_help.m new file mode 100644 index 0000000..da88f3a --- /dev/null +++ b/FastICA_25/gui_help.m @@ -0,0 +1,224 @@ +function gui_help(which_help) +% +% Used by FASTICAG + +% All the help texts and title used by GUI are stored here. +% Make changes here. +% Also displays the helpwindow with the selected text + +% @(#)$Id: gui_help.m,v 1.6 2005/10/19 13:05:34 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch which_help +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'pcamat' + + helptitle = 'FastICA: Reduce dimension'; + helptext=[ ... + 'You may reduce the dimension of the data by selecting only the ' + 'subspace corresponding to certain eigenvalues of the covariance ' + 'matrix of the data. Give the indices of the first and last ' + 'eigenvalues (sorted in descending order) to be included (all ' + 'eigenvalues in between will be included as well). The eigenvalues ' + 'and their indices can be seen in the graphical plot now on the ' + 'screen. The heights of the bars give the eigenvalues, with indices ' + 'below. ' + ' ' + 'For example, give ''1'' and ''n'' if you want to reduce the dimension ' + 'to n by principal component analysis, which means discarding the ' + 'subspaces corresponding to the smallest eigenvalues. Such a ' + 'dimension reduction may reduce noise and improve the performance of' + 'ICA. ']; + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'gui_cb_about' + + helptitle='About FastICA'; + helptext =[ ... + 'FastICA for Matlab 7.x and 6.x ' + 'Version 2.5, October 19 2005 ' + 'Copyright (c) Hugo Gävert, Jarmo Hurri, Jaakko Särelä, and Aapo Hyvärinen.' + ' ' + 'For more information please see: ' + 'http://www.cis.hut.fi/projects/ica/fastica/ ']; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'gui_cb_help' + + helptitle='FastICA GUI'; + helptext = [... + 'Basic function: ' + ' ' + '- Click LOAD DATA and give the name of the variable that contains ' + ' the data. ' + ' ' + '- Click DO ICA to perform the analysis. ' + ' ' + '- Click SAVE RESULTS to store the results for future use. ' + ' ' + 'Options: ' + ' ' + 'If the input matrix contains the signals as column vectors instead of ' + 'row vectors, click on TRANSPOSE to transpose the data matrix. ' + ' ' + 'Click on PLOT DATA to see the data as 1-D time signals. ' + ' ' + 'Clicking REDUCE DIM gives you a graphical plot of the eigenvalue ' + 'structure of the covariance matrix of the data. You can then reduce ' + 'the dimension of the data by retaining only the subspaces corresponding to ' + 'the largest (or smallest) eigenvalues (i.e. variances). To undo this ' + 'operation click ORIGINAL DIM. You can plot the whitened (preprocessed ' + 'data) by PLOT WHITENED. ' + ' ' + 'Click on DO ICA to perform independent component analysis. ' + 'Clicking on PLOT ICS has the same effect, except that DO ICA forces ' + 'recomputation of ICA. ' + ' ' + 'You can choose the decorrelation approach by the ''Approach'' drop-down menu:' + 'deflation means that the independent components are estimated ' + 'one-by-one, whereas in the symmetric approach they are estimated in ' + 'parallel. You can now choose the number of independent components to be ' + 'estimated in both deflation and symmetric approaches. ' + ' ' + 'You have a choice of three nonlinearities: ' + ' ' + '''pow3'' (default) : g(u)=u^3 ' + '''tanh'' : g(u)=tanh(u) ' + '''gauss'' : g(u)=u*exp(-u^2/2) ' + '''skew'' : g(u)=u^2 ' + ' ' + 'For example, you could choose approach=''symmetric'' and nonlinearity=''tanh'' ' + 'to perform maximum likelihood ICA estimation for supergaussian data. ' + ' ' + 'If the algorithm does not seem to converge, you can use the stabilized ' + 'version of the fixed-point algorithm. To use the stabilized version, ' + 'choose ''on'' from the drop-down menu ''Stabilization''. ' + 'If you have specified a value less than 1 for the parameter ''mu'' from ' + 'the ''Advanced Options'' menu then the ''Stabilization'' drop-down menu is ' + 'not active. This is because if the parameter ''mu'' is less than 1 then the ' + 'program will use the stabilized code. Please see the help for ' + 'Advanced Options for more information about stabilization. ' + ' ' + 'The ADVANCED OPTIONS menu has its own HELP button. ' + ' ' + 'During computations, an INTERRUPT button appears. Clicking the button ' + 'interrupts the computations. ']; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'gui_advc' + + helptitle='FastICA GUI: Advanced options'; + helptext = [... + 'Advanced options: ' + ' ' + 'In some cases, it may be desired to improve the statistical ' + 'performance of the algorithm by using a fine-tuning procedure. This ' + 'means that after (initial) convergence, the algorithm is run ' + '(possibly) with a different nonlinearity, and using a smaller step ' + 'size and the stabilized version of the fixed-point algorithm. ' + 'You can specify the nonlinearity that will then be used with the ' + 'parameter ''Finetune''. If you set the the finetuning to ''off'', then the' + 'fine-tuning won''t be done. ' + ' ' + 'You can also fine-tune the nonlinearities used in the fixed-point ' + 'algorithm. ' + 'The nonlinearities tanh and gauss contain parameters a1 and a2, so ' + 'that the nonlinearities are in fact defined as: ' + '''tanh'' : g(u)=tanh(a1*u) ' + '''gauss'' : g(u)=u*exp(-a2*u^2/2) ' + 'The default values of a1 and a2 are 1, in which case they effectively ' + 'disappear from the definitions. ' + ' ' + 'If the algorithm does not seem to converge, you can use the stabilized' + 'version of the fixed-point algorithm. There are two ways of doing ' + 'this. The first one is to explicitly specify the value of the step ' + 'size parameter ''mu''. The default value is 1. Choosing a value that ' + 'is smaller than 1 implies that the computations are made using the ' + 'stabilized fixed-point algorithm. The second way to use the stabilized' + 'version is simpler: choose ''on'' in the drop-down menu ''stabilization'' ' + '(on the main menu page). Then the value of mu will be changed ' + 'automatically during the ICA calculations. If the program senses that ' + 'the algorithm is stuck between two points, it will halve the value of ' + 'mu (.5 * mu) for duration of one round. (This is called a ''stroke.''). ' + 'Also if there is no convergence before half of the maximum number of ' + 'iterations has been reached then the mu will be halved for the rest ' + 'of the rounds. ' + ' ' + 'The parameter ''epsilon'' is used to decide if the algorithm has ' + 'converged. A larger epsilon makes the convergence test less strict. ' + 'Note that if you use finetuning or stabilization, epsilon may need to ' + 'be reduced accordingly. ' + ' ' + '''Maximum number of iterations'' gives the absolute maximum of ' + 'iterations used in the estimation procedure. In the deflation ' + 'approach, this is iterations per component. ' + ' ' + 'You can input the ''Initial state'' of the algorithm, i.e. the initial ' + 'value for A. Choose ''guess'' in the drop-down menu ''Initial state'', ' + 'click on ''Load Initial guess'', and give the name of the variable in ' + 'Matlab workspace that contains the initial value. ' + ' ' + 'In the drop-down menu ''Display mode'' you can choose if the results are' + 'plotted during computations. You may wish to switch this off ' + 'especially if you have lots of data which takes a long time to plot. ' + '''Iteration between displays'' tells how often the running estimates of ' + 'the independent components are plotted: A value of 1 means after every' + 'iteration. ' + ' ' + 'If the data vector is very long (more than 10 000 points), it may be ' + 'advisable to use only a part of the data at every iteration. The ' + 'option ''Sample size'' allows you to give the proportion (0-1) of the ' + 'data that is used at every step. The sample is chosen randomly at ' + 'every step. ' + ' ' + 'Click on DEFAULT to return to default values for all advanced options.' + 'You can make the new values take effect without closing the window by ' + 'clicking APPLY. ']; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'gui_lc_data' + + helptitle='FastICA GUI: Load data'; + helptext = [... + 'Input the name of the variable in Matlab workspace that contains the ' + 'data. The data must be in a single matrix, each row (or column) giving' + 'the values of one signal. If the signals are in column vectors, click ' + 'TRANSPOSE after loading the data to transpose the data matrix. ' + ' ' + 'If the data is in a file, load it to Matlab workspace first. ']; + +case 'gui_lc_guess' + + helptitle='FastICA GUI: Load guess'; + helptext = [... + 'Input the name of the variable in Matlab workspace that contains the' + 'initial value for the mixing matrix A, and click OK. If the initial ' + 'value is in a file, load it to Matlab workspace first. ']; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'gui_sc' + + helptitle='FastICA GUI: Save results'; + helptext = [... + 'The results will be saved as variables in Matlab workspace. ' + 'You give a suffix that identifies the variables. For example, if you ' + 'give ''_FASTICA'', the results will be stored in the following variables:' + ' ' + 'W_FASTICA : estimate of the separating matrix ' + 'A_FASTICA : estimate of the mixing matrix ' + 'IC_FASTICA : estimated independent components (row vectors) ' + ' ' + 'Additional results related to preprocessing: ' + 'D_FASTICA and E_FASTICA : give the eigenvalue decomposition of the ' + ' covariance matrix ' + 'whiteningMatrix_FASTICA : matrix performing whitening and dimension ' + ' reduction ' + 'dewhiteningMatrix_FASTICA : the pseudoinverse of the whitening matrix ' + 'whitesig_FASTICA : whitened (i.e. preprocessed) signals. ']; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +end + +helpwin(helptext, helptitle); \ No newline at end of file diff --git a/FastICA_25/gui_l.m b/FastICA_25/gui_l.m new file mode 100644 index 0000000..be9e3e1 --- /dev/null +++ b/FastICA_25/gui_l.m @@ -0,0 +1,180 @@ +function gui_l (x, y) +% +% This file is needed by FASTICAG + +% The load dialog for loading new data +% and new initial guess. + +% @(#)$Id: gui_l.m,v 1.4 2004/07/27 13:09:26 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Global variables + +% Handle to the window +global hf_FastICA_Load; + +% Handles to some of the controls in window +global he_FastICA_file; + +% What is the load type of load dialog +global g_FastICA_loadType; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Configuration options +FIGURENAME = 'FastICA: Load'; +FIGURETAG = 'f_FastICALoad'; +FIGURESIZE = [x y 450 150]; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Check to see if this figure is already open - it should not! +% Can't have more than one copy - otherwise the global +% variables and handles can get mixed up. +if ~isempty(findobj('Tag',FIGURETAG)) + error('Error: load dialog already open!'); +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Initialize some of the controls' values + +% What are we loading - who is calling? +caller = get(gcf, 'CurrentObject'); + +switch get(caller, 'Tag') + case 'b_LoadData' % Do we load new data... + loadString = 'Load data from variable in Matlab.'; + g_FastICA_loadType = 'data'; + FIGURENAME = 'FastICA: Load data'; + + case 'b_LoadGuess' % ... or new initial guess? + loadString = 'Load initial guess for mixing matrix A from variable in Matlab.'; + g_FastICA_loadType = 'guess'; + FIGURENAME = 'FastICA: Load initial guess'; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Create the figure +a = figure('Color',[0.8 0.8 0.8], ... + 'PaperType','a4letter', ... + 'Name', FIGURENAME, ... + 'NumberTitle', 'off', ... + 'Tag', FIGURETAG, ... + 'Position', FIGURESIZE, ... + 'MenuBar', 'none'); +set (a, 'Resize', 'off'); + +hf_FastICA_Load = a; + +set(hf_FastICA_Load, 'HandleVisibility', 'callback'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% From here on it get's ugly as I have not had time to clean it up + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Create the frames +pos_l=2; +pos_w=FIGURESIZE(3)-4; +pos_h=FIGURESIZE(4)-4; +pos_t=2; +h_f_load_background = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_load_background'); + +pos_w=120; +pos_l=FIGURESIZE(3)-(pos_w+2+2); +pos_h=FIGURESIZE(4)-2*4; +pos_t=4; +h_f_load_side = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_load_side'); + +pos_l=4; +pos_w=FIGURESIZE(3)-8-pos_w-2; +pos_h=FIGURESIZE(4)-8; +pos_t=4; +h_f_load = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_load'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Controls in f_load +bgc = get(h_f_load, 'BackgroundColor'); + +pos_w=230; + +pos_frame=get(h_f_load, 'Position'); +pos_h = 40; +pos_t = pos_frame(2) + pos_frame(4) - pos_h - 6; +pos_l = pos_frame(1) + 6; + +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String',loadString, ... + 'Style','text', ... + 'Tag','t_93'); + +pos_h = 20; +pos_t = pos_t - pos_h - 10; +pos_l = pos_frame(1) + 6; + +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Name of the variable:', ... + 'Style','text', ... + 'Tag','t_92'); + +pos_w = 200; +pos_l = pos_l + 30; +pos_t = pos_t - pos_h; +he_FastICA_file = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','', ... + 'Style','edit', ... + 'Tag','e_file'); + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Controls in f_load_side +pos_vspace = 6; +pos_hspace = 10; +pos_frame = get(h_f_load_side, 'Position'); +pos_w = 100; +pos_h = 30; +pos_l = pos_frame(1) + pos_hspace; +pos_t = pos_frame(2) + pos_frame(4) - pos_h - pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_lc Load', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Load', ... + 'Tag','b_lLoad'); + +pos_t=pos_t-pos_h-pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_lc Cancel', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Cancel', ... + 'Tag','b_lCancel'); + +pos_t = pos_frame(2) + pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_lc Help', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Help', ... + 'Tag','b_lHelp'); + diff --git a/FastICA_25/gui_lc.m b/FastICA_25/gui_lc.m new file mode 100644 index 0000000..9caaf8a --- /dev/null +++ b/FastICA_25/gui_lc.m @@ -0,0 +1,112 @@ +function gui_lc (action) +% +% This file is used by FASTICAG + +% This file holds the callbacks for load-dialog + +% @(#)$Id: gui_lc.m,v 1.4 2003/09/11 12:01:19 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Global variables + +% Handle to the window +global hf_FastICA_Load; + +% Handles to some of the controls in window +global he_FastICA_file; + +% Needed handles from the main figure +global ht_FastICA_mixedStatus; + +% Needed handles from the advOpt figure +global hb_FastICA_initGuess; +global ht_FastICA_initGuess; +global hpm_FastICA_initState; + +% The needed main variables +global g_FastICA_mixedsig; +global g_FastICA_mixedmean; + +% What is the load type of load dialog +global g_FastICA_loadType; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% This should not take long... +watchonInFigure = watchon; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch action +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Load' + + varName = get(he_FastICA_file, 'String'); % The name of the variable to be loaded + command=['evalin(''base'',''assignin(''''caller'''',''''data'''',' varName ')'')']; + eval(command,'fprintf(''Variable not found in MATLAB workspace, data not loaded!\n'');data=[];'); % Variable is copyed to 'data' + if length (size (data)) > 2, + fprintf (['Input data can not have more than two dimensions, data' ... + ' not loaded.\n']); + data = []; + end + + if any (any (isnan (data))), + fprintf ('Input data contains NaN''s, data not loaded.\n'); + data = []; + end + + + if isempty(data) % if there was no name given... + watchoff (watchonInFigure); + % There used to be a 'break' statement here, but it resulted in + % errors in more recent version of Matlab -- jarmo + return; + end + switch g_FastICA_loadType + case 'data' % New data + g_FastICA_mixedsig = data; + if ~isa (g_FastICA_mixedsig, 'double') + fprintf ('Warning: converting input data into regular (double) precision.\n'); + g_FastICA_mixedsig = double (g_FastICA_mixedsig); + end + + set(ht_FastICA_mixedStatus, 'String', ''); + g_FastICA_mixedmean = []; % New data - so that means ... + gui_cb NewData; + + case 'guess' % New initial guess + set(hb_FastICA_initGuess, 'UserData', data); % Since we loaded new initial + set(ht_FastICA_initGuess, 'String', 'Loaded'); % guess, we wan't to use it too + set(hpm_FastICA_initState, 'Value', 2); % ... set initState to 'guess' + end + + close(hf_FastICA_Load); % close the dialog + + % Use return to avoid reaching the watchoff statement at the end + % (There used to be a 'break' statement here, but it resulted in + % errors in more recent version of Matlab -- jarmo) + return; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Cancel' + + close(hf_FastICA_Load); % do nothing just exit + + % Use return to avoid reaching the watchoff statement at the end + % (There used to be a 'break' statement here, but it resulted in + % errors in more recent version of Matlab -- jarmo) + return; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Help' + + % Which help do we show? + switch g_FastICA_loadType + case 'data' + gui_help('gui_lc_data'); + case 'guess' + gui_help('gui_lc_guess'); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +end % switch + +watchoff (watchonInFigure); diff --git a/FastICA_25/gui_s.m b/FastICA_25/gui_s.m new file mode 100644 index 0000000..01a9621 --- /dev/null +++ b/FastICA_25/gui_s.m @@ -0,0 +1,177 @@ +function gui_s (x, y) +% +% This file is used by FASTICAG + +% The save dialog for saving the results + +% @(#)$Id: gui_s.m,v 1.4 2004/07/27 13:09:26 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Global variables + +% Handle to the window +global hf_FastICA_Save; + +% Handles to some of the controls in window +global he_FastICA_suffix; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Configuration options +FIGURENAME = 'FastICA: Save results'; +FIGURETAG = 'f_FastICASave'; +FIGURESIZE = [x y 450 150]; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Check to see if this figure is already open - it should not! +% Can't have more than one copy - otherwise the global +% variables and handles can get mixed up. +if ~isempty(findobj('Tag',FIGURETAG)) + error('Error: load dialog already open!'); +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Initialize some of the controls' values + +saveString = 'Save results as variables in MATLAB workspace.'; +promptString = 'Suffix to identify the results:'; +helpString = 'If you give e.g. ''_FastICA'', the variables will be called A_FastICA, W_FastICA, etc.'; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Create the figure +a = figure('Color',[0.8 0.8 0.8], ... + 'PaperType','a4letter', ... + 'Name', FIGURENAME, ... + 'NumberTitle', 'off', ... + 'Tag', FIGURETAG, ... + 'Position', FIGURESIZE, ... + 'MenuBar', 'none'); +set (a, 'Resize', 'off'); + +hf_FastICA_Save = a; + +set(hf_FastICA_Save, 'HandleVisibility', 'callback'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% From here on it get's ugly as I have not had time to clean it up + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Create the frames +pos_l=2; +pos_w=FIGURESIZE(3)-4; +pos_h=FIGURESIZE(4)-4; +pos_t=2; +h_f_save_background = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_save_background'); + +pos_w=120; +pos_l=FIGURESIZE(3)-(pos_w+2+2); +pos_h=FIGURESIZE(4)-2*4; +pos_t=4; +h_f_save_side = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_save_side'); + +pos_l=4; +pos_w=FIGURESIZE(3)-8-pos_w-2; +pos_h=FIGURESIZE(4)-8; +pos_t=4; +h_f_save = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'Style','frame', ... + 'Tag','f_save'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Controls in f_save +bgc = get(h_f_save, 'BackgroundColor'); + +pos_w=230; + +pos_frame=get(h_f_save, 'Position'); +pos_h = 40; +pos_t = pos_frame(2) + pos_frame(4) - pos_h - 6; +pos_l = pos_frame(1) + 6; + +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String',saveString, ... + 'Style','text', ... + 'Tag','t_93'); + +pos_h = 20; +pos_t = pos_t - pos_h - 10; +pos_l = pos_frame(1) + 6; + +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String',promptString, ... + 'Style','text', ... + 'Tag','t_92'); + +pos_w = 200; +pos_l = pos_l + 30; +pos_t = pos_t - pos_h; +he_FastICA_suffix = uicontrol('Parent',a, ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','', ... + 'Style','edit', ... + 'Tag','e_suffix'); + +pos_w = pos_frame(3) - 12; +pos_h = 30; +pos_t = pos_frame(2) + 6; +pos_l = pos_frame(1) + 6; + +b = uicontrol('Parent',a, ... + 'BackgroundColor',bgc, ... + 'HorizontalAlignment','left', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String',helpString, ... + 'Style','text', ... + 'Tag','t_97'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Controls in f_save_side +pos_vspace = 6; +pos_hspace = 10; +pos_frame = get(h_f_save_side, 'Position'); +pos_w = 100; +pos_h = 30; +pos_l = pos_frame(1) + pos_hspace; +pos_t = pos_frame(2) + pos_frame(4) - pos_h - pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_sc Save', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Save', ... + 'Tag','b_sSave'); + +pos_t=pos_t-pos_h-pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_sc Cancel', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Cancel', ... + 'Tag','b_sCancel'); + +pos_t = pos_frame(2) + pos_vspace; +b = uicontrol('Parent',a, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Callback','gui_sc Help', ... + 'Position',[pos_l pos_t pos_w pos_h], ... + 'String','Help', ... + 'Tag','b_sHelp'); + diff --git a/FastICA_25/gui_sc.m b/FastICA_25/gui_sc.m new file mode 100644 index 0000000..cf65bc5 --- /dev/null +++ b/FastICA_25/gui_sc.m @@ -0,0 +1,74 @@ +function gui_sc (action) +% +% This file is used by FASTICAG + +% This file holds the callbacks for save-dialog + +% @(#)$Id: gui_sc.m,v 1.3 2003/09/08 11:28:59 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Global variables + +% Handle to the window +global hf_FastICA_Save; + +% Handles to some of the controls in window +global he_FastICA_suffix; + +% The needed main variables +global g_FastICA_ica_sig; +global g_FastICA_ica_A; +global g_FastICA_ica_W; +global g_FastICA_white_sig; +global g_FastICA_white_wm; +global g_FastICA_white_dwm; +global g_FastICA_pca_E; +global g_FastICA_pca_D; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% This should not take long... +watchonInFigure = watchon; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +switch action +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Save' + + suffix = deblank(get(he_FastICA_suffix, 'String')); % The suffix for the variables + + fprintf('Saving results in variables in Matlab workspace.\n'); + assignin('base',['IC' suffix],g_FastICA_ica_sig); + assignin('base',['A' suffix],g_FastICA_ica_A); + assignin('base',['W' suffix],g_FastICA_ica_W); + assignin('base',['whitesig' suffix],g_FastICA_white_sig); + assignin('base',['whiteningMatrix' suffix],g_FastICA_white_wm); + assignin('base',['dewhiteningMatrix' suffix],g_FastICA_white_dwm); + assignin('base',['E' suffix],g_FastICA_pca_E); + assignin('base',['D' suffix],g_FastICA_pca_D); + + close(hf_FastICA_Save); % close the dialog + + % Use return to avoid reaching the watchoff statement at the end + % (There used to be a 'break' statement here, but it resulted in + % errors in more recent version of Matlab -- jarmo) + return; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Cancel' + + close(hf_FastICA_Save); % do nothing just exit + + % Use return to avoid reaching the watchoff statement at the end + % (There used to be a 'break' statement here, but it resulted in + % errors in more recent version of Matlab -- jarmo) + return; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +case 'Help' + + gui_help('gui_sc'); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +end % switch + +watchoff (watchonInFigure); diff --git a/FastICA_25/icaplot.m b/FastICA_25/icaplot.m new file mode 100644 index 0000000..9126f1a --- /dev/null +++ b/FastICA_25/icaplot.m @@ -0,0 +1,397 @@ +function icaplot(mode, varargin); +%ICAPLOT - plot signals in various ways +% +% ICAPLOT is mainly for plottinf and comparing the mixed signals and +% separated ica-signals. +% +% ICAPLOT has many different modes. The first parameter of the function +% defines the mode. Other parameters and their order depends on the +% mode. The explanation for the more common parameters is in the end. +% +% Classic +% icaplot('classic', s1, n1, range, xrange, titlestr) +% +% Plots the signals in the same manner as the FASTICA and FASTICAG +% programs do. All the signals are plotted in their own axis. +% +% Complot +% icaplot('complot', s1, n1, range, xrange, titlestr) +% +% The signals are plotted on the same axis. This is good for +% visualization of the shape of the signals. The scale of the signals +% has been altered so that they all fit nicely. +% +% Histogram +% icaplot('histogram', s1, n1, range, bins, style) +% +% The histogram of the signals is plotted. The number of bins can be +% specified with 'bins'-parameter. The style for the histograms can +% be either 'bar' (default) of 'line'. +% +% Scatter +% icaplot('scatter', s1, n1, s2, n2, range, titlestr, s1label, +% s2label, markerstr) +% +% A scatterplot is plotted so that the signal 1 is the 'X'-variable +% and the signal 2 is the 'Y'-variable. The 'markerstr' can be used +% to specify the maker used in the plot. The format for 'markerstr' +% is the same as for Matlab's PLOT. +% +% Compare +% icaplot('compare', s1, n1, s2, n2, range, xrange, titlestr, +% s1label, s2label) +% +% This for for comparing two signals. The main used in this context +% would probably be to see how well the separated ICA-signals explain +% the observed mixed signals. The s2 signals are first scaled with +% REGRESS function. +% +% Compare - Sum +% icaplot('sum', s1, n1, s2, n2, range, xrange, titlestr, s1label, +% s2label) +% +% The same as Compare, but this time the signals in s2 (specified by +% n2) are summed together. +% +% Compare - Sumerror +% icaplot('sumerror', s1, n1, s2, n2, range, xrange, titlestr, +% s1label, s2label) +% +% The same as Compare - Sum, but also the 'error' between the signal +% 1 and the summed IC's is plotted. +% +% +% More common parameters +% The signals to be plotted are in matrices s1 and s2. The n1 and n2 +% are used to tell the index of the signal or signals to be plotted +% from s1 or s2. If n1 or n2 has a value of 0, then all the signals +% from corresponding matrix will be plotted. The values for n1 and n2 +% can also be vectors (like: [1 3 4]) In some casee if there are more +% than 1 signal to be plotted from s1 or s2 then the plot will +% contain as many subplots as are needed. +% +% The range of the signals to be plotted can be limited with +% 'range'-parameter. It's value is a vector ( 10000:15000 ). If range +% is 0, then the whole range will be plotted. +% +% The 'xrange' is used to specify only the labels used on the +% x-axis. The value of 'xrange' is a vector containing the x-values +% for the plots or [start end] for begin and end of the range +% ( 10000:15000 or [10 15] ). If xrange is 0, then value of range +% will be used for x-labels. +% +% You can give a title for the plot with 'titlestr'. Also the +% 's1label' and 's2label' are used to give more meaningfull label for +% the signals. +% +% Lastly, you can omit some of the arguments from the and. You will +% have to give values for the signal matrices (s1, s2) and the +% indexes (n1, n2) + +% @(#)$Id: icaplot.m,v 1.2 2003/04/05 14:23:58 jarmo Exp $ + +switch mode +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + % 'dispsig' is to replace the old DISPSIG + % '' & 'classic' are just another names - '' quite short one :-) + case {'', 'classic', 'dispsig'} + % icaplot(mode, s1, n1, range, xrange, titlestr) + if length(varargin) < 1, error('Not enough arguments.'); end + if length(varargin) < 5, titlestr = '';else titlestr = varargin{5}; end + if length(varargin) < 4, xrange = 0;else xrange = varargin{4}; end + if length(varargin) < 3, range = 0;else range = varargin{3}; end + if length(varargin) < 2, n1 = 0;else n1 = varargin{2}; end + s1 = varargin{1}; + range=chkrange(range, s1); + xrange=chkxrange(xrange, range); + n1=chkn(n1, s1); + + clf; + + numSignals = size(n1, 2); + for i = 1:numSignals, + subplot(numSignals, 1, i); + plot(xrange, s1(n1(i), range)); + end + subplot(numSignals,1, 1); + if (~isempty(titlestr)) + title(titlestr); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + case 'complot' + % icaplot(mode, s1, n1, range, xrange, titlestr) + if length(varargin) < 1, error('Not enough arguments.'); end + if length(varargin) < 5, titlestr = '';else titlestr = varargin{5}; end + if length(varargin) < 4, xrange = 0;else xrange = varargin{4}; end + if length(varargin) < 3, range = 0;else range = varargin{3}; end + if length(varargin) < 2, n1 = 0;else n1 = varargin{2}; end + s1 = remmean(varargin{1}); + range=chkrange(range, s1); + xrange=chkxrange(xrange, range); + n1=chkn(n1, s1); + + for i = 1:size(n1, 2) + S1(i, :) = s1(n1(i), range); + end + + alpha = mean(max(S1')-min(S1')); + for i = 1:size(n1,2) + S2(i,:) = S1(i,:) - alpha*(i-1)*ones(size(S1(1,:))); + end + + plot(xrange, S2'); + axis([min(xrange) max(xrange) min(min(S2)) max(max(S2)) ]); + + set(gca,'YTick',(-size(S1,1)+1)*alpha:alpha:0); + set(gca,'YTicklabel',fliplr(n1)); + + if (~isempty(titlestr)) + title(titlestr); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + case 'histogram' + % icaplot(mode, s1, n1, range, bins, style) + if length(varargin) < 1, error('Not enough arguments.'); end + if length(varargin) < 5, style = 'bar';else style = varargin{5}; end + if length(varargin) < 4, bins = 10;else bins = varargin{4}; end + if length(varargin) < 3, range = 0;else range = varargin{3}; end + if length(varargin) < 2, n1 = 0;else n1 = varargin{2}; end + s1 = varargin{1}; + range = chkrange(range, s1); + n1 = chkn(n1, s1); + + numSignals = size(n1, 2); + rows = floor(sqrt(numSignals)); + columns = ceil(sqrt(numSignals)); + while (rows * columns < numSignals) + columns = columns + 1; + end + + switch style + case {'', 'bar'} + for i = 1:numSignals, + subplot(rows, columns, i); + hist(s1(n1(i), range), bins); + title(int2str(n1(i))); + drawnow; + end + + case 'line' + for i = 1:numSignals, + subplot(rows, columns, i); + [Y, X]=hist(s1(n1(i), range), bins); + plot(X, Y); + title(int2str(n1(i))); + drawnow; + end + otherwise + fprintf('Unknown style.\n') + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + case 'scatter' + % icaplot(mode, s1, n1, s2, n2, range, titlestr, xlabelstr, ylabelstr, markerstr) + if length(varargin) < 4, error('Not enough arguments.'); end + if length(varargin) < 9, markerstr = '.';else markerstr = varargin{9}; end + if length(varargin) < 8, ylabelstr = 'Signal 2';else ylabelstr = varargin{8}; end + if length(varargin) < 7, xlabelstr = 'Signal 1';else xlabelstr = varargin{7}; end + if length(varargin) < 6, titlestr = '';else titlestr = varargin{6}; end + if length(varargin) < 5, range = 0;else range = varargin{5}; end + n2 = varargin{4}; + s2 = varargin{3}; + n1 = varargin{2}; + s1 = varargin{1}; + range = chkrange(range, s1); + n1 = chkn(n1, s1); + n2 = chkn(n2, s2); + + rows = size(n1, 2); + columns = size(n2, 2); + for r = 1:rows + for c = 1:columns + subplot(rows, columns, (r-1)*columns + c); + plot(s1(n1(r), range),s2(n2(c), range),markerstr); + if (~isempty(titlestr)) + title(titlestr); + end + if (rows*columns == 1) + xlabel(xlabelstr); + ylabel(ylabelstr); + else + xlabel([xlabelstr ' (' int2str(n1(r)) ')']); + ylabel([ylabelstr ' (' int2str(n2(c)) ')']); + end + drawnow; + end + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + case {'compare', 'sum', 'sumerror'} + % icaplot(mode, s1, n1, s2, n2, range, xrange, titlestr, s1label, s2label) + if length(varargin) < 4, error('Not enough arguments.'); end + if length(varargin) < 9, s2label = 'IC';else s2label = varargin{9}; end + if length(varargin) < 8, s1label = 'Mix';else s1label = varargin{8}; end + if length(varargin) < 7, titlestr = '';else titlestr = varargin{7}; end + if length(varargin) < 6, xrange = 0;else xrange = varargin{6}; end + if length(varargin) < 5, range = 0;else range = varargin{5}; end + s1 = varargin{1}; + n1 = varargin{2}; + s2 = varargin{3}; + n2 = varargin{4}; + range = chkrange(range, s1); + xrange = chkxrange(xrange, range); + n1 = chkn(n1, s1); + n2 = chkn(n2, s2); + + numSignals = size(n1, 2); + if (numSignals > 1) + externalLegend = 1; + else + externalLegend = 0; + end + + rows = floor(sqrt(numSignals+externalLegend)); + columns = ceil(sqrt(numSignals+externalLegend)); + while (rows * columns < (numSignals+externalLegend)) + columns = columns + 1; + end + + clf; + + for j = 1:numSignals + subplot(rows, columns, j); + switch mode + case 'compare' + plotcompare(s1, n1(j), s2,n2, range, xrange); + [legendtext,legendstyle]=legendcompare(n1(j),n2,s1label,s2label,externalLegend); + case 'sum' + plotsum(s1, n1(j), s2,n2, range, xrange); + [legendtext,legendstyle]=legendsum(n1(j),n2,s1label,s2label,externalLegend); + case 'sumerror' + plotsumerror(s1, n1(j), s2,n2, range, xrange); + [legendtext,legendstyle]=legendsumerror(n1(j),n2,s1label,s2label,externalLegend); + end + + if externalLegend + title([titlestr ' (' s1label ' ' int2str(n1(j)) ')']); + else + legend(char(legendtext)); + if (~isempty(titlestr)) + title(titlestr); + end + end + end + + if (externalLegend) + subplot(rows, columns, numSignals+1); + legendsize = size(legendtext, 2); + hold on; + for i=1:legendsize + plot([0 1],[legendsize-i legendsize-i], char(legendstyle(i))); + text(1.5, legendsize-i, char(legendtext(i))); + end + hold off; + axis([0 6 -1 legendsize]); + axis off; + end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function plotcompare(s1, n1, s2, n2, range, xrange); + style=getStyles; + K = regress(s1(n1,:)',s2'); + plot(xrange, s1(n1,range), char(style(1))); + hold on + for i=1:size(n2,2) + plotstyle=char(style(i+1)); + plot(xrange, K(n2(i))*s2(n2(i),range), plotstyle); + end + hold off + +function [legendText, legendStyle]=legendcompare(n1, n2, s1l, s2l, externalLegend); + style=getStyles; + if (externalLegend) + legendText(1)={[s1l ' (see the titles)']}; + else + legendText(1)={[s1l ' ', int2str(n1)]}; + end + legendStyle(1)=style(1); + for i=1:size(n2, 2) + legendText(i+1) = {[s2l ' ' int2str(n2(i))]}; + legendStyle(i+1) = style(i+1); + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function plotsum(s1, n1, s2, n2, range, xrange); + K = diag(regress(s1(n1,:)',s2')); + sigsum = sum(K(:,n2)*s2(n2,:)); + plot(xrange, s1(n1, range),'k-', ... + xrange, sigsum(range), 'b-'); + +function [legendText, legendStyle]=legendsum(n1, n2, s1l, s2l, externalLegend); + if (externalLegend) + legendText(1)={[s1l ' (see the titles)']}; + else + legendText(1)={[s1l ' ', int2str(n1)]}; + end + legendText(2)={['Sum of ' s2l ': ', int2str(n2)]}; + legendStyle={'k-';'b-'}; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function plotsumerror(s1, n1, s2, n2, range, xrange); + K = diag(regress(s1(n1,:)',s2')); + sigsum = sum(K(:,n2)*s2(n2,:)); + plot(xrange, s1(n1, range),'k-', ... + xrange, sigsum(range), 'b-', ... + xrange, s1(n1, range)-sigsum(range), 'r-'); + +function [legendText, legendStyle]=legendsumerror(n1, n2, s1l, s2l, externalLegend); + if (externalLegend) + legendText(1)={[s1l ' (see the titles)']}; + else + legendText(1)={[s1l ' ', int2str(n1)]}; + end + legendText(2)={['Sum of ' s2l ': ', int2str(n2)]}; + legendText(3)={'"Error"'}; + legendStyle={'k-';'b-';'r-'}; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function style=getStyles; + color = {'k','r','g','b','m','c','y'}; + line = {'-',':','-.','--'}; + for i = 0:size(line,2)-1 + for j = 1:size(color, 2) + style(j + i*size(color, 2)) = strcat(color(j), line(i+1)); + end + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function range=chkrange(r, s) + if r == 0 + range = 1:size(s, 2); + else + range = r; + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function xrange=chkxrange(xr,r); + if xr == 0 + xrange = r; + elseif size(xr, 2) == 2 + xrange = xr(1):(xr(2)-xr(1))/(size(r,2)-1):xr(2); + elseif size(xr, 2)~=size(r, 2) + error('Xrange and range have different sizes.'); + else + xrange = xr; + end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function n=chkn(n,s) + if n == 0 + n = 1:size(s, 1); + end \ No newline at end of file diff --git a/FastICA_25/pcamat.m b/FastICA_25/pcamat.m new file mode 100644 index 0000000..a91b0c8 --- /dev/null +++ b/FastICA_25/pcamat.m @@ -0,0 +1,358 @@ +function [E, D] = pcamat(vectors, firstEig, lastEig, s_interactive, ... + s_verbose); +%PCAMAT - Calculates the pca for data +% +% [E, D] = pcamat(vectors, firstEig, lastEig, ... +% interactive, verbose); +% +% Calculates the PCA matrices for given data (row) vectors. Returns +% the eigenvector (E) and diagonal eigenvalue (D) matrices containing the +% selected subspaces. Dimensionality reduction is controlled with +% the parameters 'firstEig' and 'lastEig' - but it can also be done +% interactively by setting parameter 'interactive' to 'on' or 'gui'. +% +% ARGUMENTS +% +% vectors Data in row vectors. +% firstEig Index of the largest eigenvalue to keep. +% Default is 1. +% lastEig Index of the smallest eigenvalue to keep. +% Default is equal to dimension of vectors. +% interactive Specify eigenvalues to keep interactively. Note that if +% you set 'interactive' to 'on' or 'gui' then the values +% for 'firstEig' and 'lastEig' will be ignored, but they +% still have to be entered. If the value is 'gui' then the +% same graphical user interface as in FASTICAG will be +% used. Default is 'off'. +% verbose Default is 'on'. +% +% +% EXAMPLE +% [E, D] = pcamat(vectors); +% +% Note +% The eigenvalues and eigenvectors returned by PCAMAT are not sorted. +% +% This function is needed by FASTICA and FASTICAG + +% For historical reasons this version does not sort the eigenvalues or +% the eigen vectors in any ways. Therefore neither does the FASTICA or +% FASTICAG. Generally it seams that the components returned from +% whitening is almost in reversed order. (That means, they usually are, +% but sometime they are not - depends on the EIG-command of matlab.) + +% @(#)$Id: pcamat.m,v 1.5 2003/12/15 18:24:32 jarmo Exp $ + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Default values: +if nargin < 5, s_verbose = 'on'; end +if nargin < 4, s_interactive = 'off'; end +if nargin < 3, lastEig = size(vectors, 1); end +if nargin < 2, firstEig = 1; end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Check the optional parameters; +switch lower(s_verbose) + case 'on' + b_verbose = 1; + case 'off' + b_verbose = 0; + otherwise + error(sprintf('Illegal value [ %s ] for parameter: ''verbose''\n', s_verbose)); +end + +switch lower(s_interactive) + case 'on' + b_interactive = 1; + case 'off' + b_interactive = 0; + case 'gui' + b_interactive = 2; + otherwise + error(sprintf('Illegal value [ %s ] for parameter: ''interactive''\n', ... + s_interactive)); +end + +oldDimension = size (vectors, 1); +if ~(b_interactive) + if lastEig < 1 | lastEig > oldDimension + error(sprintf('Illegal value [ %d ] for parameter: ''lastEig''\n', lastEig)); + end + if firstEig < 1 | firstEig > lastEig + error(sprintf('Illegal value [ %d ] for parameter: ''firstEig''\n', firstEig)); + end +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Calculate PCA + +% Calculate the covariance matrix. +if b_verbose, fprintf ('Calculating covariance...\n'); end +covarianceMatrix = cov(vectors', 1); + +% Calculate the eigenvalues and eigenvectors of covariance +% matrix. +[E, D] = eig (covarianceMatrix); + +% The rank is determined from the eigenvalues - and not directly by +% using the function rank - because function rank uses svd, which +% in some cases gives a higher dimensionality than what can be used +% with eig later on (eig then gives negative eigenvalues). +rankTolerance = 1e-7; +maxLastEig = sum (diag (D) > rankTolerance); +if maxLastEig == 0, + fprintf (['Eigenvalues of the covariance matrix are' ... + ' all smaller than tolerance [ %g ].\n' ... + 'Please make sure that your data matrix contains' ... + ' nonzero values.\nIf the values are very small,' ... + ' try rescaling the data matrix.\n'], rankTolerance); + error ('Unable to continue, aborting.'); +end + +% Sort the eigenvalues - decending. +eigenvalues = flipud(sort(diag(D))); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Interactive part - command-line +if b_interactive == 1 + + % Show the eigenvalues to the user + hndl_win=figure; + bar(eigenvalues); + title('Eigenvalues'); + + % ask the range from the user... + % ... and keep on asking until the range is valid :-) + areValuesOK=0; + while areValuesOK == 0 + firstEig = input('The index of the largest eigenvalue to keep? (1) '); + lastEig = input(['The index of the smallest eigenvalue to keep? (' ... + int2str(oldDimension) ') ']); + % Check the new values... + % if they are empty then use default values + if isempty(firstEig), firstEig = 1;end + if isempty(lastEig), lastEig = oldDimension;end + % Check that the entered values are within the range + areValuesOK = 1; + if lastEig < 1 | lastEig > oldDimension + fprintf('Illegal number for the last eigenvalue.\n'); + areValuesOK = 0; + end + if firstEig < 1 | firstEig > lastEig + fprintf('Illegal number for the first eigenvalue.\n'); + areValuesOK = 0; + end + end + % close the window + close(hndl_win); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Interactive part - GUI +if b_interactive == 2 + + % Show the eigenvalues to the user + hndl_win = figure('Color',[0.8 0.8 0.8], ... + 'PaperType','a4letter', ... + 'Units', 'normalized', ... + 'Name', 'FastICA: Reduce dimension', ... + 'NumberTitle','off', ... + 'Tag', 'f_eig'); + h_frame = uicontrol('Parent', hndl_win, ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'Units', 'normalized', ... + 'Position',[0.13 0.05 0.775 0.17], ... + 'Style','frame', ... + 'Tag','f_frame'); + +b = uicontrol('Parent',hndl_win, ... + 'Units','normalized', ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'HorizontalAlignment','left', ... + 'Position',[0.142415 0.0949436 0.712077 0.108507], ... + 'String','Give the indices of the largest and smallest eigenvalues of the covariance matrix to be included in the reduced data.', ... + 'Style','text', ... + 'Tag','StaticText1'); +e_first = uicontrol('Parent',hndl_win, ... + 'Units','normalized', ... + 'Callback',[ ... + 'f=round(str2num(get(gcbo, ''String'')));' ... + 'if (f < 1), f=1; end;' ... + 'l=str2num(get(findobj(''Tag'',''e_last''), ''String''));' ... + 'if (f > l), f=l; end;' ... + 'set(gcbo, ''String'', int2str(f));' ... + ], ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','right', ... + 'Position',[0.284831 0.0678168 0.12207 0.0542535], ... + 'Style','edit', ... + 'String', '1', ... + 'Tag','e_first'); +b = uicontrol('Parent',hndl_win, ... + 'Units','normalized', ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'HorizontalAlignment','left', ... + 'Position',[0.142415 0.0678168 0.12207 0.0542535], ... + 'String','Range from', ... + 'Style','text', ... + 'Tag','StaticText2'); +e_last = uicontrol('Parent',hndl_win, ... + 'Units','normalized', ... + 'Callback',[ ... + 'l=round(str2num(get(gcbo, ''String'')));' ... + 'lmax = get(gcbo, ''UserData'');' ... + 'if (l > lmax), l=lmax; fprintf([''The selected value was too large, or the selected eigenvalues were close to zero\n'']); end;' ... + 'f=str2num(get(findobj(''Tag'',''e_first''), ''String''));' ... + 'if (l < f), l=f; end;' ... + 'set(gcbo, ''String'', int2str(l));' ... + ], ... + 'BackgroundColor',[1 1 1], ... + 'HorizontalAlignment','right', ... + 'Position',[0.467936 0.0678168 0.12207 0.0542535], ... + 'Style','edit', ... + 'String', int2str(maxLastEig), ... + 'UserData', maxLastEig, ... + 'Tag','e_last'); +% in the first version oldDimension was used instead of +% maxLastEig, but since the program would automatically +% drop the eigenvalues afte maxLastEig... +b = uicontrol('Parent',hndl_win, ... + 'Units','normalized', ... + 'BackgroundColor',[0.701961 0.701961 0.701961], ... + 'HorizontalAlignment','left', ... + 'Position',[0.427246 0.0678168 0.0406901 0.0542535], ... + 'String','to', ... + 'Style','text', ... + 'Tag','StaticText3'); +b = uicontrol('Parent',hndl_win, ... + 'Units','normalized', ... + 'Callback','uiresume(gcbf)', ... + 'Position',[0.630697 0.0678168 0.12207 0.0542535], ... + 'String','OK', ... + 'Tag','Pushbutton1'); +b = uicontrol('Parent',hndl_win, ... + 'Units','normalized', ... + 'Callback',[ ... + 'gui_help(''pcamat'');' ... + ], ... + 'Position',[0.767008 0.0678168 0.12207 0.0542535], ... + 'String','Help', ... + 'Tag','Pushbutton2'); + + h_axes = axes('Position' ,[0.13 0.3 0.775 0.6]); + set(hndl_win, 'currentaxes',h_axes); + bar(eigenvalues); + title('Eigenvalues'); + + uiwait(hndl_win); + firstEig = str2num(get(e_first, 'String')); + lastEig = str2num(get(e_last, 'String')); + + % close the window + close(hndl_win); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% See if the user has reduced the dimension enought + +if lastEig > maxLastEig + lastEig = maxLastEig; + if b_verbose + fprintf('Dimension reduced to %d due to the singularity of covariance matrix\n',... + lastEig-firstEig+1); + end +else + % Reduce the dimensionality of the problem. + if b_verbose + if oldDimension == (lastEig - firstEig + 1) + fprintf ('Dimension not reduced.\n'); + else + fprintf ('Reducing dimension...\n'); + end + end +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Drop the smaller eigenvalues +if lastEig < oldDimension + lowerLimitValue = (eigenvalues(lastEig) + eigenvalues(lastEig + 1)) / 2; +else + lowerLimitValue = eigenvalues(oldDimension) - 1; +end + +lowerColumns = diag(D) > lowerLimitValue; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Drop the larger eigenvalues +if firstEig > 1 + higherLimitValue = (eigenvalues(firstEig - 1) + eigenvalues(firstEig)) / 2; +else + higherLimitValue = eigenvalues(1) + 1; +end +higherColumns = diag(D) < higherLimitValue; + +% Combine the results from above +selectedColumns = lowerColumns & higherColumns; + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% print some info for the user +if b_verbose + fprintf ('Selected [ %d ] dimensions.\n', sum (selectedColumns)); +end +if sum (selectedColumns) ~= (lastEig - firstEig + 1), + error ('Selected a wrong number of dimensions.'); +end + +if b_verbose + fprintf ('Smallest remaining (non-zero) eigenvalue [ %g ]\n', eigenvalues(lastEig)); + fprintf ('Largest remaining (non-zero) eigenvalue [ %g ]\n', eigenvalues(firstEig)); + fprintf ('Sum of removed eigenvalues [ %g ]\n', sum(diag(D) .* ... + (~selectedColumns))); +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Select the colums which correspond to the desired range +% of eigenvalues. +E = selcol(E, selectedColumns); +D = selcol(selcol(D, selectedColumns)', selectedColumns); + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Some more information +if b_verbose + sumAll=sum(eigenvalues); + sumUsed=sum(diag(D)); + retained = (sumUsed / sumAll) * 100; + fprintf('[ %g ] %% of (non-zero) eigenvalues retained.\n', retained); +end + + + + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +function newMatrix = selcol(oldMatrix, maskVector); + +% newMatrix = selcol(oldMatrix, maskVector); +% +% Selects the columns of the matrix that marked by one in the given vector. +% The maskVector is a column vector. + +% 15.3.1998 + +if size(maskVector, 1) ~= size(oldMatrix, 2), + error ('The mask vector and matrix are of uncompatible size.'); +end + +numTaken = 0; + +for i = 1 : size (maskVector, 1), + if maskVector(i, 1) == 1, + takingMask(1, numTaken + 1) = i; + numTaken = numTaken + 1; + end +end + +newMatrix = oldMatrix(:, takingMask); \ No newline at end of file diff --git a/FastICA_25/remmean.m b/FastICA_25/remmean.m new file mode 100644 index 0000000..1160b7a --- /dev/null +++ b/FastICA_25/remmean.m @@ -0,0 +1,15 @@ +function [newVectors, meanValue] = remmean(vectors); +%REMMEAN - remove the mean from vectors +% +% [newVectors, meanValue] = remmean(vectors); +% +% Removes the mean of row vectors. +% Returns the new vectors and the mean. +% +% This function is needed by FASTICA and FASTICAG + +% @(#)$Id: remmean.m,v 1.2 2003/04/05 14:23:58 jarmo Exp $ + +newVectors = zeros (size (vectors)); +meanValue = mean (vectors')'; +newVectors = vectors - meanValue * ones (1,size (vectors, 2)); diff --git a/FastICA_25/whitenv.m b/FastICA_25/whitenv.m new file mode 100644 index 0000000..5c1609c --- /dev/null +++ b/FastICA_25/whitenv.m @@ -0,0 +1,82 @@ +function [newVectors, whiteningMatrix, dewhiteningMatrix] = whitenv ... + (vectors, E, D, s_verbose); +%WHITENV - Whitenv vectors. +% +% [newVectors, whiteningMatrix, dewhiteningMatrix] = ... +% whitenv(vectors, E, D, verbose); +% +% Whitens the data (row vectors) and reduces dimension. Returns +% the whitened vectors (row vectors), whitening and dewhitening matrices. +% +% ARGUMENTS +% +% vectors Data in row vectors. +% E Eigenvector matrix from function 'pcamat' +% D Diagonal eigenvalue matrix from function 'pcamat' +% verbose Optional. Default is 'on' +% +% EXAMPLE +% [E, D] = pcamat(vectors); +% [nv, wm, dwm] = whitenv(vectors, E, D); +% +% +% This function is needed by FASTICA and FASTICAG +% +% See also PCAMAT + +% @(#)$Id: whitenv.m,v 1.3 2003/10/12 09:04:43 jarmo Exp $ + +% ======================================================== +% Default value for 'verbose' +if nargin < 4, s_verbose = 'on'; end + +% Check the optional parameter verbose; +switch lower(s_verbose) + case 'on' + b_verbose = 1; + case 'off' + b_verbose = 0; + otherwise + error(sprintf('Illegal value [ %s ] for parameter: ''verbose''\n', s_verbose)); +end + +% ======================================================== +% In some cases, rounding errors in Matlab cause negative +% eigenvalues (elements in the diagonal of D). Since it +% is difficult to know when this happens, it is difficult +% to correct it automatically. Therefore an error is +% signalled and the correction is left to the user. +if any (diag (D) < 0), + error (sprintf (['[ %d ] negative eigenvalues computed from the' ... + ' covariance matrix.\nThese are due to rounding' ... + ' errors in Matlab (the correct eigenvalues are\n' ... + 'probably very small).\nTo correct the situation,' ... + ' please reduce the number of dimensions in the' ... + ' data\nby using the ''lastEig'' argument in' ... + ' function FASTICA, or ''Reduce dim.'' button\nin' ... + ' the graphical user interface.'], ... + sum (diag (D) < 0))); +end + +% ======================================================== +% Calculate the whitening and dewhitening matrices (these handle +% dimensionality simultaneously). +whiteningMatrix = inv (sqrt (D)) * E'; +dewhiteningMatrix = E * sqrt (D); + +% Project to the eigenvectors of the covariance matrix. +% Whiten the samples and reduce dimension simultaneously. +if b_verbose, fprintf ('Whitening...\n'); end +newVectors = whiteningMatrix * vectors; + +% ======================================================== +% Just some security... +if ~isreal(newVectors) + error ('Whitened vectors have imaginary values.'); +end + +% Print some information to user +if b_verbose + fprintf ('Check: covariance differs from identity by [ %g ].\n', ... + max (max (abs (cov (newVectors', 1) - eye (size (newVectors, 1)))))); +end diff --git a/NP_ActivityAroundSpikes.m b/NP_ActivityAroundSpikes.m new file mode 100644 index 0000000..09e9798 --- /dev/null +++ b/NP_ActivityAroundSpikes.m @@ -0,0 +1,315 @@ +function NP_ActivityAroundSpikes(ROI, directory_raw, directory_out, varargin) +%NP_ACTIVITYAROUNDSPIKES +% This function is meant to help with finding an extracting a window of +% activity around spikes for comparison in a paper. This is achieved through +% a two pass process. First, videos are analyzed once to figure out traces +% patterns (using NP_ExtractROIs) and spikes (using NP_From_Raw_To_Traces). +% This is both done with donuts and without donuts. Those ROIs with a +% sufficient number of donut-spikes (specified by `min_donut_spikes`, which +% defaults to 7) are then used for the second stage. +% +% During the second stage, the system will reload the videos and extract +% frames in a window of time surrounding each spike for each ROI selected +% during the first stage. A center of mass image, as well as a mat file, +% are saved to the output directory (organized into subfolders for each +% ROI). +% +% There are a number of additional settings in the parameter section below +% for customizing the behavior. + +%% parameters +% video information +fs = 30; +skip_frames = 30; % first and last frames from each video that are discarded + +% selection details +spike_donut_threshold = 3; % standard deviation for detecting spikes +spike_all_threshold = 3; % standard deviations for detecting spikes +min_donut_spikes = 7; % only generate figures for ROIs that have at least this many donut spikes + +% what window to consider +window = [0.5 0.5]; % seconds before and after + +% what to save +save_mat = true; % save a MATLAB file with traces, spikes, and other info +save_image = true; % save an un-annotated mass image +save_image_with_annot = true; % save a mass image with a circle around the ROI +save_plot = true; % save a plot of all traces +save_video = true; % save the video for the time slice + +% other details +show_progress = true; % show a little progress bar +mask = '*.mat'; % mask for finding movies in the directory +debug = false; % open a window showing spike detection and other debugging + +% load custom parameters +nparams = length(varargin); +if 0 < mod(nparams, 2) + error('Parameters must be specified as parameter/value pairs'); +end +for i = 1:2:nparams + nm = lower(varargin{i}); + if ~exist(nm, 'var') + error('Invalid parameter: %s.', nm); + end + eval([nm ' = varargin{i+1};']); +end + +%% setup +% get list of files +files = dir(fullfile(directory_raw, mask)); +files = cellfun(@(x) fullfile(directory_raw, x), {files(:).name}, 'UniformOutput', false); +files_count = length(files); + +% convert window to samples +if isscalar(window) + window = window * [1 1]; +end +window = ceil(window * fs); + +% convert skip frames to beginning / end +if isscalar(skip_frames) + skip_frames = skip_frames * [1 1]; +end + +% open progress bar +if show_progress + h = waitbar(0, 'Extracting data...'); +end + +%% find ROIs of interest +% this is the first pass through the videos; loading the videos twice is +% pretty slow, but it maximizes the + +spikes_donut = cell(size(files)); % ROI * time +spikes_all = cell(size(files)); % ROI * time +traces_all = cell(size(files)); % ROI * time + +for i = 1:files_count + % load video (slow) + v = load(files{i}, 'video*'); + nms = fieldnames(v); + if 1 ~= length(nms) + warning('More than one variable in the video file. Skipping.'); + continue; + end + if isfield(v.(nms{1}), 'frames') + video = v.(nms{1}); + else + video = struct('frames', v.(nms{1})); + end + clear v; + + % convert to grayscale + if 3 == ndims(video.frames(1).cdata) && 3 == size(video.frames(1).cdata, 3) + video_gs = video_rgb2gray(cat(4, video.frames(:).cdata)); + video.frames = struct('cdata', squeeze(num2cell(video_gs, [1 2]))); + clear video_gs; + end + + % extract ROIs with donut + roi_trace = NP_ExtractROIs(video.frames((1 + skip_frames(1)):(end - skip_frames(2))), ROI, 1); + + % convert to spikes + [~, ~, roi_spikes] = NP_From_Raw_To_Traces({roi_trace}, spike_donut_threshold); + + % store spikes + spikes_donut{i} = squeeze(roi_spikes); + + % extract ROIs without donut + roi_trace = NP_ExtractROIs(video.frames((1 + skip_frames(1)):(end - skip_frames(2))), ROI, 0); + + % convert to spikes + [~, ~, roi_spikes] = NP_From_Raw_To_Traces({roi_trace}, spike_all_threshold); + + % store spikes + traces_all{i} = roi_trace; + spikes_all{i} = squeeze(roi_spikes); + + % clear video + clear video; + + % if debug + if debug + figure; + subplot(1, 3, 1); + plot_many(traces_all{i}'); + title(files{i}); + subplot(1, 3, 2); + plot_many(spikes_all{i}'); + title('All spikes'); + subplot(1, 3, 3); + plot_many(spikes_donut{i}'); + title('Donut spikes'); + end + + % update progress + if show_progress + waitbar(i / (2 * files_count)); + end +end + +%% identify ROIs of interest +donut_spikes_per_roi = sum(cat(2, spikes_donut{:}), 2); + +% rois of interest +rois_of_interest = donut_spikes_per_roi >= min_donut_spikes; +rois_of_interest = reshape(rois_of_interest, 1, []); % make row, better for iteration + +% make folders for each ROI +for i = find(rois_of_interest) + fprintf('ROI %d: %d donut spikes\n', i, donut_spikes_per_roi(i)); + if ~exist(fullfile(directory_out, num2str(i)), 'dir') + mkdir(directory_out, num2str(i)); + end +end + +%% using ROIs of interest, look through videos to find surrounding vehavior + +% reusable mesh for drawing rois +x = []; y = []; +video_width = 0; video_height = 0; + +for i = 1:files_count + % get spikes and traces for current video + cur_spikes = spikes_all{i}; + cur_traces = traces_all{i}; + + % skipped file + if isempty(cur_spikes) + continue; + end + + % has any spikes of interest? if not, skip + if ~any(any(cur_spikes(rois_of_interest, (1 + window(1)):(end - window(2))))) + continue; + end + + % load video (slow) + v = load(files{i}, 'video*'); + nms = fieldnames(v); + if 1 ~= length(nms) + warning('More than one variable in the video file. Skipping.'); + continue; + end + if isfield(v.(nms{1}), 'frames') + video = v.(nms{1}); + else + video = struct('frames', v.(nms{1})); + end + clear v; + + % convert to grayscale + if 3 == ndims(video.frames(1).cdata) && 3 == size(video.frames(1).cdata, 3) + video_gs = video_rgb2gray(cat(4, video.frames(:).cdata)); + video.frames = struct('cdata', squeeze(num2cell(video_gs, [1 2]))); + clear video_gs; + end + + % name + [~, name, ~] = fileparts(files{i}); + + % for each roi + for j = find(rois_of_interest) + % for each spike + for k = find(cur_spikes(j, :)) + % make sure window is available + if k < (1 + window(1)) + continue; + end + if k > (size(cur_spikes, 2) - window(2)) + continue; + end + + % get relevant frames + frames = cat(3, video.frames((skip_frames(1) + k - window(1)):(skip_frames(1) + k + window(2))).cdata); + % scaling greyscale + raw = video_adjust(frames, [0.5 0.999]); + + % extract traces + traces = cur_traces(:, (k - window(1)):(k + window(2))); + spikes = cur_spikes(:, (k - window(1)):(k + window(2))); + + % save plot + if save_plot + f = figure; + plot_many(((skip_frames(1) + k - window(1)):(skip_frames(1) + k + window(2))) ./ fs, traces'); + title(sprintf('%s; ROI %d', strrep(name, '_', '\_'), j)); + print(gcf, fullfile(directory_out, num2str(j), sprintf('%s_%d.png', name, k)), '-dpng', '-r300'); + close(f); + end + + % calculate mass image + cmap = jet(64); + % use this line to compress the colormap to show variation that + % is close in time (on a small spectrum of the colormap): + cmap = [repmat(cmap(1, :), 16, 1); cmap; repmat(cmap(end, :), 16, 1)]; + % then run NP_PixelMass + [im, im_mass, im_std] = NP_PixelMass(frames, 'cmap', cmap); + if save_image + imwrite(im, fullfile(directory_out, num2str(j), sprintf('%s_%d.jpg', name, k))); + end + + if save_image_with_annot + % check mesh grid + if size(frames, 1) ~= video_height || size(frames, 2) ~= video_width + video_height = size(frames, 1); + video_width = size(frames, 2); + [x, y] = meshgrid(1:video_width, 1:video_height); + end + + % stats + center = ROI.stats(j).Centroid; + radius2 = (ROI.stats(j).Diameter / 2) ^ 2; + + % calculate distance + distance = (x - center(1)) .^ 2 + (y - center(2)) .^ 2; + mask_space = distance > radius2 & distance < radius2 * 2; + im(repmat(mask_space, 1, 1, 3)) = 1; + imwrite(im, fullfile(directory_out, num2str(j), sprintf('%s_%d_self.jpg', name, k))); + end + + if save_video + % dff + dff = NP_Dff(frames); + + % draw spikes + d = false(size(spikes)); + d(j, :) = spikes(j, :); + dff2 = NP_DrawROIs(dff, ROI, d, fs); + + % write + video_write(fullfile(directory_out, num2str(j), sprintf('%s_%d_raw.mp4', name, k)), raw, fs); % black screen for sleep videos + %video_write(fullfile(directory_out, num2str(j), sprintf('%s_%d_dff.mp4', name, k)), dff, fs); + %video_write(fullfile(directory_out, num2str(j), sprintf('%s_%d_WithSpikes.mp4', name, k)), dff2, fs); + end + + if save_mat + % meta data for saving + roi = j; + file = files{i}; + frame = skip_frames(1) + k; + + % save matlab data + save(fullfile(directory_out, num2str(j), sprintf('%s_%d.mat', name, k)), ... + 'roi', 'file', 'frame', 'traces', 'spikes', 'im_mass', 'im_std'); + end + end + end + + % clear video + clear video; + + % update progress + if show_progress + waitbar((files_count + i) / (2 * files_count)); + end +end + +%% clean up +% close progress +if show_progress + close(h); +end + +end diff --git a/NP_ApplyICA.m b/NP_ApplyICA.m new file mode 100644 index 0000000..2131f4d --- /dev/null +++ b/NP_ApplyICA.m @@ -0,0 +1,27 @@ +function ica_sig = NP_ApplyICA(frames, separating, height, width) +%NP_APPLYICA Apply ICA separating matrix to video +% Like the NP_PerformICA, this resizes and unrolls the videos, but simply +% applies an existing separating matrix to extract the components. + +% turn into movie data +if isstruct(frames) + video_gs = cat(3, frames(:).cdata); +else + video_gs = frames; +end + +% convert to single +video_gs = im2single(video_gs); + +% resize +video_gs = imresize(video_gs, [height width]); + +% unroll (each row corresponds to a pixel, each column corresponds to a +% time step) +data = reshape(video_gs, [], size(video_gs, 3)); + +% use separating matrix to perform unmixing +ica_sig = separating * data; + +end + diff --git a/NP_Bs.m b/NP_Bs.m new file mode 100644 index 0000000..b186007 --- /dev/null +++ b/NP_Bs.m @@ -0,0 +1,67 @@ +function video_bs = NP_Bs(frames) + +% WALIII +% 09.05.15 +% adjusted for Sanne 10.06.15 + +% Nathan +% made more generic, separated from batching functionality 4/28/16 + +% This script first downsamples videos, then subtracts the background +% through disk filter blurring, then blows up video to normal size again +% for ROI selection later. +% It saves background subtracted videos in mat & avi format. +% It also motion-corrects the BS videos and the data matrix, and makes +% maximum projection images for ROI selection later. +% Motion correction not working + +%% VARIABLES: +downsample_factor = 1; %downsampling: 4; otherwise 1 +motion_correction = false; +use_gpu = gpuDeviceCount > 0; + +%% Downsample, subtract background and smooth +video_bs = cat(3, frames(:).cdata); + +if use_gpu + video_bs = gpuArray(video_bs); +end + +% downsampling: downsample_factor = 0.25; otherwise 1 +if downsample_factor ~= 1 + video_bs = imresize(video_bs, 1 / downsample_factor); +end + +% disk size for blurring to subtract from data for background subtraction; +filter_disk_blur = fspecial('disk', 50 / (downsample_factor ^ 2)); +bground = imfilter(video_bs, filter_disk_blur, 'replicate'); +video_bs = video_bs - bground; + +filter_disk_smooth = fspecial('disk', 1); % smoothing with a very small disk +video_bs = imfilter(video_bs, filter_disk_smooth); + +%% scale back to size after downsampling +if downsample_factor ~= 1 + video_bs = imresize(video_bs, downsample_factor); +end + +if use_gpu + video_bs = gather(video_bs); +end + +%% correct motion artifacts in movies +% Commented out for now - veeerrrry slow, sometimes even crashes +if motion_correction + error('Not yet supported. Must test.'); + + [optimizer, metric] = imregconfig('multimodal'); % Same device, but might have different brightness ranges + + for frameIter=1:(size(video_bs, 3)); + video_bs(:,:,frameIter)=imregister(video_bs(:, :, frameIter), video_bs(:,:,100), 'rigid', optimizer, metric); + end +end + +%% Rescale +video_bs = video_adjust(video_bs, [0.5 0.999]); + +end diff --git a/NP_Dff.m b/NP_Dff.m new file mode 100644 index 0000000..1773a7a --- /dev/null +++ b/NP_Dff.m @@ -0,0 +1,71 @@ +function video_dff = NP_Dff(frames, varargin) +%FS_DFF_NEW Generates delta f over f video +% When passed a video, this function calculates a delta f over f version +% of the video, which is useful for visualizing Calcium traces. This +% process is done in a few steps: +% +% 1. The video is smoothed over time (each frame is averaged with up to +% three neighboring frames) +% +% 2. A small gaussian filter is applied over the video (spatial +% smoothing). +% +% 3. A baseline image is calcualted using the 3rd percentile value for +% each pixel over time. The baseline image is gaussian filtered using a +% much larger filter (spatial smoothing). +% +% 4. The square of the baseline image is subtracted from the square of +% the pixel intensity (roughly delta f) and this is then divided by the +% baseline (roughly delta f over f). The square is used based on Will's +% feedback that it proves more reliable at suppressing low variance +% pixels. + +% parameters +filt_rad = 1; % gauss filter radius +filt_alpha = 1; % gauss filter alpha +per = 10; % baseline percentile (0 for min) +clim = [0.5 0.99]; % color range + +% load custom parameters +nparams = length(varargin); +if 0 < mod(nparams, 2) + error('Parameters must be specified as parameter/value pairs.'); +end +for i = 1:2:nparams + nm = lower(varargin{i}); + if ~exist(nm, 'var') + error('Invalid parameter: %s.', nm); + end + eval([nm ' = varargin{i+1};']); +end + +% turn into movie data +if isstruct(frames) + mov = cat(3, frames(:).cdata); +else + mov = frames; +end + +% smooth (use a [1/3 1/3 1/3] convolution along the third dimension) +mov = video_smooth(single(mov), 3); + +% Gaussian filter video +h = fspecial('gaussian', filt_rad, filt_alpha); +mov = imfilter(mov, h, 'replicate'); + +% calculate baseline using percentile and repeat over video +baseline = prctile(mov, per, 3); + +% use circular gaussian filter for baseline +h = fspecial('gaussian', 20, 40); +baseline = imfilter(baseline, h, 'replicate'); % filter baseline + +% calculate dff +video_dff = bsxfun(@minus, mov .^ 2, baseline .^ 2); +video_dff = bsxfun(@rdivide, video_dff, baseline); + +% get high and low percentiles +video_dff = video_adjust(video_dff, clim); + +end + diff --git a/NP_DrawROIs.m b/NP_DrawROIs.m new file mode 100644 index 0000000..9fbd1a4 --- /dev/null +++ b/NP_DrawROIs.m @@ -0,0 +1,95 @@ +function video_rgb = NP_DrawROIs(frames, roi, spike_data, Fs) +%DRAWROIS Annotate video with regions of interest at spikes +% For each spike in the spike data, the video will be annotated with a +% circe indicating the region of interest. This allows for visual +% inspection of the video to ensure that spike detection matches +% expectations. + +% default parameters +if ~exist('Fs', 'var') || isempty(Fs) + Fs = 30; +end + +% parameters used when drawing +draw_for = round(0.25 * Fs); % 0.25 seconds + +% examine inputs +roi_count = length(roi.stats); + +% generate output video +% concatenate all frames and convert to double) +if isstruct(frames) + video_gs = cat(3, frames(:).cdata); +else + video_gs = frames; +end +video_length = size(video_gs, 3); + +% check lengths +if size(spike_data, 1) ~= roi_count + error('Expecting %d regions in the spike data.', roi_count); +end +if size(spike_data, 2) ~= video_length + error('Expecting %d frames in the spike data.', video_length); +end + +% convert to RGB +video_r = reshape(video_gs, [], video_length); +video_g = video_r; +video_b = video_r; + +% get dimensions +video_height = size(video_gs, 1); +video_width = size(video_gs, 2); + +% get spikes to draw +[spike_roi, spike_tm] = find(spike_data); +spike_count = length(spike_roi); + +% helper variables +% empty frame... +[x, y] = meshgrid(1:video_width, 1:video_height); +% for calculating time indices +time_idx = 1:video_length; + +% colors... +colors = lines(roi_count); +if isa(video_gs, 'uint8') + colors = uint8(colors .* (256 - 1)); +elseif isa(video_gs, 'uint16') + colors = uint16(colors .* (256 * 256 - 1)); +elseif isa(video_gs, 'single') + colors = single(colors); +end + +clear video_gs; + +% for each spike... +for i = 1:spike_count + cur_roi = spike_roi(i); + + % stats + center = roi.stats(cur_roi).Centroid; + radius2 = (roi.stats(cur_roi).Diameter / 2) ^ 2; + + % calculate distance + distance = (x - center(1)) .^ 2 + (y - center(2)) .^ 2; + mask_space = distance > radius2 & distance < radius2 * 1.5; + + % concatenate mask over time + mask_time = time_idx >= spike_tm(i) & time_idx <= spike_tm(i) + draw_for; + + % set color + video_r(mask_space, mask_time) = colors(cur_roi, 1); + video_g(mask_space, mask_time) = colors(cur_roi, 2); + video_b(mask_space, mask_time) = colors(cur_roi, 3); +end + +% combine channels +video_rgb = cat(3, ... + reshape(video_r, video_height, video_width, 1, video_length), ... + reshape(video_g, video_height, video_width, 1, video_length), ... + reshape(video_b, video_height, video_width, 1, video_length)); + +end + diff --git a/NP_ExtractPlumes.m b/NP_ExtractPlumes.m new file mode 100644 index 0000000..b8488b0 --- /dev/null +++ b/NP_ExtractPlumes.m @@ -0,0 +1,111 @@ +function indices = NP_ExtractPlumes(frames, varargin) +%NP_EXTRACTPLUMES Find periods of video that may be plumes +% This uses mean intensity per frame to identify potential plumes in the +% video. The process involves a few key steps: +% +% 1. A window of 300 (customizable) frames is used to calculate a +% threshold based on the 90th percentile (customizable) intensity value. +% +% 2. A smoothed intensity curve is then compared to this threshold to +% determine plumes. +% +% 3. The plume period is then extended forward and backward to include +% any ramp up and ramp down period, based on the derivative of the +% smoothed intensity curve. +% +% The function returns indices that correspond with the start and stop of +% each plume found. Returned value `indices` is a n x 2 matrix, where +% each row corresponds to a single plume. + +% parameters +moving_avg_window = 300; % frames over which threshold is caculated +moving_avg_ptile = 90; % percentile used for threshold +min_duration = 5; % in frames + +% load custom parameters +nparams=length(varargin); +if 0 < mod(nparams, 2) + error('Parameters must be specified as parameter/value pairs'); +end +for i = 1:2:nparams + nm = lower(varargin{i}); + if ~exist(nm, 'var') + error('Invalid parameter: %s.', nm); + end + eval([nm ' = varargin{i+1};']); +end + +% turn into movie data +if isstruct(frames) + video = cat(3, frames(:).cdata); +else + video = frames; +end + +% calculate mean intensity +intensity = mean(reshape(video, [], size(video, 3))); + +% smooth intensity +smooth_intensity = sgolayfilt(intensity, 3, 41); + +% calculate threshold +col = (1:moving_avg_window)'; +row = 0:(size(video, 3) - moving_avg_window); +idx = bsxfun(@plus, col, row); +threshold = prctile(intensity(idx), moving_avg_ptile); +threshold = [threshold(1) * ones(1, ceil((size(video, 3) - length(threshold)) / 2)) threshold threshold(end) * ones(1, floor((size(video, 3) - length(threshold)) / 2))]; + +% % visualize +% t = 1:length(intensity); +% figure; plot(t, intensity, t, smooth_intensity, t, threshold); + +% find when smooth intensity is above threshold +above_threshold = (smooth_intensity > threshold); + +% expand periods when above threshold based on derivative +dx = [0 diff(smooth_intensity)]; + +% extend backwards +% as long as smoothed intensity is increasing +while true + should_include = (dx(1:(end-1)) > 0 & ~above_threshold(1:(end-1)) & above_threshold(2:end)); + if any(should_include) + above_threshold([should_include false]) = true; + else + break; + end +end + +% extend forwards +% as long as smoothed intensity is decreasing +while true + should_include = (dx(2:end) < 0 & ~above_threshold(2:end) & above_threshold(1:(end-1))); + if any(should_include) + above_threshold([false should_include]) = true; + else + break; + end +end + +% % plot periods above threshold +% t = 1:length(intensity); +% figure; scatter(t(above_threshold), intensity(above_threshold)); + +% based on: +% http://stackoverflow.com/questions/3274043/finding-islands-of-zeros-in-a-sequence + +% calculate differences +dsig = diff([0; above_threshold(:); 0]); +index_start = find(dsig > 0); +index_end = find(dsig < 0) - 1; +duration = index_end - index_start + 1; + +% threshold duration +index_string = (duration >= min_duration); +index_start = index_start(index_string); +index_end = index_end(index_string); + +% combine indices +indices = [index_start index_end]; + +end diff --git a/NP_ExtractROIs.m b/NP_ExtractROIs.m new file mode 100644 index 0000000..16e8cfd --- /dev/null +++ b/NP_ExtractROIs.m @@ -0,0 +1,72 @@ +function roi_ave = NP_ExtractROIs(frames, roi, donut) +%NP_EXTRACTROIS Extract regions of interest +% This function takes a video (`frames`) and a bunch of regions of +% interest (`roi`), and will extract and average trace for each ROI. +% +% Optionally, a `donut` multiplier can be specificied. If the donut is +% above zero, a donut (annulus) is created around the region of interest +% and subtracted from the region of interest time course. The variable +% donut specifices how many pixels should be in the donut. For example, +% if `donut` = 1, then the annulus will contain the same number of pixels +% as the region of interest. + +% default value is no donut +% use donut = 2 for roughtly equal number of pixels in donut and donut hole +if ~exist('donut', 'var') || isempty(donut) + donut = 0; +end + +% examine inputs +roi_count = length(roi.stats); + +% convert to grayscale video +if isstruct(frames) + video_gs = cat(3, frames(:).cdata); +else + video_gs = frames; +end +video_length = size(video_gs, 3); + +% get roi data + +% make grid (number each pixel of the video) +[x, y] = meshgrid(1:size(video_gs, 2), 1:size(video_gs, 1)); + +% allocate memory for return matrix (1 row per ROI, 1 column per frame) +roi_ave = zeros(roi_count, video_length); + +% reshape video to have one row per pixel +video_gs_r = reshape(video_gs, [], video_length); + +% for each region of interest... +for i = 1:roi_count + % get center and radius squared + center = roi.stats(i).Centroid; + radius2 = (roi.stats(i).Diameter / 2) ^ 2; + + % calculate distances between pixels and ROI center + d = (x - center(1)) .^ 2 + (y - center(2)) .^ 2; + + if 0 < donut + % has donut, should subtract it + % make masks representing donut and donut hole + mask_donut_hole = d < radius2; + mask_donut = d >= radius2 & d < (radius2 * (1 + donut)); + + % get donut and donut hole + ave_donut_hole = mean(video_gs_r(mask_donut_hole(:), :), 1); + ave_donut = mean(video_gs_r(mask_donut(:), :), 1); + + % subtract donut from donut hole + roi_ave(i, :) = ave_donut_hole - ave_donut; + else + % make mask + mask = d < radius2; + + % extract mean time series + roi_ave(i, :) = mean(video_gs_r(mask(:), :), 1); + end +end + +end + diff --git a/NP_From_Raw_To_Traces.m b/NP_From_Raw_To_Traces.m new file mode 100755 index 0000000..ffabd2e --- /dev/null +++ b/NP_From_Raw_To_Traces.m @@ -0,0 +1,211 @@ +function [Av_Data,Trace_Data,Spike_Data] = NP_From_Raw_To_Traces(aveRoiRaw,threshold,Fs,binSize) +% Created: 2015/12/11 at 24 Cummington, Boston +% Byron Price +% Updated: 2015/12/11 +% By: Byron Price +% This file will run through raw data of fluorescence traces and output +% detrended fluorescence traces, spike data, and summed spike data +% across ROIs (called avalanches). +% Updated: 2016/05/01 +% By: Nathan Perkins +% Eliminated non-linear fitting, consolidated spike detection, +% introduced more flexibility in spike detection criteria (including +% requiring consecutive moments above threshold) and support finding when +% the spike begins. +% +% INPUT: aveRoiRaw - the roi_ave.raw matrix from a single session +% FOUR OPTIONAL INPUTS +% threshold - z-score threshold (peaks in activity above this value +% are counted as spikes, default = 2 +% Fs - sampling frequency (Hz), default = 30 +% binSize - width of bins (secs), spikes are counted as having occurred +% within bins of a certain size, default = 1/Fs +% OUTPUT: Av_Data - number videos by number frames matrix of summed spike +% activity +% Trace_Data - number videos by number ROIs by number frames +% matrix of detrended fluorescence traces +% Spike_Data - number videos by number ROIs by number frames +% matrix of spike data (zeros and ones for each ROI +% indicating a spike in a bin) +% + +tic + +%OPTIONAL INPUTS +if nargin > 5 + error('Gardner:DataStream:TooManyInputs', ... + 'Requires at most 4 optional inputs'); +end + +% Fill in unset optional inputs. +switch nargin + case 1 + threshold = 3; + Fs = 30; + binSize = 1/Fs; + case 2 + Fs = 30; + binSize = 1/Fs; + case 3 + binSize = 1/Fs; +end + +% FIGURE OUT HOW MANY VIDEOS, ROIs, and FRAMES +alldata = aveRoiRaw; +numVideos = size(alldata,2); +numROIs = size(alldata{1},1); +numFrames = length(alldata{1,1}); +consecutive = 2; +find_start = true; + +% DETREND EACH ROI INDIVIDUALLY FOR EACH VIDEO +Trace_Data = zeros(numVideos,numROIs,numFrames); +for i = 1:numVideos + for j = 1:numROIs + [alldata{1,i}(j,:)] = Preprocessing(alldata{1,i}(j,:)); + end + Trace_Data(i,:,:) = alldata{1,i}(:,:); +end + +Detrended = toc + +% COUNT SPIKES AND SUM ACROSS ROIs IN A SINGLE RECORDING +Spike_Data = false(numVideos,numROIs,numFrames); +Av_Data = zeros(numVideos,numFrames); +for j=1:numVideos + binarySpikes = []; % will contain event data for all ROIs in + % a single recording + for k=1:numROIs + % detect calcium spikes + [~,Spikes] = Spike_Detector(squeeze(Trace_Data(j,k,:)),Fs,binSize,threshold,consecutive,find_start); + binarySpikes = [binarySpikes,Spikes]; + end + Spike_Data(j,:,:) = binarySpikes'; + sumSpikes = sum(binarySpikes,2); % add up spikes from each ROI + % into a single vector, this + % will be used to deterimine + % avalanche size + + Av_Data(j,:) = sumSpikes; + +end + +save('Spontaneous_Data.mat','Av_Data','Spike_Data','Trace_Data'); + +end + + + +function [timeSeries] = Preprocessing(timeSeries) +% Av_Preprocessing.m +% Detrend a time series and subtract out the mean +% Created:2015/10/21 at 24 Cummington, Boston +% Byron Price +% Updated: 2015/12/11 +% By: Byron Price +% INPUT: timeSeries - calcium imaging pixel intensities over time for a +% single ROI +% OUTPUT: timeSeries - detrended data + +% LINEAR REGRESSION TO SUBTRACT OUT BLEACHING +x = 1:1:length(timeSeries); +X = [ones(length(x),1) x']; +b = X\timeSeries'; +ycalc = X*b; + +timeSeries = (timeSeries'-ycalc)'; + +timeSeries = timeSeries./max(timeSeries); +end + +function [numBins,Spikes] = Spike_Detector(timeSeries,sampleFreq,binSize,threshold, consecutive, find_start) +%Avalanche.m +% Detect calcium spikes in imaging data for a single ROI. +% Created: 2015/09/30 at 24 Cummington, Boston +% Byron Price +% Updated: 2015/12/11 +% By: Byron Price +% Updated: 2016/05/01 +% By: Nathan Perkins +% +% REFERENCE: Klaus, Plenz 2011 Statistical Analyses Support Power Law ... +% Ribeiro, Copelli et al. 2010 Spike Avalanches Exhibit ... +% +% INPUT: timeSeries - change in activity over time for a single ROI in +% units given by T = 1/Fs ... Fs = sampling frequency +% sampleFreq - sampling frequency, Hz +% binSize - width of bin (seconds) +% Spikes are counted as having occurred within a given +% bin if the activity of that bin is above "threshold" +% threshold - zscore threshold (1.5, 2 etc. standard deviations +% above the mean) for decision: above threshold = activity +% forms part of an avalanche +% consecutive - number of consecutive timesteps above threshold +% required to count as spike +% find_start - whether or not to find the start +% OUTPUT: numBins - given the binSize and the length of the recording, +% numBins = (total # frames) / (# frames / bin) +% Spikes - a vector containing either a 0 or a 1, 1 being an +% spike of activity within that bin, 0 otherwise + +T = 1/sampleFreq; % period for a single frame +framesPerBin = round(binSize/T); + + +times = 1:framesPerBin:length(timeSeries); +numBins = length(times); %number of bins, based on the + % length of the data and bin size (secs) + +% timeSeries = timeSeries./max(timeSeries); +stdActivity = std(timeSeries); + +% SPIKE DETECTION + +Spikes = false(size(timeSeries)); + +% the trace was already divided by its maximum value, there are a few steps to being +% counted as a calcium spike: + +% 1) have value greater than `threshold` standard deviations above mean +% (defaults to 2 standard deviations) +above_threshold = (timeSeries ./ stdActivity) > threshold; + +% calculate deltas +timeSeriesDelta = [0; diff(timeSeries)]; + +% find starts of spikes +start_above_threshold = above_threshold & [true; ~above_threshold(1:(end-1))]; +for j = find(start_above_threshold') + % find length of time above threshold + l = find(~above_threshold(j:end), 1); + if isempty(l) + % no moment below threshold? remainder of spike train is above threshold + l = 1 + length(above_threshold) - j; + else + l = l - 1; + end + + % 2) require more than `consecutive` moments above the threshold + if l < consecutive + continue; + end + + % 3) find the local maximum + [~, spike_peak] = max(timeSeries(j:(j + l - 1))); + spike_peak = spike_peak + j - 1; + + % 4) step back to "start" of spike + if find_start + spike_start = spike_peak; + while spike_start > 1 && timeSeriesDelta(spike_start - 1) >= 0 + spike_start = spike_start - 1; + end + Spikes(spike_start) = true; + else + Spikes(spike_peak) = true; + end +end + +end + + diff --git a/NP_PerformICA.m b/NP_PerformICA.m new file mode 100644 index 0000000..df5c34b --- /dev/null +++ b/NP_PerformICA.m @@ -0,0 +1,60 @@ +function [ica_sig, mixing, separating, height, width] = NP_PerformICA(frames, varargin) +%NP_PERFORMICA Perform indepdent component analysis +% This function performs independent component analysis on a video. It +% will first resize the video to a more managable size (by default, 1/4 +% the width and height). It then unfurls the video and uses the FastICA +% algorithm. The FastICA algorithm will reduce the dimensionality using +% principal component alaysis to get a lower dimensional space (default +% 100 dimensions) and will then extract independent components (by +% default, the first 25). +% +% Mostly this function serves as a nice wrapper around the FastICA +% algorithm, handling video resizing and unrolling. + +% parameters +resize_factor = 4; +eig_components = 100; +ica_components = 25; + +% load custom parameters +nparams=length(varargin); +if 0 < mod(nparams, 2) + error('Parameters must be specified as parameter/value pairs'); +end +for i = 1:2:nparams + nm = lower(varargin{i}); + if ~exist(nm, 'var') + error('Invalid parameter: %s.', nm); + end + eval([nm ' = varargin{i+1};']); +end + +% check parameters +if ica_components > eig_components + error('There must be more PCA components than ICA components.'); +end + +% turn into movie data +if isstruct(frames) + video_gs = cat(3, frames(:).cdata); +else + video_gs = frames; +end + +% convert to single +video_gs = im2single(video_gs); + +% resize +video_gs = imresize(video_gs, 1 / resize_factor); +height = size(video_gs, 1); +width = size(video_gs, 2); + +% unroll (each row corresponds to a pixel, each column corresponds to a +% time step) +data = reshape(video_gs, [], size(video_gs, 3)); + +% perform pca +[ica_sig, mixing, separating] = fastica(data, 'lastEig', eig_components, 'numOfIC', ica_components); + +end + diff --git a/NP_PixelMass.m b/NP_PixelMass.m new file mode 100644 index 0000000..b32aa31 --- /dev/null +++ b/NP_PixelMass.m @@ -0,0 +1,95 @@ +function [img_comp, mass_norm, std_proj_norm] = NP_PixelMass(video, varargin) +%NP_PIXELMASS Calculates the center of mass for each pixel over time +% This function takes a (raw) video, performs basic background +% subtraction on it, then calculates the center of mass for each pixel +% over time. This was adapted from Will's FS_plot_allpxs function. The +% function returns several variables for showing related data: +% +% If you call the function without any outputs, then it will display the +% results in a new figure window. +% +% The first output, `img_comp`, is a RGB image showing the center of mass +% for those pixels with a large std deviation. +% +% The second output, `mass_norm` is the normalized center of mass for +% each pixel. +% +% The third output, `std_proj_norm` is normalized standard deviation for +% each pixel, used to highlight those pixels with activity of note. +% +% (The `img_comp` is a composite of the `mass_norm` +% colored based on the jet colormap and the `std_proj_norm` as an alpha +% channel.) + +% parameters +filt_rad = 20; % gauss filter radius +filt_alpha = 30; % gauss filter alpha +lims = 3; % contrast prctile limits (i.e. clipping limits lims 1-lims) +cmap = jet(64); +per = 0; % baseline percentile (0 for min) + +% load custom parameters +nparams=length(varargin); +if 0 < mod(nparams, 2) + error('Parameters must be specified as parameter/value pairs'); +end +for i = 1:2:nparams + nm = lower(varargin{i}); + if ~exist(nm, 'var') + error('Invalid parameter: %s.', nm); + end + eval([nm ' = varargin{i+1};']); +end + +% check type +if ~isa(video, 'double') + video = mat2gray(video); +end + +% get size +[sz_rows, sz_columns, sz_frames] = size(video); + +% filter +h = fspecial('gaussian', filt_rad, filt_alpha); +video = imfilter(video, h, 'replicate'); + +% calculate baseline using percentile and repeat over video +baseline = prctile(video, per, 3); + +% calculate dff +video_dff = bsxfun(@minus, video .^ 2, baseline .^ 2); +video_dff = bsxfun(@rdivide, video_dff, baseline); + +% figure out center of max +com_idx = reshape(1:sz_frames, 1, 1, sz_frames); +com_idx = repmat(com_idx, sz_rows, sz_columns, 1); + +% calculate mass +mass = sum(video_dff, 3); +mass = sum(video_dff .* com_idx, 3) ./ mass; + +% normalize +mass_norm = mat2gray(mass, [1 sz_frames]); + +% convert to color indices +idx_img = round(mass_norm .* size(cmap, 1)); +img = ind2rgb(idx_img, cmap); + +% calculate std dev projection +std_proj = std(video_dff, [], 3); + +% normalize std projection +clims = prctile(std_proj(:), [lims 100 - lims]); +std_proj_norm = mat2gray(std_proj, clims); + +% make composite image +img_comp = img .* repmat(std_proj_norm, 1, 1, 3); + +if nargout == 0 + figure; + imshow(img_comp); + colormap(cmap); colorbar; +end + +end + diff --git a/NP_RoiAverages.m b/NP_RoiAverages.m new file mode 100644 index 0000000..da34542 --- /dev/null +++ b/NP_RoiAverages.m @@ -0,0 +1,94 @@ +function [roi_ave] = NP_RoiAverages(ROI,varargin) +% ROIS is a cell array of image indices returned by FS_image_roi + +% VARIABLES +ave_fs=30; % frame rate +duration=30; % movie duration in seconds +resize = 1; +colors=eval(['winter(' num2str(length(ROI.coordinates)) ')']); +sono_colormap='hot'; +save_dir='roi'; +template=[]; +donut = 1; % donut 0 or 1 + +%% first convert ROIS to row and column indices + +if resize~=1 + disp(['Adjusting ROIs for resizing by factor ' num2str(resize)]); + + for VideoIter=1:length(ROI.coordinates) + ROI.coordinates{VideoIter}=round(ROI.coordinates{VideoIter}.*resize); + end +end + +mkdir(save_dir); +mov_listing=dir(fullfile(pwd,'*.mat')); +mov_listing={mov_listing(:).name}; + +to_del=[]; +for VideoIter=1:length(mov_listing) + if strcmp(mov_listing{VideoIter},'dff_data.mat') + to_del=VideoIter; + end +end +mov_listing(to_del)=[]; + +%% Make matrix for video data (mov_data) +% Here, to calculate matrix size; below for data when looping through +% videos +load(fullfile(pwd,mov_listing{1}),'video'); +mov_data_temp = video.frames; +for VideoIter = 1:length(mov_data_temp) + mov_data(:,:,VideoIter) = mov_data_temp(VideoIter).cdata; +end +mov_data = double(mov_data); + +[rows,columns,frames]=size(mov_data); + +t = 1/ave_fs % seconds/frame +ave_time = (t):(t):(duration); +number_of_frames = length(ave_time) +roi_ave.raw={}; + +clear mov_data % to allow looping through each video below + +%% loop through videos, extract frames +disp('Looping through each video...'); +Videos=length(mov_listing); +for VideoIter=1:Videos + disp(['Processing video ' num2str(VideoIter) ' of ' num2str(length(mov_listing))]); + load(fullfile(pwd,mov_listing{VideoIter}),'video'); + mov_data_temp = video.frames; + + %% loop through frames, extract row and column values + for FrameIter = 1:length(mov_data_temp) + mov_data(:,:,FrameIter) = mov_data_temp(FrameIter).cdata(:,:); % mov_data=x512,y512,frameiter + end + mov_data = double(mov_data); + + %% + [~,file,~]=fileparts(mov_listing{VideoIter}); % [path,file,extension] + save_file=[ file '_roi' ]; + + [~,~,frames] = size(mov_data); %[rows,columns,frames] + roi_n = length(ROI.coordinates); + roi_data = zeros(roi_n,frames); + + %% extract mean values per frame in each ROI circle + disp('Computing ROI averages...'); + + [nblanks formatstring] = fb_progressbar(100); + fprintf(1,['Progress: ' blanks(nblanks)]); + + roi_data = NP_ExtractROIs(mov_data, ROI, donut); + + fprintf(1,'\n'); + +%% Save files + roi_ave.raw{VideoIter}=(roi_data); + roi_ave.filename{VideoIter}=mov_listing{VideoIter}; + roi_ave.t=ave_time; + save(fullfile(save_dir,['ave_roi.mat']),'roi_ave'); + disp('Generating roi_ave matrix...'); + +end \ No newline at end of file diff --git a/SM_ActivityAroundSpikes.m b/SM_ActivityAroundSpikes.m new file mode 100644 index 0000000..76de7a8 --- /dev/null +++ b/SM_ActivityAroundSpikes.m @@ -0,0 +1,279 @@ +function SM_ActivityAroundSpikes(ROI, directory_raw, directory_out, varargin) +%NP_ACTIVITYAROUNDSPIKES +% This function is meant to help with finding an extracting a window of +% activity around spikes for comparison in a paper. This is achieved through +% a two pass process. First, videos are analyzed once to figure out traces +% patterns (using NP_ExtractROIs) and spikes (using NP_From_Raw_To_Traces). +% This is both done with donuts and without donuts. Those ROIs with a +% sufficient number of donut-spikes (specified by `min_donut_spikes`, which +% defaults to 7) are then used for the second stage. +% +% During the second stage, the system will reload the videos and extract +% frames in a window of time surrounding each spike for each ROI selected +% during the first stage. A center of mass image, as well as a mat file, +% are saved to the output directory (organized into subfolders for each +% ROI). +% +% There are a number of additional settings in the parameter section below +% for customizing the behavior. + +%% parameters +% video information +fs = 30; +skip_frames = 30; % first and last frames from each video that are discarded + +% selection detailsSM +spike_donut_threshold = 3; % standard deviation for detecting spikes +spike_all_threshold = 3; % standard deviations for detecting spikes +min_donut_spikes = 7; % only generate figures for ROIs that have at least this many donut spikes + +% what window to consider +window = [0.5 0.5]; % seconds before and after + +% what to save +save_mat = true; % save a MATLAB file with traces, spikes, and other info +save_image = true; % save an un-annotated mass image +save_image_with_annot = true; % save a mass image with a circle around the ROI +save_plot = true; % save a plot of all traces +save_video = true; % save the video for the time slice + +% other details +show_progress = true; % show a little progress bar +mask = '*.mat'; % mask for finding movies in the directory +debug = false; % open a window showing spike detection and other debugging + +% load custom parameters +nparams = length(varargin); +if 0 < mod(nparams, 2) + error('Parameters must be specified as parameter/value pairs'); +end +for i = 1:2:nparams + nm = lower(varargin{i}); + if ~exist(nm, 'var') + error('Invalid parameter: %s.', nm); + end + eval([nm ' = varargin{i+1};']); +end + +%% setup +% get list of files +files = dir(fullfile(directory_raw, mask)); +files = cellfun(@(x) fullfile(directory_raw, x), {files(:).name}, 'UniformOutput', false); +files_count = length(files); + +% convert window to samples +if isscalar(window) + window = window * [1 1]; +end +window = ceil(window * fs); + +% convert skip frames to beginning / end +if isscalar(skip_frames) + skip_frames = skip_frames * [1 1]; +end + +% open progress bar +if show_progress + h = waitbar(0, 'Extracting data...'); +end + +%% find ROIs of interest +% this is the first pass through the videos; loading the videos twice is +% pretty slow, but it maximizes the + +spikes_donut = cell(size(files)); % ROI * time +spikes_all = cell(size(files)); % ROI * time +traces_all = cell(size(files)); % ROI * time + +for i = 1:files_count + % load video (slow) + video = load(files{i}, 'video*'); + + % extract ROIs with donut + roi_trace = NP_ExtractROIs(video.video(:,:,(1 + skip_frames(1)):(end - skip_frames(2))), ROI, 1); + + % convert to spikes + [~, ~, roi_spikes] = NP_From_Raw_To_Traces({roi_trace}, spike_donut_threshold); + + % store spikes + spikes_donut{i} = squeeze(roi_spikes); + + % extract ROIs without donut + roi_trace = NP_ExtractROIs(video.video(:,:,(1 + skip_frames(1)):(end - skip_frames(2))), ROI, 0); + + % convert to spikes + [~, ~, roi_spikes] = NP_From_Raw_To_Traces({roi_trace}, spike_all_threshold); + + % store spikes + traces_all{i} = roi_trace; + spikes_all{i} = squeeze(roi_spikes); + + % clear video + clear video; + + % if debug + if debug + figure; + subplot(1, 3, 1); + plot_many(traces_all{i}'); + title(files{i}); + subplot(1, 3, 2); + plot_many(spikes_all{i}'); + title('All spikes'); + subplot(1, 3, 3); + plot_many(spikes_donut{i}'); + title('Donut spikes'); + end + + % update progress + if show_progress + waitbar(i / (2 * files_count)); + end +end + +%% identify ROIs of interest +donut_spikes_per_roi = sum(cat(2, spikes_donut{:}), 2); + +% rois of interest +rois_of_interest = donut_spikes_per_roi >= min_donut_spikes; +rois_of_interest = reshape(rois_of_interest, 1, []); % make row, better for iteration + +% make folders for each ROI +for i = find(rois_of_interest) + fprintf('ROI %d: %d donut spikes\n', i, donut_spikes_per_roi(i)); + if ~exist(fullfile(directory_out, num2str(i)), 'dir') + mkdir(directory_out, num2str(i)); + end +end + +%% using ROIs of interest, look through videos to find surrounding vehavior + +% reusable mesh for drawing rois +x = []; y = []; +video_width = 0; video_height = 0; + +for i = 1:files_count + % get spikes and traces for current video + cur_spikes = spikes_all{i}; + cur_traces = traces_all{i}; + + % skipped file + if isempty(cur_spikes) + continue; + end + + % has any spikes of interest? if not, skip + if ~any(any(cur_spikes(rois_of_interest, (1 + window(1)):(end - window(2))))) + continue; + end + + % load video (slow) + video = load(files{i}, 'video*'); + + % name + [~, name, ~] = fileparts(files{i}); + + % for each roi + for j = find(rois_of_interest) + % for each spike + for k = find(cur_spikes(j, :)) + % make sure window is available + if k < (1 + window(1)) + continue; + end + if k > (size(cur_spikes, 2) - window(2)) + continue; + end + + % get relevant frames + frames = video.video(:,:,((skip_frames(1) + k - window(1)):(skip_frames(1) + k + window(2)))); + % NO scaling + raw = video_adjust(frames, [0.5 0.999]); + + % extract traces + traces = cur_traces(:, (k - window(1)):(k + window(2))); + spikes = cur_spikes(:, (k - window(1)):(k + window(2))); + + % save plot + if save_plot + f = figure; + plot_many(((skip_frames(1) + k - window(1)):(skip_frames(1) + k + window(2))) ./ fs, traces'); + title(sprintf('%s; ROI %d', strrep(name, '_', '\_'), j)); + print(gcf, fullfile(directory_out, num2str(j), sprintf('%s_%d.png', name, k)), '-dpng', '-r300'); + close(f); + end + + % calculate mass image + cmap = jet(64); + % use this line to compress the colormap to show variation that + % is close in time (on a small spectrum of the colormap): + cmap = [repmat(cmap(1, :), 16, 1); cmap; repmat(cmap(end, :), 16, 1)]; + % then run NP_PixelMass + [im, im_mass, im_std] = NP_PixelMass(frames, 'cmap', cmap); + if save_image + imwrite(im, fullfile(directory_out, num2str(j), sprintf('%s_%d.jpg', name, k))); + end + + if save_image_with_annot + % check mesh grid + if size(frames, 1) ~= video_height || size(frames, 2) ~= video_width + video_height = size(frames, 1); + video_width = size(frames, 2); + [x, y] = meshgrid(1:video_width, 1:video_height); + end + + % stats + center = ROI.stats(j).Centroid; + radius2 = (ROI.stats(j).Diameter / 2) ^ 2; + + % calculate distance + distance = (x - center(1)) .^ 2 + (y - center(2)) .^ 2; + mask_space = distance > radius2 & distance < radius2 * 2; + im(repmat(mask_space, 1, 1, 3)) = 1; + imwrite(im, fullfile(directory_out, num2str(j), sprintf('%s_%d_self.jpg', name, k))); + end + + if save_video + % dff + dff = NP_Dff(frames); + + % draw spikes + d = false(size(spikes)); + d(j, :) = spikes(j, :); + dff2 = NP_DrawROIs(frames, ROI, d, fs); + + % write + video_write(fullfile(directory_out, num2str(j), sprintf('%s_%d_raw.mp4', name, k)), raw, fs); % black screen for sleep videos + %video_write(fullfile(directory_out, num2str(j), sprintf('%s_%d_dff.mp4', name, k)), dff, fs); + video_write(fullfile(directory_out, num2str(j), sprintf('%s_%d_WithSpikes.mp4', name, k)), dff2, fs); + end + + if save_mat + % meta data for saving + roi = j; + file = files{i}; + frame = skip_frames(1) + k; + + % save matlab data + save(fullfile(directory_out, num2str(j), sprintf('%s_%d.mat', name, k)), ... + 'roi', 'file', 'frame', 'traces', 'spikes', 'im_mass', 'im_std'); + end + end + end + + % clear video + clear video; + + % update progress + if show_progress + waitbar((files_count + i) / (2 * files_count)); + end +end + +%% clean up +% close progress +if show_progress + close(h); +end + +end diff --git a/SM_BatchBS.m b/SM_BatchBS.m index d21d0d2..b93003b 100755 --- a/SM_BatchBS.m +++ b/SM_BatchBS.m @@ -13,7 +13,7 @@ % Motion correction not working %% VARIABLES: -DSFactor = 4; %downsampling: 4; otherwise 1 +DSFactor = 1; %downsampling: 4; otherwise 1 mat_dir = 'BS_MOVIES'; %% Make DFF_MOVIES folder @@ -35,6 +35,7 @@ %% Loop through videos for videoIter = 1:length(mov_listing); + tic [~,file,~] = fileparts(mov_listing{videoIter}); load(fullfile(DIR,mov_listing{videoIter}),'video'); MaxImages = zeros(512,512,length(video.frames)); % preallocate matrix @@ -59,6 +60,8 @@ clear video.frames; % so that after this loop, the next video can % be read; mov.data matrix = videoframes X, Y, frames + ReadInAndPrepareTime = toc + %% Downsample, subtract background and smooth for frameIter = 1:(length(mov_data)); mov_data_16bit(:,:,frameIter) = uint16(mov_data(frameIter).cdata/256); @@ -75,6 +78,8 @@ DiskSmooth = fspecial('disk',1); % smoothing with a very small disk mov_data_BS = imfilter(mov_data_BS,DiskSmooth); + DownsampleSmoothTime = toc + %% Calculating reference frame for imregister (100th frame) LinKatOne = 1; for u = 50:55; % take y-lines in the middle of the downsized image @@ -98,20 +103,20 @@ %% correct motion artifacts in movies % Commented out for now - veeerrrry slow, sometimes even crashes -% [optimizer, metric] = imregconfig('multimodal'); % Same device, but might have different brightness ranges -% -% startMotionCorr = toc -% -% for frameIter=1:(size(mov_data_BS,3)); -% mov_data_BS_MC(:,:,frameIter)=imregister(mov_data_BS(:,:,frameIter),mov_data_BS(:,:,100),'rigid',optimizer,metric); -% -% figure(1); -% colormap(bone); -% image(mov_data_BS_MC(:,:,frameIter),'CDataMapping','scaled'); -% caxis([double(L),double(H)]); -% set(gca,'ydir','reverse'); % Otherwise the y-axis would be flipped -% writeVideo(vidObj, getframe(gca)); -% end + [optimizer, metric] = imregconfig('multimodal'); % Same device, but might have different brightness ranges + + StartMotionCorr = toc + + for frameIter=1:(size(mov_data_BS,3)); + mov_data_BS_MC(:,:,frameIter)=imregister(mov_data_BS(:,:,frameIter),mov_data_BS(:,:,100),'rigid',optimizer,metric); + + figure(1); + colormap(bone); + image(mov_data_BS_MC(:,:,frameIter),'CDataMapping','scaled'); + caxis([double(L),double(H)]); + set(gca,'ydir','reverse'); % Otherwise the y-axis would be flipped + writeVideo(vidObj, getframe(gca)); + end close(gcf); % gcf = get current figure close(vidObj); @@ -134,6 +139,7 @@ end save(save_filename,'video','-v7.3'); + MovieProcessingTime = toc end %% create maximum projection images with corrected alignment diff --git a/SM_BatchDFFBS_MoviesWithSpikes.m b/SM_BatchDFFBS_MoviesWithSpikes.m new file mode 100644 index 0000000..42e9d65 --- /dev/null +++ b/SM_BatchDFFBS_MoviesWithSpikes.m @@ -0,0 +1,54 @@ +function SM_BatchDFFBS_MoviesWithSpikes(DIR) + +% WALIII +% 09.05.15 +% adjusted for Sanne 10.06.15 + +% This script first downsamples videos, then subtracts the background +% through disk filter blurring, then blows up video to normal size again +% for ROI selection later. +% It saves background subtracted videos in mat & avi format. +% It also motion-corrects the BS videos and the data matrix, and makes +% maximum projection images for ROI selection later. +% Motion correction not working + +%% VARIABLES: +mat_dir = 'NewDFFBS_Movies_WithSpikes'; + +%% Make DFF_MOVIES folder +if exist(mat_dir,'dir'); + rmdir(mat_dir,'s'); % remove folder with subfolders +end +mkdir(mat_dir); +if nargin<1 | isempty(DIR); + DIR=pwd; +end + +%% Read all videos (in .mat format) and ROI and Spike_Data matrices +mov_listing = dir(fullfile(DIR,'*.mat')); +mov_listing = {mov_listing(:).name} % reports which movies it found + +load('roi/Spontaneous_Data.mat'); +load('image_roi/roi_data_image.mat'); + + +%% Loop through videos and make dff videos with ROIs indicating spikes +for videoIter = 1:length(mov_listing); + tic + [~,file,~] = fileparts(mov_listing{videoIter}); + load(fullfile(DIR,mov_listing{videoIter}),'video'); + + % make dff + video_dff = NP_Dff(video.frames(30:end-30)); + + % draw rois + video_rgb = NP_DrawROIs(video_dff, ROI, squeeze(Spike_Data(videoIter, :, :))); + + % save + save_filename = [ fullfile(mat_dir,file) '.avi' ]; + video_write(save_filename, video_rgb, 30); + +end + +end + diff --git a/SM_BatchMoCo.m b/SM_BatchMoCo.m new file mode 100644 index 0000000..fe1e800 --- /dev/null +++ b/SM_BatchMoCo.m @@ -0,0 +1,52 @@ +function [] = SM_BatchMoCo(DIR) + +mat_dir = 'MoCo_MOVIES'; % MoCo = MotionCorrection + +%% Make MoCo_MOVIES folder +if exist(mat_dir,'dir'); + rmdir(mat_dir,'s'); % remove folder with subfolders +end +mkdir(mat_dir); +if nargin<1 | isempty(DIR); + DIR=pwd; +end + +%% Read all videos (in .mat format) +mov_listing = dir(fullfile(DIR,'*.mat')); +mov_listing = {mov_listing(:).name} % reports which movies it found + +%% Loop through videos +for videoIter = 1:length(mov_listing); + [~,file,~] = fileparts(mov_listing{videoIter}); + load(fullfile(DIR,mov_listing{videoIter}),'video'); + mov_data = zeros(512,512,length(video.frames)); % preallocate matrix + save_filename = [ fullfile(mat_dir,file) ]; + save_filename2 = [ fullfile(mat_dir,file) '.avi']; + + mov_data2 = video.frames; + for frameIter = 1:(length(mov_data2)); + mov_data(:,:,frameIter) = uint16(mov_data2(frameIter).cdata); + end + + mov_data = mat2gray(mov_data); + %% Run DFT-based subpixel alignment for motion correction: + + % https://www.osapublishing.org/ol/abstract.cfm?uri=ol-33-2-156 + % Efficient subpixel image registration algorithms + % Manuel Guizar-Sicairos, Samuel T. Thurman, and James R. Fienup + + video_reg = video_register(mov_data); + + clear('mov_data','mov_data2') + + % fix any out of bound values due to video registration + video_reg(video_reg > 1) = 1; + video_reg(video_reg < 0) = 0; + + % write video: + video_write(save_filename2, video_reg, 30); + + % save mat file: + video_reg = im2uint16(video_reg); + save(save_filename,'video_reg','-v7.3'); +end diff --git a/SM_BatchMoCo_clippedmovies.m b/SM_BatchMoCo_clippedmovies.m new file mode 100644 index 0000000..d77f6a9 --- /dev/null +++ b/SM_BatchMoCo_clippedmovies.m @@ -0,0 +1,49 @@ +function [] = SM_BatchMoCo(DIR) + +mat_dir = 'MoCo_MOVIES'; % MoCo = MotionCorrection + +%% Make MoCo_MOVIES folder +if exist(mat_dir,'dir'); + rmdir(mat_dir,'s'); % remove folder with subfolders +end +mkdir(mat_dir); +if nargin<1 | isempty(DIR); + DIR=pwd; +end + +%% Read all videos (in .mat format) +mov_listing = dir(fullfile(DIR,'*.mat')); +mov_listing = {mov_listing(:).name} % reports which movies it found + +%% Loop through videos +for videoIter = 1:length(mov_listing); + [~,file,~] = fileparts(mov_listing{videoIter}); + v = load(fullfile(DIR,mov_listing{videoIter}),'video*'); + fn = fieldnames(v); + video = v.(fn{1}); + clear v; + + save_filename = [ fullfile(mat_dir,file) ]; + save_filename2 = [ fullfile(mat_dir,file) '.avi']; + mov_data = cat(3,video(:).cdata); + mov_data = mat2gray(mov_data); + + %% Run DFT-based subpixel alignment for motion correction: + + % https://www.osapublishing.org/ol/abstract.cfm?uri=ol-33-2-156 + % Efficient subpixel image registration algorithms + % Manuel Guizar-Sicairos, Samuel T. Thurman, and James R. Fienup + + video_reg = video_register(mov_data); + + % fix any out of bound values due to video registration + video_reg(video_reg > 1) = 1; + video_reg(video_reg < 0) = 0; + + % write video: + video_write(save_filename2, video_reg, 30); + + % save mat file: + video_reg = im2uint16(video_reg); + save(save_filename,'video_reg','-v7.3'); +end diff --git a/SM_BurstCombStats.m b/SM_BurstCombStats.m new file mode 100644 index 0000000..9051193 --- /dev/null +++ b/SM_BurstCombStats.m @@ -0,0 +1,74 @@ +%% Make BurstingStats folder: +mat_dir = 'CombinedBurstingStats'; +if exist(mat_dir,'dir'); + rmdir(mat_dir,'s'); +end +mkdir(mat_dir); +DIR=pwd; + +%% Read in all datafiles: +mov_listing = dir(fullfile(DIR,'Bursting*')); +mov_listing = {mov_listing(:).name}; + +BurstsTotal = []; +IntervalsTotal = []; + +[nblanks formatstring]=progressbar(length(mov_listing)); +fprintf(1,['Progress: ' blanks(nblanks) ]); + +%% Loop through datafiles and concatenate burst durations and intervals: +for videoIter = 1:length(mov_listing); + + fprintf(1,[ num2str(videoIter), ' / ', num2str(length(mov_listing)),'\n' ] ); + + datafile = [ mov_listing{videoIter}, '/', 'AllBurstingInfo.mat' ]; + load(fullfile(DIR,datafile), 'BurstDurations', 'Intervals' ); + + a = length(BurstsTotal); + b = length(BurstDurations); + c = length(IntervalsTotal); + d = length(Intervals); + + BurstsTotal(1,a+1:a+b) = BurstDurations(:); + IntervalsTotal(1,c+1:c+d) = Intervals(:); +end + +DurationStats.MeanBurstDurations = mean(BurstsTotal); +DurationStats.MedianBurstDurations = median(BurstsTotal); +DurationStats.StDevBurstDurations = std(BurstsTotal); +[N,EDGES] = histcounts(BurstsTotal); +DurationStats.N = N; +DurationStats.EDGES = EDGES; + +IntervalStats.MeanIntervals = mean(IntervalsTotal); +IntervalStats.MedianIntervals = median(IntervalsTotal); +IntervalStats.StDevIntervals = std(IntervalsTotal); +[N,EDGES] = histcounts(IntervalsTotal); +IntervalStats.N = N; +IntervalStats.EDGES = EDGES; + +save('CombinedBurstingStats/Stats','IntervalStats','DurationStats') +save('CombinedBurstingStats/Durations','BurstsTotal') +save('CombinedBurstingStats/Intervals','IntervalsTotal') + +edges = [0:0.1:70]; +BurstFigure = figure('Name','Burst durations histogram'); +hold on; +hist((BurstsTotal(:)./30),edges); +ylim([0 5]); xlim([0 10]); +h = findobj(BurstFigure,'Type','patch'); +h.FaceColor = [ 0.6 0.8 0.6 ]; +h.EdgeColor = [ 0 0.2 0 ]; + +edges = [0:0.5:70]; +IntervalFigure = figure('Name','Inter-burst-interval durations histogram'); +hold on; +hist((IntervalsTotal(:)./30),edges); +ylim([0 5]); xlim([0 40]); +g = findobj(IntervalFigure,'Type','patch'); +g.FaceColor = [ 0.4 0.8 0.8 ]; +g.EdgeColor = [ 0 0.2 0.2 ]; + +saveas(BurstFigure,'CombinedBurstingStats/BurstHistogram','png'); +saveas(IntervalFigure,'CombinedBurstingStats/IntervalHistogram','png'); + diff --git a/SM_BurstGrandTotalCombStats.m b/SM_BurstGrandTotalCombStats.m new file mode 100644 index 0000000..1e4b8fb --- /dev/null +++ b/SM_BurstGrandTotalCombStats.m @@ -0,0 +1,72 @@ +%% Make BurstingStats folder: +mat_dir = 'GrandTotalStats'; +if exist(mat_dir,'dir'); + rmdir(mat_dir,'s'); +end +mkdir(mat_dir); +DIR=pwd; + +%% Read in all datafiles: +mov_listing = dir(fullfile(DIR,'CombinedBurstingStats#*')); +mov_listing = {mov_listing(:).name}; + +TotalDurations = []; +TotalIntervals = []; + +[nblanks formatstring]=progressbar(length(mov_listing)); +fprintf(1,['Progress: ' blanks(nblanks) ]); + +%% Loop through datafiles and concatenate burst durations and intervals: +for videoIter = 1:length(mov_listing); + + fprintf(1,[ num2str(videoIter), ' / ', num2str(length(mov_listing)),'\n' ] ); + datafile1 = [ mov_listing{videoIter}, '/' 'Durations']; + load(fullfile(DIR,datafile1) ); + datafile2 = [ mov_listing{videoIter}, '/' 'Intervals']; + load(fullfile(DIR,datafile2) ); + + a = length(TotalDurations); + b = length(BurstsTotal); + c = length(TotalIntervals); + d = length(IntervalsTotal); + TotalDurations(1,a+1:a+b) = BurstsTotal(:); + TotalIntervals(1,c+1:c+d) = IntervalsTotal(:); + +end + +DurationStats.MeanBurstDurations = mean(TotalDurations); +DurationStats.MedianBurstDurations = median(TotalDurations); +DurationStats.StDevBurstDurations = std(TotalDurations); +[N,EDGES] = histcounts(TotalDurations); +DurationStats.N = N; +DurationStats.EDGES = EDGES; + +IntervalStats.MeanIntervals = mean(TotalIntervals); +IntervalStats.MedianIntervals = median(TotalIntervals); +IntervalStats.StDevIntervals = std(TotalIntervals); +[N,EDGES] = histcounts(TotalIntervals); +IntervalStats.N = N; +IntervalStats.EDGES = EDGES; + +save('GrandTotalStats/Stats','IntervalStats','DurationStats') +save('GrandTotalStats/Durations','TotalDurations') +save('GrandTotalStats/Intervals','TotalIntervals') + +edges = [0:0.1:70]; +BurstFigure = figure('Name','Burst durations histogram'); hold on; hist((IsoDurations(:)./30),edges); +ylim([0 70]); xlim([0 10]); +h = findobj(BurstFigure,'Type','patch'); +h.FaceColor = [ 0.6 0.8 0.6 ]; +h.EdgeColor = [ 0 0.2 0 ]; + +edges = [0:0.5:70]; +IntervalFigure = figure('Name','Inter-burst-interval durations histogram'); hold on; hist((IsoIntervals(:)./30),edges); +ylim([0 70]); xlim([0 70]); +g = findobj(IntervalFigure,'Type','patch'); +g.FaceColor = [ 0.4 0.8 0.8 ]; +g.EdgeColor = [ 0 0.2 0.2 ]; + +saveas(BurstFigure,'GrandTotalStats/BurstHistogram','png'); +saveas(IntervalFigure,'GrandTotalStats/IntervalHistogram','png'); + + diff --git a/SM_BurstStartEndtimes.m b/SM_BurstStartEndtimes.m new file mode 100644 index 0000000..a9efc1a --- /dev/null +++ b/SM_BurstStartEndtimes.m @@ -0,0 +1,289 @@ +function [AllVideosBurstingFrames, AllBurstingDurations, ROIbursting, BurstParticipation, BurstParticipationRatio, Intervals, IntervalStats, BurstDurations, DurationStats, ROI_threshold, num_skipped, savefilename_AllVideosBursting, BurstFigure, BurstingImFigure] = SM_BurstStartEndtimes(Av_Data,Spike_Data,ROI,ROI_threshold,num_skipped,num_beginning,min_burstduration) + +%% default parameters +if ~exist('ROI_threshold', 'var') || isempty(ROI_threshold) + ROI_threshold = 4; +end +% The smaller this number, the more liberally bursts will be selected + +if ~exist('num_skipped', 'var') || isempty(num_skipped) + num_skipped = 4; +end +% The larger this number, the more liberally bursts will be selected + +if ~exist('num_beginning', 'var') || isempty(num_beginning) + num_beginning = 0; +end +% How many frames to include before bursts? + +if ~exist('min_burstduration', 'var') || isempty(min_burstduration) + min_burstduration = 2; +end +% As a default, is does not count bursts with length of 1 frame + + + + +%% Looping through videos: + +num_videos = size(Av_Data,1); +num_frames = size(Av_Data,2); + +for VideoIter = 1: num_videos % loop through videos + + + %% FIND BURSTS + + [activitylocations] = find(Av_Data(VideoIter,:)>=(ROI_threshold)); + % find where there is activity of a defined # ROIs simultaneously + BurstStartingFrames = []; + BurstEndingFrames = []; + % allocate matrices & make sure there's no old data + + % Find which activity frames are individual bursts (eliminate + % overlapping numbers) + [diff_al] = diff(activitylocations); + if size(activitylocations) >= [1,1]; + [burstlocations(1,1)] = activitylocations(1,1); + for i = 2:(length(diff_al)) + if (diff_al(1,i-1)) <= (num_skipped+1); continue; + else [burstlocations(end+1)] = activitylocations(1,i); + end + end + else continue; + end + num_bursts = length(burstlocations); + + + %% Find beginning of bursts + + for BurstIter = 1:num_bursts % loop through above found bursts + EarliestActivity = burstlocations(1,BurstIter); + + while true + SearchForActivityStart = EarliestActivity - num_skipped; + SearchForActivityStop = EarliestActivity - 1; + + % stop once we have earliest activity at frame 1 + if SearchForActivityStop < 1 + break; + end + + % do not look before beginning of video + if SearchForActivityStart < 1 + SearchForActivityStart = 1; + end + + % find earliest during search window + BurstingFrame = find(Av_Data(VideoIter, SearchForActivityStart:SearchForActivityStop), 1); + + % nothing found? stop the loop + if isempty(BurstingFrame) + break; + end + + % found something + EarliestActivity = SearchForActivityStart + BurstingFrame - 1; + end + + BurstStartingFrames(end+1) = EarliestActivity; + end + + % adjust beginnings + BurstStartingFrames = max(BurstStartingFrames - num_beginning, 1); + + + % Find ending of bursts + + for BurstIter = 1:num_bursts % loop through above found bursts + LatestActivity = burstlocations(1, BurstIter); + + while true + SearchForActivityStart = LatestActivity + 1; + SearchForActivityStop = LatestActivity + num_skipped; + + % stop once we have earliest activity at frame 1 + if SearchForActivityStart > num_frames + break; + end + + % do not look before beginning of video + if SearchForActivityStop > num_frames + SearchForActivityStop = num_frames; + end + + % find earliest during search window + BurstingFrame = find(Av_Data(VideoIter, SearchForActivityStart:SearchForActivityStop), 1); + + % nothing found? stop the loop + if isempty(BurstingFrame) + break; + end + + % found something + LatestActivity = SearchForActivityStart + BurstingFrame - 1; + end + + BurstEndingFrames(end+1) = LatestActivity; + end + + % Total data: rows = nr of bursts; column 1 = start, column 2 = end + + AllBurstingFrames = [BurstStartingFrames(1) BurstEndingFrames(1)]; + + for BurstIter = 2:num_bursts + if BurstStartingFrames(BurstIter) <= BurstEndingFrames(BurstIter - 1) + AllBurstingFrames(end, 2) = BurstEndingFrames(BurstIter); + else + AllBurstingFrames(end + 1, 1) = BurstStartingFrames(BurstIter); + AllBurstingFrames(end, 2) = BurstEndingFrames(BurstIter); + end + end + AllBurstingDurations = AllBurstingFrames(:, 2) - AllBurstingFrames(:, 1) + 1; + AllBurstingFrames = AllBurstingFrames(AllBurstingDurations >= min_burstduration, :); + AllBurstingDurations = AllBurstingDurations(AllBurstingDurations >= min_burstduration); + + AllVideosBurstingFrames{VideoIter}=(AllBurstingFrames); + + savefilename_AllVideosBursting = ['AllVideosBursting_' num2str(ROI_threshold) 'ROIthresh_' num2str(num_skipped) 'FrameWindow' ]; + save(savefilename_AllVideosBursting,'AllVideosBurstingFrames', 'AllBurstingDurations') + + clear ( 'activitylocations', 'burstlocations', 'diff_al' ); + + savefilename = ['BurstFigure_' num2str(ROI_threshold) 'ROIthresh_' num2str(num_skipped) 'FrameWindow' ]; + BurstFigure = figure('Name',['Bursts_Video' num2str(VideoIter)]); + t = (1:size(Av_Data, 2)) ./ 30; %times + plot(t, Av_Data); hold on; scatter((BurstStartingFrames(:)./30), (Av_Data(BurstStartingFrames)./30), 'g'); scatter((BurstEndingFrames(:)./30), (Av_Data(BurstEndingFrames)./30), 'r'); hold off; + saveas(BurstFigure,savefilename,'png'); + saveas(BurstFigure,savefilename,'fig'); + +end % end VideoIter + + +%% Find ROIs that were involved in bursts + +ROIbursting = {}; + +for VideoIter = 1:length(AllVideosBurstingFrames); + ROItimes = squeeze(Spike_Data(VideoIter,:,:)); + + for BurstIter = 1:size(AllVideosBurstingFrames{1,VideoIter},1) + % Calculates how many bursts there are for each video again + A = (AllVideosBurstingFrames{1,VideoIter}(BurstIter,1)); + B = (AllVideosBurstingFrames{1,VideoIter}(BurstIter,2)); + ROIbursting{1,end+1} = ROItimes(:,(A:B)); % saves ROI data for each + % burst in the dataset, without indicating from which video it was + end + +% Use the below code lines if you want to save data for each video +% separately (now saves all videos together below the "end" statement): +% savefilename = ['ROIbursts_Video' num2str(VideoIter2)]; +% save(savefilename,'ROIbursting'); +end + + +%% Analyze which ROIs initiated bursts + +BurstParticipation = zeros((size(ROItimes,1)), max(AllBurstingDurations)); +% Rows: All ROIs +% Columns: 1=total count of burst participation in frame 1, 2=frame 2, etc + + +for BurstIter = 1:size(ROIbursting,2) % loop through data per burst + data = ROIbursting{1,BurstIter}; + num_frames2 = size(data,2); + BurstParticipation(:, 1:num_frames2) = BurstParticipation(:, 1:num_frames2) + data; +end + +% Do the same but now calculate the ratio (nr devided by nr of bursts): + +BurstParticipationRatio = BurstParticipation; +for BurstIter = 1:size(BurstParticipationRatio, 2) + BurstParticipationRatio(:, BurstIter) = BurstParticipationRatio(:, BurstIter) ./ sum(AllBurstingDurations >= BurstIter); +end + + +%% Calculate intervals + +Intervals = []; + +for VideoIter = 1:length(AllVideosBurstingFrames); + for IntervalIter = 1:size(AllVideosBurstingFrames{VideoIter},1)-1; + [Start] = AllVideosBurstingFrames{VideoIter}(IntervalIter,2); + [End] = AllVideosBurstingFrames{VideoIter}(IntervalIter+1,1); + if End-Start <= 1; continue; end; + Intervals(1,end+1) = End-Start; + end +end + +IntervalStats.MeanIntervals = mean(Intervals); +IntervalStats.MedianIntervals = median(Intervals); +IntervalStats.StDevIntervals = std(Intervals); +[N,EDGES] = histcounts(Intervals); +IntervalStats.N = N; +IntervalStats.EDGES = EDGES; +% [N,EDGES] = histcounts(X) partitions the values in X into bins, and + % returns the count in each bin, as well as the bin edges. histcounts + % determines the bin edges using an automatic binning algorithm that + % returns uniform bins of a width that is chosen to cover the range of + % values in X and reveal the shape of the underlying distribution. + + +%% Calculate bursting durations + +BurstDurations = []; + +for VideoIter = 1:length(AllVideosBurstingFrames); + for IntervalIter = 1:size(AllVideosBurstingFrames{VideoIter},1); + [Start] = AllVideosBurstingFrames{VideoIter}(IntervalIter,1); + [End] = AllVideosBurstingFrames{VideoIter}(IntervalIter,2); + if End-Start <= 1; continue; end; + BurstDurations(1,end+1) = End-Start; + end +end + +DurationStats.MeanBurstDurations = mean(BurstDurations); +DurationStats.MedianBurstDurations = median(BurstDurations); +DurationStats.StDevBurstDurations = std(BurstDurations); +[N,EDGES] = histcounts(BurstDurations); +DurationStats.N = N; +DurationStats.EDGES = EDGES; +% [N,EDGES] = histcounts(X) partitions the values in X into bins, and + % returns the count in each bin, as well as the bin edges. histcounts + % determines the bin edges using an automatic binning algorithm that + % returns uniform bins of a width that is chosen to cover the range of + % values in X and reveal the shape of the underlying distribution. + +%% Save all values calculated in "AllBurstingInfo": +save('AllBurstingInfo', 'ROIbursting', 'BurstParticipation', 'BurstParticipationRatio', 'Intervals', 'IntervalStats', 'BurstDurations', 'DurationStats') + + + +%% Lastly: Plot figure to visualize which ROIs initiate bursting + +BurstingImFigure = figure('Name','ROIs that initiate bursting'); + +image(ROI.reference_image); +colormap('gray(2555'); +circle_colors = hot(100); +hold on; + +NrOfROIs = length(ROI.coordinates); +for ROIiter = 1:NrOfROIs % loop through ROIs + + RelativeValues = BurstParticipationRatio(:, 1); % take numbers from BurstParticipationRatios calculated earlier + RelativeValues = RelativeValues - min(RelativeValues(:)); % set range between [0, inf) + RelativeValues = RelativeValues ./ max(RelativeValues(:)) ; % set range between [0, 1] + RelativeValues(RelativeValues==0) = 0.01; % replace 0 by small number + ColorValue = RelativeValues(ROIiter,1); + + coords = ROI.stats(ROIiter).Centroid; + radius = ROI.stats(ROIiter).Diameter / 2; + scatter(coords(1), coords(2), pi * radius ^ 2, circle_colors(round(ColorValue * 100), :), 'filled'); + text(coords(1) + 2, coords(2) - 7, num2str(ROIiter)); + +end +savefilename = ['ROI_BurstInitiation_BrainMap_' num2str(ROI_threshold) 'ROIthresh_' num2str(num_skipped) 'FrameWindow' ]; +saveas(BurstingImFigure,savefilename,'png'); +autoArrangeFigures(2,2) + diff --git a/SM_BurstsEphys.m b/SM_BurstsEphys.m new file mode 100644 index 0000000..ab60cc6 --- /dev/null +++ b/SM_BurstsEphys.m @@ -0,0 +1,203 @@ + +num_skipped = 1667; % equivalent to 5 frames in 30 fr/sec data (10000/30*5) +num_beginning = 0; +min_burstduration = 667; % equivalent to 2 frames in 30 fr/sec data (2/30 *10000) + +AllVideosBurstingFrames = {}; +%% Looping through videos: + +num_videos = size(SM_Spike_Data,1); +num_frames = size(SM_Spike_Data,3); + +for VideoIter = 1: num_videos % loop through videos + + + %% FIND BURSTS + + [activitylocations] = find(SM_Spike_Data(VideoIter,1,:)); + % find where there is activity as detected by SM_SpikeDetectorEphys + BurstStartingFrames = []; + BurstEndingFrames = []; + % allocate matrices & make sure there's no old data + + % Find which activity frames are individual bursts (eliminate + % overlapping numbers) + [diff_al] = diff(activitylocations); + if size(activitylocations) >= [1,1]; + [burstlocations(1,1)] = activitylocations(1,1); + for i = 2:(length(diff_al)) + if (diff_al(i-1,1)) <= (num_skipped+1); + continue; + else [burstlocations(end+1)] = activitylocations(i,1); + end + end + else continue; + end + num_bursts = length(burstlocations); + + + %% Find beginning of bursts + + for BurstIter = 1:num_bursts % loop through above found bursts + EarliestActivity = burstlocations(1,BurstIter); + + while true + SearchForActivityStart = EarliestActivity - num_skipped; + SearchForActivityStop = EarliestActivity - 1; + + % stop once we have earliest activity at frame 1 + if SearchForActivityStop < 1 + break; + end + + % do not look before beginning of video + if SearchForActivityStart < 1 + SearchForActivityStart = 1; + end + + % find earliest during search window + BurstingFrame = find(SM_Spike_Data(1,1, SearchForActivityStart:SearchForActivityStop), 1); + + % nothing found? stop the loop + if isempty(BurstingFrame) + break; + end + + % found something + EarliestActivity = SearchForActivityStart + BurstingFrame - 1; + end + + BurstStartingFrames(end+1) = EarliestActivity; + end + + % adjust beginnings + BurstStartingFrames = max(BurstStartingFrames - num_beginning, 1); + + + % Find ending of bursts + + for BurstIter = 1:num_bursts % loop through above found bursts + LatestActivity = burstlocations(1, BurstIter); + + while true + SearchForActivityStart = LatestActivity + 1; + SearchForActivityStop = LatestActivity + num_skipped; + + % stop once we have earliest activity at frame 1 + if SearchForActivityStart > num_frames + break; + end + + % do not look before beginning of video + if SearchForActivityStop > num_frames + SearchForActivityStop = num_frames; + end + + % find earliest during search window + BurstingFrame = find(SM_Spike_Data(1,1, SearchForActivityStart:SearchForActivityStop), 1); + + % nothing found? stop the loop + if isempty(BurstingFrame) + break; + end + + % found something + LatestActivity = SearchForActivityStart + BurstingFrame - 1; + end + + BurstEndingFrames(end+1) = LatestActivity; + end + + % Total data: rows = nr of bursts; column 1 = start, column 2 = end + + AllBurstingFrames = [BurstStartingFrames(1) BurstEndingFrames(1)]; + + for BurstIter = 2:num_bursts + if BurstStartingFrames(BurstIter) <= BurstEndingFrames(BurstIter - 1) + AllBurstingFrames(end, 2) = BurstEndingFrames(BurstIter); + else + AllBurstingFrames(end + 1, 1) = BurstStartingFrames(BurstIter); + AllBurstingFrames(end, 2) = BurstEndingFrames(BurstIter); + end + end + AllBurstingDurations = AllBurstingFrames(:, 2) - AllBurstingFrames(:, 1) + 1; + AllBurstingFrames = AllBurstingFrames(AllBurstingDurations >= min_burstduration, :); + AllBurstingDurations = AllBurstingDurations(AllBurstingDurations >= min_burstduration); + + AllVideosBurstingFrames{VideoIter}=(AllBurstingFrames); + + savefilename_AllVideosBursting = ['AllVideosBursting_' num2str(num_skipped) 'FrameWindow' ]; + save(savefilename_AllVideosBursting,'AllVideosBurstingFrames', 'AllBurstingDurations') + + clear ( 'activitylocations', 'burstlocations', 'diff_al' ); + + savefilename = ['BurstFigure_' num2str(num_skipped) 'FramesSkipped_' num2str(min_burstduration) 'MinDuration' ]; + BurstFigure = figure('Name','Bursts Jeff''s Ephys sleep data' ); + T = 1: 1: size(SM_Spike_Data, 3); % duration in # frames + plot(T, squeeze(SM_Spike_Data(1,1,:))); + hold on; + plot(T,alldata{1}*10); + scatter((AllBurstingFrames(:,1)), squeeze(SM_Spike_Data(1,1,AllBurstingFrames(:,1))), 'g'); + scatter((AllBurstingFrames(:,2)), squeeze(SM_Spike_Data(1,1,(AllBurstingFrames(:,2)))), 'r'); hold off; + ylim([-1.5 1.1]); hold off; + + saveas(BurstFigure,savefilename,'png'); + saveas(BurstFigure,savefilename,'fig'); + +end % end VideoIter + + +%% Calculate intervals + +Intervals = []; + +for VideoIter = 1:length(AllVideosBurstingFrames); + for IntervalIter = 1:size(AllVideosBurstingFrames{VideoIter},1)-1; + [Start] = AllVideosBurstingFrames{VideoIter}(IntervalIter,2); + [End] = AllVideosBurstingFrames{VideoIter}(IntervalIter+1,1); + if End-Start <= 1; continue; end; + Intervals(1,end+1) = End-Start; + end +end + +IntervalStats.MeanIntervals = mean(Intervals); +IntervalStats.MedianIntervals = median(Intervals); +IntervalStats.StDevIntervals = std(Intervals); +[N,EDGES] = histcounts(Intervals); +IntervalStats.N = N; +IntervalStats.EDGES = EDGES; +% [N,EDGES] = histcounts(X) partitions the values in X into bins, and + % returns the count in each bin, as well as the bin edges. histcounts + % determines the bin edges using an automatic binning algorithm that + % returns uniform bins of a width that is chosen to cover the range of + % values in X and reveal the shape of the underlying distribution. + + +%% Calculate bursting durations + +BurstDurations = []; + +for VideoIter = 1:length(AllVideosBurstingFrames); + for IntervalIter = 1:size(AllVideosBurstingFrames{VideoIter},1); + [Start] = AllVideosBurstingFrames{VideoIter}(IntervalIter,1); + [End] = AllVideosBurstingFrames{VideoIter}(IntervalIter,2); + if End-Start <= 1; continue; end; + BurstDurations(1,end+1) = End-Start; + end +end + +DurationStats.MeanBurstDurations = mean(BurstDurations); +DurationStats.MedianBurstDurations = median(BurstDurations); +DurationStats.StDevBurstDurations = std(BurstDurations); +[N,EDGES] = histcounts(BurstDurations); +DurationStats.N = N; +DurationStats.EDGES = EDGES; +% [N,EDGES] = histcounts(X) partitions the values in X into bins, and + % returns the count in each bin, as well as the bin edges. histcounts + % determines the bin edges using an automatic binning algorithm that + % returns uniform bins of a width that is chosen to cover the range of + % values in X and reveal the shape of the underlying distribution. + +%% Save all values calculated in "AllBurstingInfo": +save('AllBurstingInfo', 'Intervals', 'IntervalStats', 'BurstDurations', 'DurationStats') + diff --git a/SM_Parse.m b/SM_Parse.m index 4e218f6..f63bfd3 100755 --- a/SM_Parse.m +++ b/SM_Parse.m @@ -1,4 +1,3 @@ - function SM_Parse(DIR,varargin) mat_dir='mat'; @@ -13,7 +12,7 @@ function SM_Parse(DIR,varargin) if nargin<1 | isempty(DIR), DIR=pwd; end mov_listing=dir(fullfile(DIR,'*.tif')); -mov_listing={mov_listing(:).name}; +mov_listing={mov_listing(:).name} filenames=mov_listing; @@ -25,15 +24,17 @@ function SM_Parse(DIR,varargin) file FILE = fullfile(DIR,mov_listing{i}); -info = imfinfo(FILE); -num_images = numel(info); + info = imfinfo(FILE); + num_images = numel(info); -for k = 1:num_images - A = imread(FILE, k, 'Info', info); - video.frames(k).cdata = A; -end + for k = 1:num_images + A = imread(FILE, k, 'Info', info); + video.frames(k).cdata = A; + end - save(fullfile(mat_dir,[file '.mat']),'video','-v7.3'); + save(fullfile(mat_dir,[file '.mat']),'video','-v7.3'); + + clear('k','num_images','A','video.frames') end fprintf(1,'\n'); \ No newline at end of file diff --git a/SM_PlotOneOrMultVideos.m b/SM_PlotOneOrMultVideos.m deleted file mode 100644 index f662bae..0000000 --- a/SM_PlotOneOrMultVideos.m +++ /dev/null @@ -1,110 +0,0 @@ -function SM_PlotOneOrMultVideos(roi_ave) - -%% Prepare reading in the data - -[Videos]=length(roi_ave.raw); -[Frames]=length(roi_ave.raw{1}(1,:)); -[ROIS]=length(roi_ave.raw{1}(:,1)); - -%% VARIABLES make sure to adjust if necessary - -VideosSelected = [11:29]; %[7 10 13 15 17 ]; -framerate = 30; % nr of frames per second -comptime=10; % frames to delete at beginning & compensate in graph -BOSselection = comptime:Frames; -savefilename = ['multiple_plot_' datestr(clock)]; - -%% Calculate values and preallocate matrix -BOStime = length(BOSselection); - -data = zeros(ROIS,Frames,Videos); -total_raw = zeros(ROIS,BOStime,Videos); -total_dff = zeros(ROIS,BOStime,Videos); -total_videos = zeros(ROIS,BOStime,Videos); -total_dffvideos = zeros(ROIS,BOStime,Videos); - -%% Read in data -for videoIter = VideosSelected -data(:,:,videoIter)=(roi_ave.raw{videoIter}); -end - -%% loop through data to calculate DFF -figure(); hold on -c = colormap(lines(ROIS*Videos+10)); - -for videoIter2=VideosSelected - dataPerVideo = data(:,BOSselection,videoIter2); - - for ROIiter=1:ROIS - - dataPerROI = dataPerVideo(ROIiter,:); - baseline=prctile(dataPerROI,0); % 0 is the min - dff=(dataPerROI-baseline)./baseline; - total_raw(ROIiter,:,videoIter2)=dataPerROI; - total_dff(ROIiter,:,videoIter2)=dff; - - end - - total_videos=total_videos+total_raw; - total_dffvideos=total_dffvideos+total_dff; -end - -%% Plotting - -for videoIter3 = VideosSelected - plotPerVideo = total_dffvideos(:,:,videoIter3); - - counter = 1; - - for ROIiter2 = 1:ROIS - dff = plotPerVideo(ROIiter2,:); - shiftup = (0.15*counter-1); - plot(((comptime+(1:length(dff)))/framerate),dff+shiftup,'Color',c(ROIiter2,:),'LineWidth',1.0); - xlim([0 ((comptime+BOStime)/framerate)]); - counter = counter+1; - end - -%% More figure stuff & save data and variables -ylabel(''); -xlabel('Time (s)'); -set(findall(gcf,'type','text'),'FontSize',13,'fontWeight','bold') - -save(savefilename); - -end - - - -%% ----[ Setup Sonogram ]------% - -% fs=24.4141e3; -% [b,a]=ellip(5,.2,80,[500]/(fs/2),'high'); -% [IMAGE,F,T]=fb_pretty_sonogram(filtfilt(b,a,mic_data./abs(max(mic_data))),fs,'low',1.5,'zeropad',0); - -%% ----[ Plotting ]------% -% h(1) = subplot(10,1,1:2); -% imagesc((T*framerate - startTime*framerate + 1)/framerate,F,log(abs(IMAGE)+1e+2));set(gca,'YDir','normal'); -% colormap(flipud(bone)*.8) -% freezeColors; -% ylim([0 9000]); -% hold on - -% here, you can make a subplot on top with a sonogram, for example -% h(2) = subplot(10,1,3:10); -% title('Calcium transients LNY19RB 9/2/15 BOS playback #4 (normalized ROIs)'); - - -%% ---------[ Optional: picking peaks ] --------------% - -% This code is for selecting peaks in fluorescense change and constructing -% a raster plot based on those -% -% [pks,locs] = findpeaks(dff,'MinPeakWidth',100,'MinPeakProminence',1.0*std(dff)); -% hold on; plot(locs/framerate,pks+shiftup,'*','Color',c(i,:));% line([locs(:,:)/framerate,locs(:,:)/framerate],[-1 9],'Color',c(i,:)) -% hold off -% -% locs = transpose(locs); -% -% hold on -% line([locs(:,:)/framerate,locs(:,:)/framerate],[500 2000],'Color',c(i,:)) -% hold off \ No newline at end of file diff --git a/SM_PlotSummedVideos.m b/SM_PlotSummedVideos.m deleted file mode 100644 index 6295780..0000000 --- a/SM_PlotSummedVideos.m +++ /dev/null @@ -1,111 +0,0 @@ -function SM_PlotSummedVideos(roi_ave) - -%% prepare reading in data - -[Videos]=length(roi_ave.raw); -[Frames]=length(roi_ave.raw{1}(1,:)); -[ROIS]=length(roi_ave.raw{1}(:,1)); - -%% VARIABLES make sure to adjust if necessary -VideosSelected = 1:Videos; -framerate = 30; -comptime=10; % frames to delete at beginning & compensate in graph -BOSselection = comptime:Frames; -savefilename = ['summed_matrix_' datestr(clock)]; - -%% Preallocate matrices: - -startTime = (1*(1/framerate)); -endTime = (Frames*(1/framerate)); -BOStime = length(BOSselection); - -data=zeros(ROIS,Frames,Videos); -summed_raw=zeros(ROIS,BOStime); -summed_dff=zeros(ROIS,BOStime); -summed_videos=zeros(ROIS,BOStime); -summed_dffvideos=zeros(ROIS,BOStime); - -%% read in data - -for videoIter=VideosSelected -data(:,:,videoIter)=(roi_ave.raw{videoIter}); -end - -%% loop through data to calculate DFF and make data matrices - -for videoIter=VideosSelected - -dataPerVideo = data(:,BOSselection,videoIter); - - for ROIiter=1:ROIS - - dataPerROI = dataPerVideo(ROIiter,:); - baseline=prctile(dataPerROI,0); % 0 is the min - dff=(dataPerROI-baseline)./baseline; - summed_raw(ROIiter,:)=dataPerROI; - summed_dff(ROIiter,:)=dff; - end - summed_videos=summed_videos+summed_raw; - summed_dffvideos=summed_dffvideos+summed_dff; -end - - - -%% plot data per ROI -figure(); hold on -c = colormap(lines(ROIS+10)); -counter = 1; - - for ROIiter2=1:ROIS - dff=summed_dffvideos(ROIiter2,:); - shiftup = (0.05*counter-1); - plot(((comptime+(1:length(dff)))/framerate),dff+shiftup,'Color',c(ROIiter2,:),'LineWidth',1.0); - xlim([0 ((comptime+BOStime)/framerate)]); - counter=counter+1; - end - -%% More figure stuff -ylabel(''); -xlabel('Time (s)'); -set(findall(gcf,'type','text'),'FontSize',13,'fontWeight','bold') - -%% Save variables and matrices -save(savefilename); - -end - - - -%% ----[ Setup Sonogram ]------% - -% fs=24.4141e3; -% [b,a]=ellip(5,.2,80,[500]/(fs/2),'high'); -% [IMAGE,F,T]=fb_pretty_sonogram(filtfilt(b,a,mic_data./abs(max(mic_data))),fs,'low',1.5,'zeropad',0); - -%% ----[ Plotting ]------% -% h(1) = subplot(10,1,1:2); -% imagesc((T*framerate - startTime*framerate + 1)/framerate,F,log(abs(IMAGE)+1e+2));set(gca,'YDir','normal'); -% colormap(flipud(bone)*.8) -% freezeColors; -% ylim([0 9000]); -% hold on - -% here, you can make a subplot on top with a sonogram, for example -% h(2) = subplot(10,1,3:10); -% title('Calcium transients LNY19RB 9/2/15 BOS playback #4 (normalized ROIs)'); - - -%% ---------[ Optional: picking peaks ] --------------% - -% This code is for selecting peaks in fluorescense change and constructing -% a raster plot based on those -% -% [pks,locs] = findpeaks(dff,'MinPeakWidth',100,'MinPeakProminence',1.0*std(dff)); -% hold on; plot(locs/framerate,pks+shiftup,'*','Color',c(i,:));% line([locs(:,:)/framerate,locs(:,:)/framerate],[-1 9],'Color',c(i,:)) -% hold off -% -% locs = transpose(locs); -% -% hold on -% line([locs(:,:)/framerate,locs(:,:)/framerate],[500 2000],'Color',c(i,:)) -% hold off \ No newline at end of file diff --git a/SM_PlotWithSonogramMultipleData.m b/SM_PlotWithSonogramMultipleData.m deleted file mode 100644 index d211185..0000000 --- a/SM_PlotWithSonogramMultipleData.m +++ /dev/null @@ -1,55 +0,0 @@ -%% VARIABLES -% load saved variables into the workspace first: - % load roi_ave - % and the output matrix from plot one or multiple videos - % and the stimulus: SONG = audioread('filename'); - -sonogram_comptime = 150; % frame at which song started playing -comptime = 10; % frames clipped from beginning and compensated in graph -data_to_plot = total_dffvideos; % matrix from which data is grabbed -fs = 48000; -SelectedVideos = [11:29]; -shiftupValue = 0.8; - -startTime = (1*(1/framerate)); -endTime = (Frames*(1/framerate)); - -%% Plot sonogram -[b,a] = ellip(5,.2,80,[500]/(fs/2),'high'); -[IMAGE,F,T] = fb_pretty_sonogram(filtfilt(b,a,SONG./abs(max(SONG))),fs,'low',1.5,'zeropad',0); -figure() - - h(1) = subplot(10,1,1:2); - imagesc((sonogram_comptime+T*framerate-startTime*framerate+1)/framerate,F,log(abs(IMAGE)+1e+2));set(gca,'YDir','normal'); - colormap(flipud(bone)*.8) - freezeColors; - ylim([0 9000]); - hold on - - h(2) = subplot(10,1,3:10); - hold on - -%% Plot ROI data - -for videoIter = SelectedVideos - plotPerVideo = data_to_plot(:,:,videoIter); - - counter = 1; - c = colormap(lines(50)); - - for ROIiter = 1:ROIS - dataPerROI = plotPerVideo(ROIiter,:); - shiftup = (shiftupValue*counter-1); - plot(((((comptime+(1:length(dataPerROI)))))/framerate),dataPerROI+shiftup,'Color',c(ROIiter,:),'LineWidth',1.0); - counter=counter+1; - - end -end - -%% Some more figure stuff -ylabel(''); -xlabel('Time (s)'); -set(findall(gcf,'type','text'),'FontSize',13,'fontWeight','bold') -linkaxes(h,'x'); -xlim([0 ((comptime+BOStime)/framerate)]); - diff --git a/SM_PlotWithSonogramSummedData.m b/SM_PlotWithSonogramSummedData.m deleted file mode 100644 index b45535a..0000000 --- a/SM_PlotWithSonogramSummedData.m +++ /dev/null @@ -1,50 +0,0 @@ -%% VARIABLES -% load saved variables into the workspace first: - % load roi_ave - % and the output matrix from plot summed videos - % and the stimulus: SONG = audioread('filename'); - -sonogram_comptime = 150; % frame at which song started playing -comptime = 10; % frames clipped from beginning and compensated in graph -data_to_plot = summed_dffvideos; % matrix from which data is grabbed -fs = 48000; -shiftupValue = 0.08; - -startTime = (1*(1/framerate)); -endTime = (Frames*(1/framerate)); - -%% Plot sonogram -[b,a] = ellip(5,.2,80,[500]/(fs/2),'high'); -[IMAGE,F,T] = fb_pretty_sonogram(filtfilt(b,a,SONG./abs(max(SONG))),fs,'low',1.5,'zeropad',0); -figure() - - h(1) = subplot(10,1,1:2); - imagesc((sonogram_comptime+T*framerate-startTime*framerate+1)/framerate,F,log(abs(IMAGE)+1e+2));set(gca,'YDir','normal'); - colormap(flipud(bone)*.8) - freezeColors; - ylim([0 9000]); - hold on - - h(2) = subplot(10,1,3:10); - hold on - -%% Plot ROI data - - counter = 1; - c = colormap(lines(50)); - -for ROIiter = 1:ROIS -dataPerROI = data_to_plot(ROIiter,:); % Only when using summed matrix (not when multiple matrix) -shiftup = (shiftupValue*counter-1); -plot(((((comptime+(1:length(dataPerROI)))))/framerate),dataPerROI+shiftup,'Color',c(ROIiter,:),'LineWidth',1.0); -counter=counter+1; - -end - -%% Some more figure stuff -ylabel(''); -xlabel('Time (s)'); -set(findall(gcf,'type','text'),'FontSize',13,'fontWeight','bold') -linkaxes(h,'x'); -xlim([0 ((comptime+BOStime)/framerate)]); - diff --git a/SM_SortedSpikeAnalysis.m b/SM_SortedSpikeAnalysis.m new file mode 100644 index 0000000..9ac3fc4 --- /dev/null +++ b/SM_SortedSpikeAnalysis.m @@ -0,0 +1,431 @@ +function [AllVideoSpikingFrames, SpikeTogetherUnique, SortedROIindex, ROIlags, CoActFigLag, CoActFig, LagFig, ImFig] = SM_SortedSpikeAnalysis(Spike_Data,ROI,WP) +% Make sure that Spike_Data is loaded + +WindowParameter = WP; % in frames - try 4 to begin with +% so WP / framerate == window in seconds +% Wills data is 22 fr/sec; mine 30 fr/sec +TakeOutLowNrs = 0; % For plotting ROIindex +% Plotted are all connections that fired together more often than this +% value + +%% Select which ROIs to plot (ROIindex will still have all ROIs) + +% For Wills singing data: +% n = sort([ 2 4 5 7 11 13 14 15 18 19 20 21 24 27 28 30 31 1 32 33]); + +% For SanneSleep6: (14 ROIs / 8&9, 15&16 overlapped) +% n = [ 1 2 3 4 5 6 7 8 10 11 12 13 14 15 ]; + +% For SanneSleep7 all ROIs: (28 ROIs / top left group / 10&11 overlapped) +% n = [ 1 2 3 4 5 6 7 8 9 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29]; + +% For SanneSleep7 as comparison to Wills: (21 ROIs / top left group / 10&11 overlapped) +% n = [ 2 3 4 5 6 7 8 9 11 12 13 14 15 18 19 21 22 24 25 26 27]; + +% For SanneSleep14 as comparison to Wills: (20 ROIs same as Wills 33=29) +% n = sort([ 2 4 5 7 8 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 30 6 1 3 9]); + +% For SanneSleep16 (26 ROIs - 21 & 22 overlapped) +% n = [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 22 23 24 25 26 27]; + +% For SanneSleep28 (21 ROIs - 4&5, 8&9, 10&11 overlapped) +% n = [ 1 2 3 4 6 7 8 11 12 13 14 15 16 17 18 19 20 21]; + +% For SanneSleep31 (1&2, 4&5, 21&22, 34&35 overlapped) +% n = [ 1 3 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29 30 31 32 33 34 36 ]; +% 20 ROIs picked somewhat randomly (skipped about every other ROI): +% n = [ 1 3 5 8 9 10 12 14 16 18 20 23 25 28 29 30 32 33 34 36 ]; +% 20 ROIs picked on location ("middle" cluster): +% n = [ 6 7 8 9 16 17 18 19 20 21 25 26 27 28 29 30 31 32 34 36 ]; +% n = [ 6 7 8 13 14 15 16 17 18 19 20 21 23 24 25 26 28 29 30 31 ]; + +% For plotting all ROIs: +num_ROIs = size(Spike_Data,2); +n = 1:num_ROIs; + +%% Calculating sizes +num_ROIs = size(n,2); +num_videos = size(Spike_Data,1); +num_frames = size(Spike_Data,3); + +%% Find all frames in which spiking occurred + +AllSpikingFrames = zeros(num_ROIs,num_frames); + +for VideoIter1 = 1: num_videos + + for ROIiter1 = n + [activitylocations] = find(Spike_Data(VideoIter1,ROIiter1,:)>0); + num_spikes = length(activitylocations); + + for SpikeIter = 1:num_spikes + AllSpikingFrames(ROIiter1,SpikeIter)=activitylocations(SpikeIter,1); + end + + clear('activitylocations'); + + end + + AllVideoSpikingFrames{VideoIter1} = AllSpikingFrames; + +end + +% savefilename1 = ['SpikingFrames_' num2str(WindowParameter) 'frameswindow']; +% save(savefilename1,'AllVideoSpikingFrames') + +%% Which ROIs spike at the same time? = Find co-activity + +SpikeTogetherMatrix = []; +Allspikes = {}; + +for video = 1:num_videos + % rows = ROIs; columns = frames + spikes = squeeze(Spike_Data(video, :, :)); + max_frames = size(spikes, 2); + + % find all spikes + [rois, frames] = find(spikes); + + % for everything that spikes + for i = 1:length(rois) + % get the subsequent window + % (everything that spikes in the currrent frame plus the next WindowParameter - 1 frames) + subsequent_spikes = spikes(:, frames(i):min(frames(i) + WindowParameter - 1, max_frames)); + + % prevent double counting (this prevents counting spiking with self + % in the same frame, and prevents counting cospiking rois in the + % same frame multiple times) + subsequent_spikes(1:rois(i), 1) = 0; + + % roi and frame; everything else in subsequent spikes is a unique + % "spike together" with this roi and frame + roi = rois(i); + frame = frames(i); + + [co_rois, co_frames] = find(subsequent_spikes); + co_frames = co_frames + frame - 1; + + if ~isempty(co_rois) + new_rows = [ones(length(co_rois), 1) * roi, co_rois, ones(length(co_rois), 1) * frame, co_frames]; + SpikeTogetherMatrix = [SpikeTogetherMatrix; new_rows]; + end + end +end + +if isempty(SpikeTogetherMatrix) + warning('No spikes detected'); +end + +I = SpikeTogetherMatrix(:,1); +J = SpikeTogetherMatrix(:,2); +frameI = SpikeTogetherMatrix(:,3); +frameJ = SpikeTogetherMatrix(:,4); +SpikeTogetherTable = table(I,J,frameI,frameJ); +SpikeTogetherUnique = unique(SpikeTogetherTable); + +%% Now, make matrices that add up these spikes for each ROI-pair +% and calculate the lag between the ROI-pairs: + +ROIindex = zeros(num_ROIs,num_ROIs); +ROIorder = cell(num_ROIs,num_ROIs); +ROIlags = zeros(num_ROIs,num_ROIs,2); + +% To have same nr of spikes as will's singing data & somewhat equally +% distributed over ROIs, run this instead of the first line below: +% +% SpikeInterval = floor(size(SpikeTogetherUnique,1)/5688); +% for Xiter = 1 : SpikeInterval : SpikeInterval*5688 + +for Xiter = 1 : size(SpikeTogetherUnique,1) + ROIXcoordinate = SpikeTogetherUnique{Xiter,1}; + [~,ROIX,~] = find(n==ROIXcoordinate); + ROIYcoordinate = SpikeTogetherUnique{Xiter,2}; + [~,ROIY,~] = find(n==ROIYcoordinate); + +% % OPTION 1: asymmetric; ignore ROIs spiking in same frame +% if SpikeTogetherUnique{Xiter, 3} == SpikeTogetherUnique{Xiter, 4} +% continue; +% end +% ROIindex(ROIX,ROIY) = ROIindex(ROIX,ROIY)+1; + +% % OPTION 2: assymetric; but count spiking together in same frame on +% % both side +% if SpikeTogetherUnique{Xiter, 3} == SpikeTogetherUnique{Xiter, 4} +% ROIindex(ROIY,ROIX) = ROIindex(ROIY,ROIX)+1; +% end +% ROIindex(ROIX,ROIY) = ROIindex(ROIX,ROIY)+1; + + % OPTION 3: symmetric + ROIindex(ROIX,ROIY) = ROIindex(ROIX,ROIY)+1; + ROIindex(ROIY,ROIX) = ROIindex(ROIY,ROIX)+1; + + ROIorder{ROIX,ROIY}{end+1,1} = (SpikeTogetherUnique{Xiter,4}) - (SpikeTogetherUnique{Xiter,3}); + +end + +% loop through ROIorder cells (X & Y); +% then loop through each lag value in those cells +% (number depends on # co-activities = LagIter) + +for XROIorder = 1:num_ROIs + for YROIorder = 1:num_ROIs + + Lag = {}; + LagMatrix = []; + + for LagIter = 1:length(ROIorder{XROIorder,YROIorder}) + Lag(end+1,1) = (ROIorder{XROIorder,YROIorder}(LagIter,1)); + end + + LagMatrix = cell2mat(Lag); + ROIlags(XROIorder,YROIorder,1) = mean(LagMatrix); + ROIlags(XROIorder,YROIorder,2) = std(LagMatrix); + + end +end + +NrOfSpikesIn2ROIs = sum(sum(ROIindex(:))); + +% ROIlags info: + +% The first dimension (x) is ROIs +% The second (y) is the ROIs they fire with in the window selected +% The third dimension (z) has the mean lag (z1) and standard deviation (z2) + % If there is a positive mean lag with a low std, then cell(x) always + % and robustly leads cell(y); +% If there is a mean lag of around zero with a low std, then cell(x) always +% and robustly fires at the same time as cell(y); + % If there is a mean lag of around zero with a high std, then cell(x) + % might lead sometimes, while it follows cell(y) at other times; +% If there is a negative lag with a low std, then cell(x) always and +% robustly follows cell(y) + % If the value is NaN (not a number), than these ROIs did not fire + % together + + + +%% Stereotyped sequence or random ordering? + +% Determine which ROIs spiked first -- the order will be used for sorting +% the ROIindex as well later (below in the loops) + +AllSeqIndex = []; +ROIseqIndex = []; + +% find which ROIs spiked first in each video +for VideoSeqIter = 1:num_videos + AllVideoSpikingFrames{VideoSeqIter}(AllVideoSpikingFrames{VideoSeqIter}==0)=Inf; + % I want the zeros to come last (cells that haven't spiked) + [SequenceMatrix, SeqIndex] = sortrows((AllVideoSpikingFrames{VideoSeqIter}(:,:)),1); + AllSeqIndex(VideoSeqIter,:) = SeqIndex; + AllVideoSpikingFrames{VideoSeqIter}(AllVideoSpikingFrames{VideoSeqIter}==Inf)=0; +end + +% find the most common ones if there is variation +SeqIndex = []; +for SeqIter1 = 1:size(AllSeqIndex,2) + unqASI = unique(AllSeqIndex(:,SeqIter1)); + % which ROIs ever fired first, or second, etc? + [valueCount,~] = histc(AllSeqIndex(:,SeqIter1),unqASI); + % and how often did each of them fire? + [valueSort,valueIndex] = sort(valueCount,'descend'); + % sort to find the maximum + + CurrComparison = unqASI(valueIndex(1),1); % = the ROI that is most often the first to fire + + for i=2:length(valueIndex) % find a next ROI in line if this ROI already fired earlier + if ismember(CurrComparison,SeqIndex)==1 + CurrComparison = unqASI(valueIndex(i),1); + end + if ismember(CurrComparison,SeqIndex)==1 + where = ismember(n,SeqIndex)==0; + [~,b] = find(where==1); + CurrComparison = n(b(1)); + end + end + + SeqIndex(1,SeqIter1) = CurrComparison; % an array with which ROIs fired first + % most often, which second, etc., ending with ROIs that did not fire +end + +%% Sorting based on brain location: +% Find smallest X & smallest Y pair first = top left ROI +% Sort rest of ROIs based on distance from first coordinates + +num_n = length(n); + +% Make ROI location matrix 'lookuptable': +CoordinateLookup = zeros(num_n,3); % allocate matrix; + +for CoordIter = 1:num_n; + CoordinateLookup(CoordIter,1) = n(CoordIter); % columns 1-3: ROInr, X, Y + CoordinateLookup(CoordIter,2:3) = ROI.stats(n(CoordIter)).Centroid; +end + +% Make matrix in which ROIs are sorted on distance from the top left ROI: +CoordinateSorting = zeros(num_n,4); % columns: ROInr, X, Y, distance to first ROI +d = zeros(num_n,2); % matrix for distances +LocIndex = zeros(1,num_n); + +% Start with top left ROI: +[X,I] = min(CoordinateLookup(:,2)); % = top left ROI +CoordinateSorting(1,1) = n(I(1)); +CoordinateSorting(1,2) = CoordinateLookup(I(1),2); +CoordinateSorting(1,3) = CoordinateLookup(I(1),3); +CoordinateSorting(1,4) = 0; +LocIndex(1,1) = I(1); + + +% Find nearest ROI with precedingly ordered ROI: +for CoordIter2 = 2:num_n; + Coord1 = [CoordinateSorting(CoordIter2-1,2),CoordinateSorting(CoordIter2-1,3)]; % bijv ROI 16 + + % then find distances between all ROIs and previously ordered ROI in d: + for CoordIter3 = 1:num_n; + Coord2 = [CoordinateLookup(CoordIter3,2),CoordinateLookup(CoordIter3,3)]; + CurrComparison = [Coord1;Coord2]; + d(CoordIter3,1) = n(CoordIter3); + d(CoordIter3,2) = pdist(CurrComparison,'euclidean'); + end + clear('X','I'); + [X,I] = sort(d(:,2)); % nearest ROI - X is distance, n(I) is ROI + + % find first ROI that is not yet in the Sorting matrix: + % Find first n(I) isnotmember CoordinateSorting(:,1) + position = ismember(n(I),CoordinateSorting(:,1)); + position = find(position==0,1); + + % Fill in next ROI in Sorting matrix: + CoordinateSorting(CoordIter2,1) = n(I(position)); % ROI + CoordinateSorting(CoordIter2,2) = CoordinateLookup(I(position),2); + CoordinateSorting(CoordIter2,3) = CoordinateLookup(I(position),3); + CoordinateSorting(CoordIter2,4) = X(position); % distance + + LocIndex(1,CoordIter2) = I(position); + +end + +% LocIndex = CoordinateSorting(:,1)'; + +%% Sort ROIindex using SeqIndex: +%SeqIndex = n; % undo all sorting +SeqIndex = symrcm(ROIindex); + +SortedROIindex = ROIindex(SeqIndex, SeqIndex); +LocationROIindex = ROIindex(LocIndex, LocIndex); + + +%% Sort ROIplotting using SeqIndex: +% ROIplotting = SortedROIindex; +ROIplotting = LocationROIindex; + + +%% Prepare data for plotting +ROIplotting(ROIplotting (meansqtemp + 0.2*stdsqtemp); % 0.00001; + SM_Spike_Data(Iter,1,i) = 1; + else + SM_Spike_Data(Iter,1,i) = 0; + end + end + + % Downsample to 200 Hz for plotting with downsampled newdata + a = []; aa = []; + a = squeeze(SM_Spike_Data(Iter,1,:)); + + for i = 1: 50: floor(size(SM_Spike_Data,3))-50 + aa(end+1) = mean(a(i:i+50)); + end + + figure('Name',['Iter_' num2str(Iter)]); + plot(aa); + hold on; + plot(newdata(Iter,:)); + +end + +autoArrangeFigures(3,3) + +save('SM_Spike_Data','SM_Spike_Data'); + diff --git a/SM_imaging_dissimilarity.m b/SM_imaging_dissimilarity.m new file mode 100644 index 0000000..0c29541 --- /dev/null +++ b/SM_imaging_dissimilarity.m @@ -0,0 +1,100 @@ +% load in the normalized center of mass per pixel matrices (512x512 double) +% saved from NP_ActivityAroundSpikes + +% % I used sumv as control (similarity across cells as baseline dissimilarity) + +cellnr = 1; % adjust so that the right traces are selected for plotting +DIR = pwd; +sumvlist = dir(fullfile(DIR,'*.mat')); % use for sleeping data +sumvlist = {sumvlist(:).name}; +NrSpikes = length(sumvlist); + +% prepare matrices for pixel mass dissimilarity scores: +total_array = []; +d = zeros(NrSpikes, NrSpikes); +sumd = []; + +% prepare matrices for ROI trace dissimilarity scores: +total_traces = []; +d2 = zeros(NrSpikes, NrSpikes); +sumd2 = []; + +% Combine all mass matrices into one array: +for iter = 1:NrSpikes + [~,file,~] = fileparts(sumvlist{iter}); + load(fullfile(DIR,sumvlist{iter}), 'im_*'); + load(fullfile(DIR,sumvlist{iter}), 'traces'); + + % now that we know the image dimensions, setup our matrices + if iter == 1 + total_array = zeros(NrSpikes, size(im_mass, 1), size(im_mass, 2)); + total_traces = zeros(NrSpikes, size(traces, 1), size(traces, 2)); + end + + % add image to array + total_array(iter, :, :) = im_mass .* im_std; + total_traces(iter, :, :) = traces; +end + +% make difference matrix 'd' & summed dissimilarity vector 'sumd': +for i = 1:NrSpikes + for j = 1:NrSpikes + if j>i; + difference = total_array(i, :, :) - total_array(j, :, :); + d(i, j) = mean(abs(difference(:))); % MAE: mean absolute error + sumd(end+1) = d(i, j); + + difference2 = total_traces(i, :, :) - total_traces(j, :, :); + d2(i, j) = mean(abs(difference2(:))); + sumd2(end+1) = d2(i, j); + end + end +end + +% save summed dissimilarity vector for all sleep cells: +save('Dissimilarity_matrix','sumd', 'sumd2','total_traces','-v7.3') + +% plot summed dissimilarity distribution: +figure(1); hold on; title('Dissimilarity histogram pixel mass'); +hist(sumd, 200); hold off +saveas(1,'Dissimilarity Histogram Pixel Mass.eps') + +figure(2); hold on; title('Dissimilarity histogram traces'); +hist(sumd2, 200); hold off +saveas(2,'Dissimilarity Histogram Traces.eps') + +tracedata = squeeze(total_traces(:,cellnr,:)); +figure(3); plot_many(tracedata') +saveas(3,'Spike Traces.eps') + +% %% dissimilarity between-cells as control +% +% % Make sure sumv singing and sumv sleep are loaded into the workspace +% +% control_sumv_sleep = sumv_out_sleep; +% [a,b] = size(control_sumv_sleep); +% +% for i = 1:a +% tt = control_sumv_sleep(i,:); +% tt(9900:11000) = mean(tt); +% tt = tt-mean(tt); +% control_sumv_sleep(i,:) = (tt-mean(tt))/(std(tt)); +% end +% +% d = zeros(a); +% for i = 1:a +% for j = 1:a +% d(i,j) = sum(abs(control_sumv_sleep(i,:)-control_sumv_sleep(j,:))); +% end +% end +% +% % make summed dissimilarity vector: +% sumd_control_sleep = [d(1:length(d)*length(d))]; +% +% % save summed dissimilarity vector for all sleep cells: +% save('Control_Sleep_RA_dissimilarity_matrix','sumd_control_sleep') +% +% % plot summed dissimilarity distribution: +% figure() +% hist(sumd_control_sleep,200) +% xlim([1 3e4]); diff --git a/SM_just_roi.m b/SM_just_roi.m index efc5a3f..db6fa90 100644 --- a/SM_just_roi.m +++ b/SM_just_roi.m @@ -2,11 +2,11 @@ % ROIS is a cell array of image indices returned by FS_image_roi % VARIABLES -ave_fs=30; % frame rate -duration=30; % movie duration in seconds +%ave_fs=30; % frame rate +%duration=30; % movie duration in seconds %ave_fs_i=20*ave_fs; % after interpolation resize = 1; -colors=eval(['winter(' num2str(length(ROI.coordinates)) ')']); +colors=eval(['winter(' num2str(length(ROI.stats)) ')']); sono_colormap='hot'; save_dir='roi'; template=[]; @@ -17,8 +17,8 @@ if resize~=1 disp(['Adjusting ROIs for resizing by factor ' num2str(resize)]); - for VideoIter=1:length(ROI.coordinates) - ROI.coordinates{VideoIter}=round(ROI.coordinates{VideoIter}.*resize); + for VideoIter=1:length(ROI.stats) + ROI.stats{VideoIter}=round(ROI.stats{VideoIter}.*resize); end end @@ -41,15 +41,18 @@ load(fullfile(pwd,mov_listing{1}),'video'); mov_data_temp = video.frames; for VideoIter = 1:length(mov_data_temp) - mov_data(:,:,VideoIter) = mov_data_temp(VideoIter).cdata; -end +% mov_data_temp(VideoIter) + mov_data(:,:,:,VideoIter) = mov_data_temp(VideoIter).cdata; + end mov_data = double(mov_data); [rows,columns,frames]=size(mov_data); -t = 1/ave_fs % seconds/frame -ave_time = (t):(t):(duration); -number_of_frames = length(ave_time) +%t = 1/ave_fs % seconds/frame +%ave_time = (t):(t):(duration); +ave_time = 1/30:1/30:length(video.frames)/30; +%number_of_frames = length(ave_time) +%number_of_frames = video.nrFramesTotal roi_ave.raw={}; clear mov_data % to allow looping through each video below @@ -73,7 +76,7 @@ save_file=[ file '_roi' ]; [~,~,frames] = size(mov_data); %[rows,columns,frames] - roi_n = length(ROI.coordinates); + roi_n = length(ROI.stats); roi_data = zeros(roi_n,frames); %% extract mean values per frame in each ROI circle @@ -89,7 +92,7 @@ fprintf(1,formatstring,round((ROIiter/roi_n)*100)); for FrameIter2 = 1:frames - roi_data_tmp = mov_data(ROI.coordinates{ROIiter}(:,2),ROI.coordinates{ROIiter}(:,1),FrameIter2); + roi_data_tmp = mov_data(ROI.stats(ROIiter).ConvexHull(:,2),ROI.stats(ROIiter).ConvexHull(:,1),FrameIter2); roi_data(ROIiter,FrameIter2,:) = mean(roi_data_tmp(:)); end end diff --git a/SM_spikevideos_MoCoBS.m b/SM_spikevideos_MoCoBS.m new file mode 100644 index 0000000..10916ba --- /dev/null +++ b/SM_spikevideos_MoCoBS.m @@ -0,0 +1,82 @@ +% clear all; close all; + +% Make folders: +mat_dir = 'SpikeVideos'; +if exist(mat_dir,'dir'); + rmdir(mat_dir,'s'); % remove folder with subfolders +end +mkdir(mat_dir); + +mat_dir2 = 'DffMoCoVideos'; +if exist(mat_dir2,'dir'); + rmdir(mat_dir2,'s'); % remove folder with subfolders +end +mkdir(mat_dir2); + +DIR=pwd; + +% load('image_roi/roi_data_image.mat'); + +% Make list of videos +mov_listing = dir(fullfile(DIR,'MoCo_MOVIES','*.mat')); +mov_listing = {mov_listing(:).name} % reports which movies it found +data_listing = dir(fullfile(DIR,'MoCoBSBagels_5frameswindow','*.mat')); +data_listing = {data_listing(:).name}; + +[nblanks formatstring]=progressbar(length(data_listing)); % start progressbar +fprintf(1,['Progress: ' blanks(nblanks) ]); + +% Loop through Dff (all videos; 1st half of data_listing) +for videoIter = 1:length(mov_listing); + + fprintf(1,formatstring,videoIter); % update progressbar + fprintf(['/' num2str(length(mov_listing)), '\n\n'] ); + tic + + [~,file,~] = fileparts(mov_listing{videoIter}); + load(fullfile(DIR,'MoCo_MOVIES',mov_listing{videoIter}),'video_reg'); + load(fullfile(DIR,'MoCoBSBagels_5frameswindow',data_listing{videoIter})); + + savefilename1 = ['SpikeVideos/SpikeROIvideo_' data_listing{videoIter} '.avi']; + savefilename2 = ['SpikeVideos/SpikeROIvideo_' data_listing{videoIter}]; + savefilename3 = ['DffMoCoVideos/DffBS_' mov_listing{videoIter} '.avi']; + savefilename4 = ['DffMoCoVideos/DffBS_' mov_listing{videoIter}]; + + % make dff video: + video_dff = NP_Dff(video_reg(:,:,30:end-30), 'clim', [0 1]); + % save video (avi & mat): + video_write(savefilename3, video_dff, 30); + video_dff = im2uint16(video_dff); + save(savefilename4,'video_dff','-v7.3'); + + toc + fprintf(1,['\nDffVideo\t', num2str(videoIter), '/', num2str(length(mov_listing)), '\n\n'] ); + + % draw circles around active ROIs based on DffBS spikes: + video_rgb = NP_DrawROIs(video_dff, ROI, squeeze(Spike_Data(1, :, :))); + % save video with spikes (avi & mat): + video_write(savefilename1, video_rgb, 30); + video_rgb = im2uint16(video_rgb); + save(savefilename2,'video_rgb','-v7.3'); + + toc + fprintf(1,['\nSpikeVideoDff\t', num2str(videoIter), '/', num2str(length(mov_listing)), '\n\n'] ); + + clear('Spike_Data') + load(fullfile(DIR,'MoCoBSBagels_5frameswindow',data_listing{(videoIter+length(mov_listing))})); + savefilename1 = ['SpikeVideos/SpikeROIvideo_' data_listing{(videoIter+length(mov_listing))} '.avi']; + savefilename2 = ['SpikeVideos/SpikeROIvideo_' data_listing{(videoIter+length(mov_listing))}]; + + % draw circles around active ROIs: + video_rgb = NP_DrawROIs(video_dff, ROI, squeeze(Spike_Data(1, :, :))); + % save video with spikes (avi & mat): + video_write(savefilename1, video_rgb, 30); + video_rgb = im2uint16(video_rgb); + save(savefilename2,'video_rgb','-v7.3'); + + toc + fprintf(1,['\nSpikeVideoAnnuli\t', num2str(videoIter), '/', num2str(length(mov_listing)), '\n\n'] ); + +end + +fprintf(1,'\n'); % end progressbar diff --git a/SM_videos_dissimilarity.m b/SM_videos_dissimilarity.m new file mode 100644 index 0000000..30d5779 --- /dev/null +++ b/SM_videos_dissimilarity.m @@ -0,0 +1,118 @@ +% load in the videos with activity around spikes +% saved from NP_ActivityAroundSpikes + +DIR = pwd; +videolist = dir(fullfile(DIR,'*raw.mp4')); +videolist = {videolist(:).name}; +NrSpikes = length(videolist); +n = [1]; % ROIs of interest + +% prepare matrices for video dissimilarity scores: +total_array = []; +d = zeros(NrSpikes, NrSpikes); +difference = []; +sumd = []; + +% Load in video: +for iter = 1:NrSpikes + [~,file,~] = fileparts(videolist{iter}); + video = video_read(fullfile(DIR,videolist{iter})); + if 4 == ndims(video) + video = video_rgb2gray(video); + end + + % now that we know the dimensions, setup our matrices + if iter == 1 + total_array = zeros(NrSpikes, size(video, 1), size(video, 2), size(video, 3)); + end + + % add image to array + total_array(iter, :, :, :) = video; + +end + +% make difference matrix 'd' & summed dissimilarity vector 'sumd': +for i = 1:NrSpikes + for j = (i+1):NrSpikes + % subtract videos from each other frame by frame + temp = total_array(i, :, :, :) - total_array(j, :, :, :); + + % save subtracted images: + % std image: + diff = std(squeeze(temp),1,3); + figure(); imagesc(diff); colormap('gray(2555'); + savefilename = (['Subtracted_ROIs' num2str(i) '-' num2str(j) 'Std.jpg']); + saveas(gcf, savefilename); close(gcf); + % mean image: + diff = mean(squeeze(temp),3); + figure(); imagesc(diff); colormap('gray(2555'); + savefilename = (['Subtracted_ROIs' num2str(i) '-' num2str(j) 'Mean.jpg']); + saveas(gcf, savefilename); close(gcf); + + % Make sumd vector: + d(i, j) = mean(abs(temp(:))); % MAE: mean absolute error + sumd(end+1) = d(i, j); + end +end + +% save summed dissimilarity vector for all sleep cells: +save('Dissimilarity_matrix','sumd','-v7.3') + +% plot summed dissimilarity distribution: +figure(1); hold on; title('Dissimilarity histogram videos'); +hist(sumd, 200); hold off +saveas(1,'Dissimilarity Histogram videos.eps') + +%% ROI based approach + +DIR = pwd; +traceslist = dir(fullfile(DIR,'2016*.mat')); +traceslist = {traceslist(:).name}; +NrSpikes = length(traceslist); + +% prepare matrices for video dissimilarity scores: +traces_sumd = []; + +% Load in data: +for iter = 1:NrSpikes + [~,file,~] = fileparts(traceslist{iter}); + data = load(fullfile(DIR,traceslist{iter}),'traces'); + + % now that we know the dimensions, setup our matrices + if iter == 1 + traces_array = zeros(NrSpikes, length(n), size(data.traces,2)); + end + + % add data to array + for ROIiter = 1:length(n); + traces_array(iter, ROIiter, :) = data.traces(n(ROIiter),:); + end + +end + +% make difference matrix 'd' & summed dissimilarity vector 'sumd': +for i = 1:NrSpikes + for j = (i+1):NrSpikes + % subtract videos from each other ROI by ROI + for ROIiter = 1:length(n) + temp = traces_array(i, ROIiter, :) - traces_array(j, ROIiter, :); + d(i, j) = mean(abs(temp(:))); % MAE: mean absolute error + traces_sumd(end+1) = d(i, j); + end + end +end + +% save summed dissimilarity vector for all sleep cells: +save('Dissimilarity_traces','traces_sumd','traces_array','-v7.3') + +% plot summed dissimilarity distribution: +figure(2); hold on; title('Dissimilarity histogram traces'); +hist(traces_sumd, 200); hold off +saveas(2,'Dissimilarity Histogram traces.eps') + +%% + +% %% dissimilarity controls +% Non-ROI area in video corrected for area size +% Subtract traces from different cells from each other +% (should result in larger dissimilarity scores) \ No newline at end of file diff --git a/dftregistration.m b/dftregistration.m new file mode 100755 index 0000000..1f2c1b9 --- /dev/null +++ b/dftregistration.m @@ -0,0 +1,212 @@ + + +function [output Greg] = dftregistration(buf1ft,buf2ft,usfac) +% function [output Greg] = dftregistration(buf1ft,buf2ft,usfac); +% Efficient subpixel image registration by crosscorrelation. This code +% gives the same precision as the FFT upsampled cross correlation in a +% small fraction of the computation time and with reduced memory +% requirements. It obtains an initial estimate of the crosscorrelation peak +% by an FFT and then refines the shift estimation by upsampling the DFT +% only in a small neighborhood of that estimate by means of a +% matrix-multiply DFT. With this procedure all the image points are used to +% compute the upsampled crosscorrelation. +% Manuel Guizar - Dec 13, 2007 + +% Portions of this code were taken from code written by Ann M. Kowalczyk +% and James R. Fienup. +% J.R. Fienup and A.M. Kowalczyk, "Phase retrieval for a complex-valued +% object by using a low-resolution image," J. Opt. Soc. Am. A 7, 450-458 +% (1990). + +% Citation for this algorithm: +% Manuel Guizar-Sicairos, Samuel T. Thurman, and James R. Fienup, +% "Efficient subpixel image registration algorithms," Opt. Lett. 33, +% 156-158 (2008). + +% Inputs +% buf1ft Fourier transform of reference image, +% DC in (1,1) [DO NOT FFTSHIFT] +% buf2ft Fourier transform of image to register, +% DC in (1,1) [DO NOT FFTSHIFT] +% usfac Upsampling factor (integer). Images will be registered to +% within 1/usfac of a pixel. For example usfac = 20 means the +% images will be registered within 1/20 of a pixel. (default = 1) + +% Outputs +% output = [error,diffphase,net_row_shift,net_col_shift] +% error Translation invariant normalized RMS error between f and g +% diffphase Global phase difference between the two images (should be +% zero if images are non-negative). +% net_row_shift net_col_shift Pixel shifts between images +% Greg (Optional) Fourier transform of registered version of buf2ft, +% the global phase difference is compensated for. + +% Default usfac to 1 +if exist('usfac')~=1, usfac=1; end + +% Compute error for no pixel shift +if usfac == 0, + CCmax = sum(sum(buf1ft.*conj(buf2ft))); + rfzero = sum(abs(buf1ft(:)).^2); + rgzero = sum(abs(buf2ft(:)).^2); + error = 1.0 - CCmax.*conj(CCmax)/(rgzero*rfzero); + error = sqrt(abs(error)); + diffphase=atan2(imag(CCmax),real(CCmax)); + output=[error,diffphase]; + +% Whole-pixel shift - Compute crosscorrelation by an IFFT and locate the +% peak +elseif usfac == 1, + [m,n]=size(buf1ft); + CC = ifft2(buf1ft.*conj(buf2ft)); + [max1,loc1] = max(CC); + [max2,loc2] = max(max1); + rloc=loc1(loc2); + cloc=loc2; + CCmax=CC(rloc,cloc); + rfzero = sum(abs(buf1ft(:)).^2)/(m*n); + rgzero = sum(abs(buf2ft(:)).^2)/(m*n); + error = 1.0 - CCmax.*conj(CCmax)/(rgzero(1,1)*rfzero(1,1)); + error = sqrt(abs(error)); + diffphase=atan2(imag(CCmax),real(CCmax)); + md2 = fix(m/2); + nd2 = fix(n/2); + if rloc > md2 + row_shift = rloc - m - 1; + else + row_shift = rloc - 1; + end + + if cloc > nd2 + col_shift = cloc - n - 1; + else + col_shift = cloc - 1; + end + output=[error,diffphase,row_shift,col_shift]; + +% Partial-pixel shift +else + + % First upsample by a factor of 2 to obtain initial estimate + % Embed Fourier data in a 2x larger array + [m,n]=size(buf1ft); + mlarge=m*2; + nlarge=n*2; + CC=zeros(mlarge,nlarge); + CC(m+1-fix(m/2):m+1+fix((m-1)/2),n+1-fix(n/2):n+1+fix((n-1)/2)) = ... + fftshift(buf1ft).*conj(fftshift(buf2ft)); + + % Compute crosscorrelation and locate the peak + CC = ifft2(ifftshift(CC)); % Calculate cross-correlation + [max1,loc1] = max(CC); + [max2,loc2] = max(max1); + rloc=loc1(loc2);cloc=loc2; + CCmax=CC(rloc,cloc); + + % Obtain shift in original pixel grid from the position of the + % crosscorrelation peak + [m,n] = size(CC); md2 = fix(m/2); nd2 = fix(n/2); + if rloc > md2 + row_shift = rloc - m - 1; + else + row_shift = rloc - 1; + end + if cloc > nd2 + col_shift = cloc - n - 1; + else + col_shift = cloc - 1; + end + row_shift=row_shift/2; + col_shift=col_shift/2; + + % If upsampling > 2, then refine estimate with matrix multiply DFT + if usfac > 2, + %%% DFT computation %%% + % Initial shift estimate in upsampled grid + row_shift = round(row_shift*usfac)/usfac; + col_shift = round(col_shift*usfac)/usfac; + dftshift = fix(ceil(usfac*1.5)/2); %% Center of output array at dftshift+1 + % Matrix multiply DFT around the current shift estimate + CC = conj(dftups(buf2ft.*conj(buf1ft),ceil(usfac*1.5),ceil(usfac*1.5),usfac,... + dftshift-row_shift*usfac,dftshift-col_shift*usfac))/(md2*nd2*usfac^2); + % Locate maximum and map back to original pixel grid + [max1,loc1] = max(CC); + [max2,loc2] = max(max1); + rloc = loc1(loc2); cloc = loc2; + CCmax = CC(rloc,cloc); + rg00 = dftups(buf1ft.*conj(buf1ft),1,1,usfac)/(md2*nd2*usfac^2); + rf00 = dftups(buf2ft.*conj(buf2ft),1,1,usfac)/(md2*nd2*usfac^2); + rloc = rloc - dftshift - 1; + cloc = cloc - dftshift - 1; + row_shift = row_shift + rloc/usfac; + col_shift = col_shift + cloc/usfac; + + % If upsampling = 2, no additional pixel shift refinement + else + rg00 = sum(sum( buf1ft.*conj(buf1ft) ))/m/n; + rf00 = sum(sum( buf2ft.*conj(buf2ft) ))/m/n; + end + error = 1.0 - CCmax.*conj(CCmax)/(rg00*rf00); + error = sqrt(abs(error)); + diffphase=atan2(imag(CCmax),real(CCmax)); + % If its only one row or column the shift along that dimension has no + % effect. We set to zero. + if md2 == 1, + row_shift = 0; + end + if nd2 == 1, + col_shift = 0; + end + output=[error,diffphase,row_shift,col_shift]; +end + +% Compute registered version of buf2ft +if (nargout > 1)&&(usfac > 0), + [nr,nc]=size(buf2ft); + Nr = ifftshift([-fix(nr/2):ceil(nr/2)-1]); + Nc = ifftshift([-fix(nc/2):ceil(nc/2)-1]); + [Nc,Nr] = meshgrid(Nc,Nr); + Greg = buf2ft.*exp(i*2*pi*(-row_shift*Nr/nr-col_shift*Nc/nc)); + Greg = Greg*exp(i*diffphase); +elseif (nargout > 1)&&(usfac == 0) + Greg = buf2ft*exp(i*diffphase); +end +return + +function out=dftups(in,nor,noc,usfac,roff,coff) +% function out=dftups(in,nor,noc,usfac,roff,coff); +% Upsampled DFT by matrix multiplies, can compute an upsampled DFT in just +% a small region. +% usfac Upsampling factor (default usfac = 1) +% [nor,noc] Number of pixels in the output upsampled DFT, in +% units of upsampled pixels (default = size(in)) +% roff, coff Row and column offsets, allow to shift the output array to +% a region of interest on the DFT (default = 0) +% Recieves DC in upper left corner, image center must be in (1,1) +% Manuel Guizar - Dec 13, 2007 +% Modified from dftus, by J.R. Fienup 7/31/06 + +% This code is intended to provide the same result as if the following +% operations were performed +% - Embed the array "in" in an array that is usfac times larger in each +% dimension. ifftshift to bring the center of the image to (1,1). +% - Take the FFT of the larger array +% - Extract an [nor, noc] region of the result. Starting with the +% [roff+1 coff+1] element. + +% It achieves this result by computing the DFT in the output array without +% the need to zeropad. Much faster and memory efficient than the +% zero-padded FFT approach if [nor noc] are much smaller than [nr*usfac nc*usfac] + +[nr,nc]=size(in); +% Set defaults +if exist('roff')~=1, roff=0; end +if exist('coff')~=1, coff=0; end +if exist('usfac')~=1, usfac=1; end +if exist('noc')~=1, noc=nc; end +if exist('nor')~=1, nor=nr; end +% Compute kernels and obtain DFT by matrix products +kernc=exp((-i*2*pi/(nc*usfac))*( ifftshift([0:nc-1]).' - floor(nc/2) )*( [0:noc-1] - coff )); +kernr=exp((-i*2*pi/(nr*usfac))*( [0:nor-1].' - roff )*( ifftshift([0:nr-1]) - floor(nr/2) )); +out=kernr*in*kernc; +return diff --git a/example_DataAnalysis_NP20160510.m b/example_DataAnalysis_NP20160510.m new file mode 100644 index 0000000..e0080fc --- /dev/null +++ b/example_DataAnalysis_NP20160510.m @@ -0,0 +1,29 @@ +%% BACKGROUND SUBTRACTION, NO BAGELS + +% make dff +video_dff = NP_Dff(video.frames(30:end-30), 'clim', [0 1]); +%video_dff = NP_Dff(video_a, 'clim', [0 1]); + +% extract ROIs +ave_roi = NP_ExtractROIs(video_dff, ROI, 0); % 0 means no bagsels or donuts + +% extract spikes +[Av_Data, Trace_Data, Spike_Data] = NP_From_Raw_To_Traces({ave_roi}, 2); + +%% NO BACKGROUND SUBTRACTION, YES BAGELS +% +% % extract ROI +% ave_roi = NP_ExtractROIs(video.frames(30:end-30), ROI, 1); % 1 means yes bagels +% +% % extract spikes +% [~, ~, spikes] = NP_From_Raw_To_Traces({ave_roi}, 2); + +%% NO BACKGROUND SUBTRACTION, YES BAGELS -- "full version" + +close all; clear all +load('LNY20RB_RH_9-7-15_SanneSleep6(6).mat') +load('image_roi/roi_data_image.mat'); +ave_roi = NP_ExtractROIs(video.frames(30:end-30), ROI, 1); % 1 means yes bagels +[Av_Data, Trace_Data, Spike_Data] = NP_From_Raw_To_Traces({ave_roi}, 2); +SM_SortedSpikeAnalysis +save('Video6_ave_roi_SpikeData_NoBkgrSubYesBagels') \ No newline at end of file diff --git a/example_comparison.m b/example_comparison.m new file mode 100644 index 0000000..f711686 --- /dev/null +++ b/example_comparison.m @@ -0,0 +1,46 @@ +% load comparison data +load('../Comparison/ROI_data_cleansed.mat'); +load('../Comparison/roi_spatial_stats.mat'); + +% read in video +video_gs = video_read('../Comparison/2016-01-21 07 06 34.mov'); +video_gs = video_rgb2gray(video_gs); + +% convert ROI format +% roi_stats(5) corresponds with 2016-01-21 +ROI = struct('stats', roi_stats(5).bw_stats); + +% extract roi_ave +donut = 1; +roi_trace = NP_ExtractROIs(video_gs(:, :, 5:end), ROI, donut); + +% show traces +figure; +n = size(roi_trace, 1); % number of regions +t = (1:size(roi_trace, 2)) ./ 30; %times +clrs = lines(n); % make colorful lines +subplot(1, 3, 1); % plot image for reference +im_summary = mean(video_gs, 3); +imshow(imadjust(im_summary ./ max(im_summary(:)))); +for i = 1:n + h = viscircles(ROI.stats(i).Centroid, ROI.stats(i).Diameter / 2, 'Color', clrs(i, :)); +end +subplot(1, 3, 2); % plot area for traces +plot_many(t, roi_trace', clrs); +subplot(1, 3, 3); % plot spikes +[~, ~, spikes] = NP_From_Raw_To_Traces({roi_trace}, 2); +%[~, ~, spikes] = Byrons_From_Raw_To_Traces({roi_trace}); +plot_many(squeeze(spikes(1, :, :))'); + +% make dff +video_dff = NP_Dff(video_gs(:, :, 5:end)); + +% annotate ROIS +video_rgb = NP_DrawROIs(video_dff, ROI, squeeze(spikes(1, :, :))); +if 0 < donut + video_write('donut_dff_2016-01-21 07 06 34.avi', video_rgb, 30); + print(gcf, 'donut_trace_2016-01-21 07 06 34.avi', '-dpng', '-r300'); +else + video_write('dff_2016-01-21 07 06 34.avi', video_rgb, 30); + print(gcf, 'trace_2016-01-21 07 06 34.avi', '-dpng', '-r300'); +end diff --git a/example_dff_roi.m b/example_dff_roi.m new file mode 100644 index 0000000..96adf33 --- /dev/null +++ b/example_dff_roi.m @@ -0,0 +1,13 @@ +% loading +load('LNY20RB_RH_9-7-15_SanneSleep6(7).mat'); +load('roi/Spontaneous_Data.mat'); +load('image_roi/roi_data_image.mat'); + +% make dff +video_dff = NP_Dff(video.frames(30:end-30)); + +% draw rois +video_rgb = NP_DrawROIs(video_dff, ROI, squeeze(Spike_Data(1, :, :))); + +% save +video_write('dff_LNY20RB_RH_9-7-15_SanneSleep6(7).avi', video_rgb, 30); diff --git a/example_plumes.m b/example_plumes.m new file mode 100644 index 0000000..7573467 --- /dev/null +++ b/example_plumes.m @@ -0,0 +1,41 @@ +% load video +VidName = 'SanneSleep31_LNY19RB_1minSpont_1218_(1).mat' +load(VidName); + +% concatenate into simpler format +video = cat(3, video.frames(30:end-30).cdata); % if unclipped video +%video = cat(3, video1(30:end-30).cdata); % if clipped video (adjust video#) + +% calculate plumes +indices = NP_ExtractPlumes(video); + +% calculate dff +video_dff = NP_Dff(video); + +durations = []; +intervals = []; + +% for each plume... +for i = 1:size(indices, 1) + + % get start and stop indices + strt = indices(i, 1); + stop = indices(i, 2); + + durations(end+1) = (stop-strt); + if i ~= size(indices,1); + intervals(end+1) = indices(i+1,1)-stop; + end + + % save video + video_write(sprintf('plume%d.avi', i), video_dff(:, :, strt:stop)); + + % save image + im = NP_PixelMass(video(:, :, strt:stop)); + imwrite(im, sprintf('plume%d.jpg', i)); +end + +PlumeIntervalFiles{end+1} = VidName; +PlumeIntervals(end+1) = ((size(video,3)/30)/size(indices,1)); +PlumeAllDurations = [PlumeAllDurations durations]; +PlumeAllIntervals = [PlumeAllIntervals intervals]; \ No newline at end of file diff --git a/extract_spikes_traces.m b/extract_spikes_traces.m new file mode 100644 index 0000000..aca24e9 --- /dev/null +++ b/extract_spikes_traces.m @@ -0,0 +1,66 @@ +% load video +% load Spontaneous_Data + +% concatenate into simpler format +video = cat(3, video.frames(30:end-30).cdata); % if unclipped video +%video = cat(3, video1(30:end-30).cdata); % if clipped video (adjust video#) + + +videoname = 'Video(1)'; +window_before = 30; +window_after = 30; +total_length = window_before + 1 + window_after; +fs = 30; + +% Maybe add something here were I can select a certain cell + +% New matrices -- select ROI of interest +cell18 = find(Spike_Data(1,18,:)); +extraction18 = zeros(length(cell18), 2); +roi_trace = squeeze(Trace_Data(1,:,:)); + +% Save all spiking indices: +indices = zeros(length(cell18),2); +for i = 1:length(cell18) + indices(i,1) = (cell18(i) - window_before); + indices(i,2) = (cell18(i) - window_after); +end + +num_spikes = size(indices, 1); +num_frames = indices(1, 2) - indices(1, 1); + +% prepare matrices to save all traces +sum_traces = zeros(num_spikes, num_frames); +images = []; + +% for each spike... +for i = 1:num_spikes + + % get start and stop indices + strt = indices(i, 1); + stop = indices(i, 2); + + % Check if windows don't overlap: + + % Make sum_traces matrix - here for ROI 18 + sum_traces(i,:) = Trace_Data(1, 18, strt:stop); % adjust for ROI# + + % save video + video_write(sprintf('spike%d.avi', i), video(:, :, strt:stop)); + + % save image + im = NP_PixelMass(video(:, :, strt:stop)); + imwrite(im, sprintf('spike%d.jpg', i)); + + % Save max projection images: + StdProj = std(images,0,3); % 0 = no weighting, 3 = std over 3rd dimension of matrix + % colormap(bone); + % figure(); imagesc(StdProj); + maX18 = mat2gray(StdProj); + maX18 = im2uint16(maX18); + save_filename = ([videoname '_STD_cell18_' num2str(indices(i,1)) '-' num2str(indices(i,2)) '.png']); + imwrite(maX18,save_filename,'png'); + +end + + diff --git a/plot_ica.m b/plot_ica.m new file mode 100644 index 0000000..0082496 --- /dev/null +++ b/plot_ica.m @@ -0,0 +1,47 @@ +function plot_ica(ica_sig, mixing, height, width, rows, cols) +%PLOT_ICA Plot ICA results +% Just a bunch of code to get traces and components next to each other. +% The code uses subplots to make a nice combined figure. + +% default sizing +if ~exist('rows', 'var') || isempty(rows) + rows = 3; +end +if ~exist('cols', 'var') || isempty(cols) + cols = 3; +end + +% subplot indices +sp_components = []; +sp_traces = []; + +% kludgy, but easier to reason about +% figure out subplot indices for each +for j = 1:rows + for k = 1:(2 * cols) + i = (j - 1) * 2 * cols + k; + if k <= cols + sp_components(end + 1) = i; %#ok + else + sp_traces(end + 1) = i; %#ok + end + end +end + +figure; + +% left side: components +for i = 1:(rows * cols) + subplot(rows, cols * 2, sp_components(i)); + imagesc(reshape(mixing(:, i) * sign(median(mixing(:, i))), height, width)); + title(sprintf('Component %d', i)); +end + +% right side: traces +subplot(rows, cols * 2, sp_traces); +% because ICA is scale invariant, traces may be inverted +% as a result, the sign(median(mixing)) is used to get a consistent +% calcium-esque trace scaling where spikes are positive +plot_many(bsxfun(@times, ica_sig(1:(rows * cols), :)', sign(median(mixing(:, 1:(rows * cols)))))); + +end diff --git a/plot_many.m b/plot_many.m new file mode 100644 index 0000000..c20dab0 --- /dev/null +++ b/plot_many.m @@ -0,0 +1,89 @@ +function plot_many(x, ys, clrs, labels, range) +%PLOT_MANY Plot multiple lines +% All lines (one per column of ys) are plotted, spaced out equally and +% consistently normalized. This is useful for comparing time synchronized +% spike or region traces. +% +% Arguments: +% +% x - The x coordinates shared by all lines (vector). +% +% ys - Matrix of lines or traces to plot, with each column corresponding +% to a line. +% +% cls - (Optional.) The colors to use for each line (matrix). If there +% are more lines than colors, then the colors will be cycled +% through in order. +% +% labels - (Optional.) Labels for each line (cell). Provide an empty +% vector to skip printing labels, otherwise provide a cell array +% with the same number of entries as there are columns in ys. +% +% range - (Optional.) The range used when normalizing each trace. This +% defaults to the range of the largest trace in ys, but you can +% pass in either a scalar single range or a vector of ranges +% corresponding to the number of columns in ys. + +% support single argument +if nargin == 1 + ys = x; + x = 1:size(ys, 1); +end + +% number of lines to plot +y_count = size(ys, 2); + +% default colors +if ~exist('clrs', 'var') || isempty(clrs) + clrs = lines(y_count); % make colorful lines +end +clr_count = size(clrs, 1); + +% default labels +if ~exist('labels', 'var') + labels = cell(1, y_count); + for i = 1:y_count + labels{i} = num2str(i); + end +end + +% check variables +if size(ys, 1) ~= length(x) + error('The length of vector x (%d) must match the number of rows in matrix ys (%d).', length(x), size(ys, 1)); +end +if 3 ~= size(clrs, 2) + error('The color matrix must have three columns (found %d).', size(clrs, 2)); +end +if ~isempty(labels) && length(labels) ~= y_count + error('The length of the labels cell array (%d) must match the number of columns in matrix ys (%d).', length(labels), y_count); +end + +% normalize lines +mn = min(ys, [], 1); +if ~exist('range', 'var') + mx = max(ys, [], 1); + range = max(mx - mn); +end +ys = bsxfun(@minus, ys, mn); +ys = bsxfun(@rdivide, ys, range); + +% plot +xlim([x(1) x(end)]); +ylim([0 y_count]); +xlabel('Time (frames)'); +if isempty(labels) + % no labels + set(gca, 'YTick', []); +else + set(gca, 'YTick', 0.5:1:(y_count - 0.5), 'YTickLabel', labels(end:-1:1)); +end +hold on; +for i = 1:y_count + % get line + y = ys(:, i); + plot(x, y_count - i + y, 'Color', clrs(1 + mod(i - 1, clr_count), :)); +end +hold off; + +end + diff --git a/plot_rastergram.m b/plot_rastergram.m new file mode 100644 index 0000000..b026bd7 --- /dev/null +++ b/plot_rastergram.m @@ -0,0 +1,89 @@ +function plot_rastergram(tm, spikes, varargin) +%PLOT_RASTERGRAM Plots a rastergram composed of horizontal bars at spikes +% Requires two parameters: +% +% tm: Either a vector of times corresponding with the number of columns +% in spikes, or a scalar representing the same rate of the data +% (frequency). +% +% spikes: A logical matrix with rows corresponding with rows in the plot +% and columns representing time. Each true will be plotted as a +% single vertical line in the rastergram. + +%% parameters + +line_width = 1; +colors = [0 0 0]; +labels = 1:size(spikes, 1); + +% load custom parameters +nparams = length(varargin); +if 0 < mod(nparams, 2) + error('Parameters must be specified as parameter/value pairs'); +end +for i = 1:2:nparams + nm = lower(varargin{i}); + if ~exist(nm, 'var') + error('Invalid parameter: %s.', nm); + end + eval([nm ' = varargin{i+1};']); +end + +%% setup + +num_rw = size(spikes, 1); % rows / ROIs +num_tm = size(spikes, 2); % times +num_clrs = size(colors, 1); + +% accept frequency +if isscalar(tm) + tm = (0:(num_tm - 1)) ./ tm; +end + +% accept numeric labels +if isnumeric(labels) + old = labels; + labels = cell(1, length(old)); + for i = 1:length(old) + labels{i} = num2str(old(i)); + end +end + +% checks +if ~islogical(spikes) + warning('Spikes should be a logical matrix. Converting...'); + spikes = logical(spikes); +end +if length(tm) ~= num_tm + error('Vector tm and the number of columns in the spike data must match.'); +end +if length(labels) ~= num_rw + error('The number of labels and the number of rows in the spike data must match.'); +end +if size(colors, 2) ~= 3 + error('The color data must have three columns.'); +end + +% setup plot +xlim([tm(1) tm(end)]); +ylim([0.5 num_rw + 0.5]); +xlabel('Time (s)'); +if isempty(labels) + % no labels + set(gca, 'YTick', []); +else + set(gca, 'YTick', 1:num_rw, 'YTickLabel', labels(end:-1:1)); +end + +% do actual plotting +hold on; +for i = 1:num_rw + color = 1 + mod(i - 1, num_clrs); + ln_x = bsxfun(@times, tm(spikes(i, :)), [1; 1; nan]); + ln_y = repmat(1 + num_rw - i + [0.5; -0.5; nan], 1, size(ln_x, 2)); + plot(ln_x(:), ln_y(:), 'LineWidth', line_width, 'Color', colors(color, :)); +end +hold off; + +end + diff --git a/run_activity_around_spikes.m b/run_activity_around_spikes.m new file mode 100644 index 0000000..62de2f9 --- /dev/null +++ b/run_activity_around_spikes.m @@ -0,0 +1,7 @@ +% load ROI +% load('image_roi/roi_data_image.mat'); + +% run +% NP_ActivityAroundSpikes(ROI, 'folder_with_raw_video_mat_files', 'folder_to_place_output'); +NP_ActivityAroundSpikes(ROI, 'mat', '2secActAroundSpikes', 'window', [1 1]); + diff --git a/run_ica.m b/run_ica.m new file mode 100644 index 0000000..255905b --- /dev/null +++ b/run_ica.m @@ -0,0 +1,26 @@ +%% LOAD VIDEO + +% loading +load('SanneSleep31_LNY19RB_1minSpont_1224_(2).mat'); + +%% CALCULATE ICA + +% use nice wrapper to handle resizing and unrolling video +[ica_sig, mixing, separating, height, width] = NP_PerformICA(video.frames(30:end-30)); + +%% APPLY TO ORIGINAL VIDEO + +% plot +plot_ica(ica_sig, mixing, height, width); + +% %% APPLY TO NEW VIDEO +% +% % loading +% load('SanneSleep31_LNY19RB_1minSpont_1224_(2).mat'); +% +% % the actual ICA part: +% % use separating matrix to perform saming unmixing +% ica_sig2 = NP_ApplyICA(video.frames(30:end-30), separating, height, width); +% +% % plot +% plot_ica(ica_sig2, mixing, height, width); diff --git a/run_plot_rastergram.m b/run_plot_rastergram.m new file mode 100644 index 0000000..d757840 --- /dev/null +++ b/run_plot_rastergram.m @@ -0,0 +1,9 @@ +% make some data +% rows represent rows in the plot, columns represent time +data = rand(20, 10000) > 0.995; +data([1 2 5 7 8 9 10], 2000) = true; +data(:, 5000) = true; + +tm = (1:10000) ./ 250; + +plot_rastergram(tm, data, 'colors', lines(20)); \ No newline at end of file diff --git a/sample.png b/sample.png new file mode 100644 index 0000000..2b4e3d2 Binary files /dev/null and b/sample.png differ diff --git a/scale.m b/scale.m new file mode 100644 index 0000000..130e8ac --- /dev/null +++ b/scale.m @@ -0,0 +1,24 @@ +% Run after your image is already plotted in a figure: + +% properties +bar_position = [10 10]; % top left corner of scale bar +bar_scale = 0.5; % microns/pixel +bar_length = 100; % 100 microns +bar_color = [0 1 0]; +bar_width = 3; + +% calculate coordinates +x1 = bar_position(1); +y1 = bar_position(2); +x2 = round(x1 + bar_length / bar_scale); +y2 = y1; + +hold on; + +% draw line +plot([x1 x2], [y1 y2], 'Color', bar_color, 'LineWidth', bar_width); + +% write text +text((x1 + x2) / 2, y1 + 3 * bar_width, sprintf('%d\\mum', bar_length), 'Color', bar_color, 'FontSize', 20, 'FontWeight', 'bold', 'HorizontalAlignment', 'center', 'VerticalAlignment', 'top'); + +hold off; \ No newline at end of file diff --git a/test_spike_analysis.m b/test_spike_analysis.m new file mode 100644 index 0000000..138f668 --- /dev/null +++ b/test_spike_analysis.m @@ -0,0 +1,50 @@ +%% synthetic data +roi_count = length(ROI.stats); +sample_count = 2000; + +% STIMULUS: random +% Spike_Data = rand(roi_count, sample_count) < 0.01; +% Spike_Data = reshape(Spike_Data, 1, roi_count, sample_count); + +% STIMULUS: sequential, non-overlapping +% space = 0; +% Spike_Data = false(roi_count, sample_count); +% for i = 1:roi_count +% st = 1 + (i - 1) * (1 + space); +% ev = (1 + space) * roi_count; +% Spike_Data(i, st:ev:end) = true; +% end +% Spike_Data = reshape(Spike_Data, 1, roi_count, sample_count); + +% STIMULUS: sequential, overlapping +% space = 4; +% Spike_Data = false(roi_count, sample_count); +% for i = 1:roi_count +% st = i; +% ev = (1 + space); +% Spike_Data(i, st:ev:end) = true; +% end +% Spike_Data = reshape(Spike_Data, 1, roi_count, sample_count); + +% STIMULUS: actual +% load('../Recordings/roi/Spontaneous_Data.mat'); + +% STIMULUS: all co-active +% Spike_Data = false(roi_count, sample_count); +% every = 20; +% Spike_Data(:, every:every:end) = true; +% Spike_Data = reshape(Spike_Data, 1, roi_count, sample_count); + +% STIMULUS: artificial 1 leads all others +every = 50; +Spike_Data = false(roi_count, sample_count); +Spike_Data(1, 1:every:end) = true; +Spike_Data(2:2:roi_count, 5:every:end) = true; +Spike_Data = reshape(Spike_Data, 1, roi_count, sample_count); + +%% run +SM_SortedSpikeAnalysis + +%% plot spikes +figure; +imagesc(squeeze(Spike_Data(1, :, 1:200))); diff --git a/video_adjust.m b/video_adjust.m new file mode 100644 index 0000000..4d55e1c --- /dev/null +++ b/video_adjust.m @@ -0,0 +1,25 @@ +function video = video_adjust(video, tol) +%VIDEO_ADJUST Summary of this function goes here +% Detailed explanation goes here + + +if ~exist('tol', 'var') || isempty(tol) + tol = [0.2 1]; +end + +% handle non image values gracefully +if isfloat(video) + mn = min(video(:)); + mx = max(video(:)); + if mn < 0 || mx > 1 + video = (video - mn) ./ (mx - mn); + end +end + +old_dim = size(video); +clim = stretchlim(video(:), tol); +video = imadjust(video(:), clim, []); +video = reshape(video, old_dim); + +end + diff --git a/video_read.m b/video_read.m new file mode 100644 index 0000000..2585f7a --- /dev/null +++ b/video_read.m @@ -0,0 +1,35 @@ +function [video, fps] = video_read(video_file, max_duration) +%VIDEO_READ Loads a video + +if ~exist('max_duration', 'var') || isempty(max_duration) + max_duration = 0; +end + +% open video reader +vh = VideoReader(video_file); + +% get frame rate +fps = vh.FrameRate; + +% store frames +frames = {}; + +% had frame +while hasFrame(vh) + % too long + if max_duration > 0 && vh.CurrentTime > max_duration + break + end + + % read frame + frame = readFrame(vh); + + % add frame + frames{end + 1} = frame; %#ok +end + +% turn into a video +video = cat(1 + ndims(frames{1}), frames{:}); + +end + diff --git a/video_register.m b/video_register.m new file mode 100644 index 0000000..3e62c3c --- /dev/null +++ b/video_register.m @@ -0,0 +1,60 @@ +function video = video_register(video, reference, show_progress) +%VIDEO_REGISTER + +if 3 ~= ndims(video) + error('Expecting a grayscale video.'); +end + +% show progress +if ~exist('show_progress', 'var') + show_progress = true; % default value +end + +% show progress +if show_progress + h = waitbar(0, 'Registering video...'); +end + +% convert +if isa(video, 'double') + convert = false; +else + convert = class(video); + video = double(video); +end + +% reference frame +if ~exist('reference', 'var') || isempty(reference) + % DEFAULT: middle frame + reference = -1; + ref_frame = video(:, :, round(size(video, 3) / 2)); +elseif reference == 0 + % mean + ref_frame = mean(video, 3); +else + ref_frame = video(:, :, reference); +end + +ref_fft = fft2(ref_frame); + +for i = 1:size(video, 3) + [~, out_fft] = dftregistration(ref_fft, fft2(video(:, :, i))); + video(:, :, i) = abs(ifft2(out_fft)); + + % update progress + if show_progress + waitbar(i / size(video, 3)); + end +end + +% close progress +if show_progress + close(h); +end + +% undo convert +if convert + video = cast(video, convert); +end + +end diff --git a/video_rgb2gray.m b/video_rgb2gray.m new file mode 100644 index 0000000..3447355 --- /dev/null +++ b/video_rgb2gray.m @@ -0,0 +1,14 @@ +function video_gs = video_rgb2gray(video_rgb) +%VIDEO_RGB2GRAY Convert RGB video to grayscale video + +if 4 ~= ndims(video_rgb) || 3 ~= size(video_rgb, 3) + error('Unexpected video dimensions. Expecting four dimensions with three color channels.'); +end + +video_gs = zeros(size(video_rgb, 1), size(video_rgb, 2), size(video_rgb, 4), 'like', video_rgb); +for t = 1:size(video_rgb, 4) + video_gs(:, :, t) = rgb2gray(video_rgb(:, :, :, t)); +end + +end + diff --git a/video_smooth.m b/video_smooth.m new file mode 100644 index 0000000..d6936db --- /dev/null +++ b/video_smooth.m @@ -0,0 +1,54 @@ +function video_smooth = video_smooth(video, time_steps) +%VIDEO_SMOOTH Smooths a video over time +% Smooths neighboring frames in a video based on parameter time steps. +% Each returned frame will be a running average of time_step frames in +% the input video. Supports both grayscale and multichannel videos. +% +% This function takes advantage of matlab n-dimensional convolution +% function to use a simple smoothing filter along the time dimension of +% the video. To avoid zero padding, the first and last frames are +% repeated. + +% make filter +filter = ones(1, time_steps, 'like', video) / cast(time_steps, 'like', video); + +% amount of padding +if 1 == mod(time_steps, 2) + pad_before = (time_steps - 1) / 2; + pad_after = pad_before; +else + pad_before = (time_steps / 2); + pad_after = pad_before; +end + +% handle different video types +if ndims(video) == 4 + % reshape to filter over time + filter = reshape(filter, 1, 1, 1, []); + + % replicate first and last frames + video = cat(4, ... + repmat(video(:, :, :, 1), 1, 1, 1, pad_before), ... + video, ... + repmat(video(:, :, :, end), 1, 1, 1, pad_after)); + + % smooth video + video_smooth = convn(video, filter, 'valid'); +elseif ndims(video) == 3 + % reshape to filter over time + filter = reshape(filter, 1, 1, []); + + % replicate first and last frames + video = cat(3, ... + repmat(video(:, :, 1), 1, 1, pad_before), ... + video, ... + repmat(video(:, :, end), 1, 1, pad_after)); + + % smooth video + video_smooth = convn(video, filter, 'valid'); +else + error('Invalid number of dimensions (expecting 3 or 4).'); +end + +end + diff --git a/video_write.m b/video_write.m new file mode 100644 index 0000000..d020a97 --- /dev/null +++ b/video_write.m @@ -0,0 +1,62 @@ +function video_write(video_file, video, fps, format) +%VIDEO_WRITE Write a video file + +% infer format from name +if ~exist('format', 'var') || isempty(format) + switch video_file((end-2):end) + case 'mp4' + format = 'MPEG-4'; + case 'm4v' + format = 'MPEG-4'; + case 'mj2' + format = 'Motion JPEG 2000'; + case 'avi' + format = 'Motion JPEG AVI'; + otherwise + error('Unknown format.'); + end +end + +% open writer +vh = VideoWriter(video_file, format); + +% set frame rate +if exist('fps', 'var') && ~isempty(fps) + vh.FrameRate = fps; +end + +% set quality +switch format + case 'Motion JPEG 2000' + vh.Quality = 80; + case 'Motion JPEG AVI' + vh.Quality = 80; +end + +open(vh); + +% convert format (can not write uint16) +if isa(video, 'uint16') || isa(video, 'single') + video = im2uint8(video); +end + +% write frames +if ndims(video) == 4 + for i = 1:size(video, 4) + f = im2frame(video(:, :, :, i)); + writeVideo(vh, f); + end +elseif ndims(video) == 3 + for i = 1:size(video, 3) + v = repmat(video(:, :, i), 1, 1, 3); + f = im2frame(v); + writeVideo(vh, f); + end +else + warning('Invalid video passed.'); +end + +% close +close(vh); + +end