Skip to content
Permalink
ff8326de7b
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
706 lines (620 sloc) 33.5 KB
function [fieldPar,lowpassWF,hand]=postSpikeFieldAnalysis(avgWF,ch,Fs,preSpikeMs,neuronNames,En,varargin)
% [fieldPar,lowpassWF,hand]=postSpikeFieldAnalysis(avgWF,ch,Fs,preSpikeMs,neuronNames,En,varargin)
% Function purpose : Calculate distribution of post spike fields (PSF)
%
% Function recives : avgWF - average spike STAs over all electrodes in ch [Double [neurons x ch x samples]
% ch - the channel numbers of the channels in avgWFWaveform [NChannels,Time] - the raw voltage samples of all channels
% Fs - sampling frequency of the WFs
% preSpikeMs - pre spike time in avgWF
% neuronNames - names of neurons [2 x n], [channel numbers ; neuron number]
% En - electrode layout
% varargin ('property name','property value')
%
% Function give back : par - a structure of output parameters
% .classIE - I/E marker (I=2, E=3)
% lowpassWF - the sif waveforms with spikes removed
% hand - a structure of handles from generated plots
%
% Last updated : 14/12/14
%help, avgWF [neurons x ch x samples]
%% default variables
electrodePitch=100;
nearestNeighborsDistance=190;
postSpikeFieldStartMs=3;
postSpikeFieldEndMs=20;
preSpikePeakMs=2; %this can be larger since the exact spike time is defined by the algorithm
postSpike0CrossLimMs=20;
classIEThreshMs=2;
medianFilterLengthMs=7;
spikePeakWidthMs=1;
smartInterSmoothness=0.0001; %smoothing [0 1] - higher values fit is close to data (no low pass), 0.0000005 - more low pass
weightFunctionStdMs=7;
maxPostSpikeWidthMs=3;
stdThresholdCrossingSpikeInitiation=4;
preSpikeMinInitiationMs=1.5;
preSpikeMaxInitiationMs=0.5;
postSpikeCorrMs=10; %5
maxSIFMethod='spikeNN';
IEclassificationMethod='kernelProd'; %'kernelProd','delay2Crossing';
ECorrTh=[0];
ICorrTh=[0];
plotIEClass=0;
plotMaxWFAll=0;
lowpassWF=[];
PSFMethod='max';%'integral','max','extrapInt'
fieldPositionMethod='interpolatedMaxima';%'maxima','interpolatedMaxima','COM'
preProcessing='smartInterpolation';%'smartInterpolation','lowpassFilter','medianFilter','interp','none'
removeEdges=false;
dAngle4Plot=30;
maxFields4Plot=375;
plotFieldMapAllNeurons=false;
neuronIdxPolarPlot=false;
polarPlot=true;
plotElectrodeNames=true;
plotFieldVectors=true;
plotNeuronNumbersAllFields=false;
polarPlotRemoveOuliers=false;
polarPlotDistanceThreshold=[];
normalizeColorCode=true;
extrapolateMaxima=true;
markerSizeAllFields=15;
triangulateCellPosition = true;
cellPosition=[]; % [2 x nNeurons] correction to position based on spike shape [um]
preSpikeHPMs=2;
postSpikeHPMs=3;
classIE=true; %[true,false,vec]if false, all assumed inhibitory, can also be a vector with excitatory (2) and inhibitory (3) classifications (or 0 for require classification)
%% Output list of default variables
%print out default arguments and values if no inputs are given
if nargin==0
defaultArguments=who;
for i=1:numel(defaultArguments)
eval(['defaultArgumentValue=' defaultArguments{i} ';']);
if numel(defaultArgumentValue)==1
disp([defaultArguments{i} ' = ' num2str(defaultArgumentValue)]);
else
fprintf([defaultArguments{i} ' = ']);
disp(defaultArgumentValue);
end
end
return;
end
%% Collects all input variables
for i=1:2:length(varargin)
eval([varargin{i} '=' 'varargin{i+1};'])
end
%% Main code - general calculations
postSpikeFieldStartSamples=postSpikeFieldStartMs*Fs/1000;
postSpikeFieldEndSamples=postSpikeFieldEndMs*Fs/1000;
preSpikeSamples=preSpikeMs*Fs/1000;
preSpikePeakSamples=preSpikePeakMs*Fs/1000;
spikePeakWidthSamples=spikePeakWidthMs*Fs/1000;
maxPostSpikeWidthSamples=maxPostSpikeWidthMs*Fs/1000;
postSpikeCorrSamples=postSpikeCorrMs*Fs/1000;
weightFunctionStdSamples=weightFunctionStdMs*Fs/1000;
preSpikeMinInitiationSamples=preSpikeMinInitiationMs*Fs/1000;
preSpikeMaxInitiationSamples=preSpikeMaxInitiationMs*Fs/1000;
preSpikeHPSamples=preSpikeHPMs*Fs/1000;
postSpikeHPSamples=postSpikeHPMs*Fs/1000;
medianFilterSamples=round(medianFilterLengthMs*Fs/1000/2)*2+1; %has to be an odd number
postSpike0CrossLimSamples=postSpike0CrossLimMs*Fs/1000;
[nNeurons,nCh,nSamples]=size(avgWF);
timeVec=(1:nSamples)/Fs*1000-preSpikeMs;
%Build inverse map between electrode and location
[meshX,meshY]=meshgrid(1:size(En,1),1:size(En,2));
Xc(En(~isnan(En)))=meshX(~isnan(En))*electrodePitch;
Yc(En(~isnan(En)))=meshY(~isnan(En))*electrodePitch;
% get the channel with max spike for extimating spike remove segment
[~,pMaxSpikeElec]=max( max( abs(avgWF(:,:,(preSpikeSamples-spikePeakWidthSamples/2):(preSpikeSamples+spikePeakWidthSamples/2))) ,[],3) ,[],2);
for i=1:nCh
pNeighbors{i}=find(sqrt((Xc-Xc(i)).^2+(Yc-Yc(i)).^2)<=nearestNeighborsDistance);
end
if size(ch,1)>size(ch,2)
ch=ch';
end
%% pre-process the input waveforms
if isempty(lowpassWF)
lowpassWF=zeros(size(avgWF));
switch preProcessing
case 'smartInterpolation'
pBaseline=1:(preSpikePeakSamples-preSpikeMinInitiationSamples);
preExtension=round(preSpikePeakSamples/8); %extend the detection point by a few samples
for i=1:nNeurons
fprintf('%d,',i);
%extract the initiation segment right before the spike (on nearest neigbohrs) and remove the mean of the initial part of this segment so that all segments start at 0
spikeInitiationWF=squeeze(avgWF(i,pNeighbors{pMaxSpikeElec(i)},(preSpikeSamples-preSpikePeakSamples):preSpikeSamples));%
spikeInitiationWF=bsxfun(@minus,spikeInitiationWF,mean(spikeInitiationWF(:,pBaseline),2) );
%calculate the spike onset (tr) according to where std increases rapidely over different electrode
stdProfile=std(spikeInitiationWF);
pSpikeOnset=min([preSpikePeakSamples-preSpikeMaxInitiationSamples,find(stdProfile > mean(stdProfile(pBaseline)) + stdThresholdCrossingSpikeInitiation*std(stdProfile(pBaseline)),1,'first')-1]);
pSpikeStart(i)=(preSpikeSamples-preSpikePeakSamples+pSpikeOnset-preExtension);
pSpikeSoftEnd=(preSpikeSamples+maxPostSpikeWidthSamples);
%weights for slow synaptic potential extraction
w1=ones(1,nSamples);
w1(pSpikeStart(i) : pSpikeSoftEnd)=0;
w1((pSpikeSoftEnd+1):(pSpikeSoftEnd+weightFunctionStdSamples*3))=1-exp(-( (1:weightFunctionStdSamples*3)/weightFunctionStdSamples).^2);
%weights for baseline extraction
pSpikeSoftEnd2=1200;
w2=ones(1,nSamples);
w2(pSpikeStart(i) : pSpikeSoftEnd2)=0;
w2((pSpikeSoftEnd2+1):end)=1-exp(-( (1:(nSamples-pSpikeSoftEnd2))/weightFunctionStdSamples/2).^2);
w2(1:pSpikeStart(i))=1-exp(-( (pSpikeStart(i):-1:1)/weightFunctionStdSamples/3).^2);
lowpassWF(i,:,:) = csaps(1:nSamples,squeeze(avgWF(i,:,:)),smartInterSmoothness,1:nSamples,w1);
lowpassWFBaseline(i,:,:) = csaps(1:nSamples,squeeze(lowpassWF(i,:,:)),1e-6,1:nSamples,w2);
%plotting
%{
h(1)=subplot(2,3,1);
plot(timeVec,squeeze(avgWF(i,pMaxSpikeElec(i),:)));hold on;plot(timeVec,squeeze(lowpassWF(i,pMaxSpikeElec(i),:)));plot(timeVec,(w-1)*50);
xlabel('Time [ms]');axis tight;
spikeZoom=squeeze(avgWF(i,pNeighbors{pMaxSpikeElec(i)},(preSpikeSamples-preSpikePeakSamples):(preSpikeSamples+postSpikeFieldEndSamples)));%
spikeZoom=bsxfun(@minus,spikeZoom,mean(spikeZoom(:,200),2) );
h(2)=subplot(2,3,4);
plot(timeVec((preSpikeSamples-preSpikePeakSamples):(preSpikeSamples+postSpikeFieldEndSamples)),spikeZoom');
xlabel('Time [ms]');axis tight;
h(3)=subplot(2,3,[2 6]);
[hPlot,scaleFac]=activityTracePhysicalSpacePlot(h(3),1:120,squeeze(avgWF(i,:,:)),En,'traceColor','r','DrawElectrodeNumbers',1);hold on;
[hPlot]=activityTracePhysicalSpacePlot(h(3),1:120,squeeze(lowpassWF(i,:,:)),En,'scaleFac',scaleFac);
pause;
delete(h);
%}
end
case 'lowpassFilter'
fprintf('Calculating median filter on neuron: ');
[b,a] = ellip(4,0.5,20,150/Fs,'low');
lowpassWF = permute(filtfilt(b,a,permute(avgWF,[3 1 2])),[2 3 1]);
case 'medianFilter'
fprintf('Calculating median filter on neuron: ');
for i=1:nNeurons
fprintf('%d,',i);
for j=1:nCh
lowpassWF(i,j,:) = fastmedfilt1d(squeeze(avgWF(i,j,:))',medianFilterSamples);
end
end
case 'interp'
fprintf('Calculating interpulation pre-processing on neuron: ');
nonSpikeSamples=[1:(preSpikeSamples-22) (preSpikeSamples+82):nSamples];
for i=1:nNeurons
fprintf('%d,',i);
lowpassWF(i,:,:) = interp1(nonSpikeSamples,squeeze(avgWF(i,:,nonSpikeSamples))',1:nSamples,'pchip')';
%csaps(x,y,p)
end
otherwise
error('The selected preprocessing method is not a valid one');
%test the spike removal algorithm
%{
figure;
for i=1:nNeurons
h=axes;
[hPlot,scaleFac]=activityTracePhysicalSpacePlot(h,1:120,squeeze(avgWF(i,:,:)),En,'traceColor','r','DrawElectrodeNumbers',1);hold on;
[hPlot]=activityTracePhysicalSpacePlot(h,1:120,squeeze(lowpassWF(i,:,:)),En,'scaleFac',scaleFac);
pause;
delete(h);
end
%}
end
end
%%
%calculate baseline substracted traces
preBaseline=median(lowpassWF(:,:,(preSpikeSamples-preSpikePeakSamples):(preSpikeSamples-preSpikeMinInitiationSamples)),3);
normWF=bsxfun(@minus,lowpassWF,preBaseline); %baseline substruction
% get the channel with max field for classification
if strcmp(maxSIFMethod,'spikeNN')
%build extended grid
nNeighbors=1;
[nRowsTmp,nColsTmp]=size(En);
EnExt=NaN(nRowsTmp+nNeighbors*2,nColsTmp+nNeighbors*2);
EnExt(1+nNeighbors:end-nNeighbors,1+nNeighbors:end-nNeighbors)=En;
%find max amp electrode
[~,pSpikeElec]=min(avgWF(:,:,preSpikeSamples+1),[],2);
for i=1:nNeurons
[pX,pY]=find(EnExt==pSpikeElec(i));
pElecs=EnExt(pX-nNeighbors:pX+nNeighbors,pY-nNeighbors:pY+nNeighbors); %get electrodes in extended grid
pElecs=pElecs(~isnan(pElecs)); %remove NaNs
[~,pMaxFieldInLocal]=max(max(abs( normWF(i,pElecs,(preSpikeSamples+postSpikeFieldStartSamples):(preSpikeSamples+postSpikeFieldEndSamples)) ),[],3),[],2);
pMaxField(i)=pElecs(pMaxFieldInLocal);
maxChWF(i,:)=normWF(i,pMaxField(i),:);
end
elseif strcmp(maxSIFMethod,'test')
amp0=mean(lowpassWF(:,:,(preSpikeSamples-spikePeakWidthSamples):(preSpikeSamples)),3); %mean amplitude of low pass wf during spike
ampPeak=mean(lowpassWF(:,:,(preSpikeSamples+postSpikeFieldStartSamples):(preSpikeSamples+postSpikeFieldEndSamples)),3);
ampEdge=mean(lowpassWF(:,:,(preSpikeSamples+postSpikeFieldEndSamples):(preSpikeSamples+postSpikeFieldEndSamples+spikePeakWidthSamples)),3);
validCh=(ampPeak>amp0) == (ampPeak>ampEdge); %select only channels in which the SIF area is a local peak (or vally) but not if there is a continuous trend
tmpAmp=max( abs(lowpassWF(:,:,(preSpikeSamples+1):(preSpikeSamples+postSpike0CrossLimSamples))) ,[],3);
tmpAmp(~validCh)=0;
[~,pMaxElec]=max( tmpAmp ,[],2);
maxChWF=zeros(nNeurons,nSamples);
for i=1:nNeurons
maxChWF(i,:)=lowpassWF(i,pMaxElec(i),:);
%maxNormWF(i,:)=normWF(i,pMaxElec(i),:);
end
pMaxField=pMaxElec;
elseif strcmp(maxSIFMethod,'maxSpikeChannel')
for i=1:nNeurons
maxChWF(i,:)=lowpassWF(i,pMaxSpikeElec(i),:);
end
pMaxField=pMaxSpikeElec;
end
%% This section is not working well, should be corrected to work properly
%% inhibitory excitatory classification
%determine which neurons to classify
if numel(classIE)==1
if classIE==0 %do not classify, but set all to be inhibitory
classIE=3*ones(1,nNeurons);
elseif classIE==1 %classify all
classIE=ones(1,nNeurons);
end %nothing happens for the case of one neuron in recording that was already clasified in the input
toClassify=(classIE==1);
else
toClassify=false(1,nNeurons);
end
if any(toClassify)
tmp = num2cell( cat(3, normWF(:,:,(preSpikeSamples+1):(preSpikeSamples+postSpike0CrossLimSamples)) > 0 , true([nNeurons, nCh]) ) , 3); %transform to cell mat and add one at the end of every vector
firstNon0Idx = cell2mat(cellfun(@(x) find(x, 1, 'first'), tmp,'UniformOutput',0)); %find first threshold crossing for every trace
firstNon0Idx(firstNon0Idx==(postSpike0CrossLimSamples+1))=0; %set to zero (meaning no crossing found) all the traces with crossings in the last artificially added bin
if strcmp(IEclassificationMethod,'delay2Crossing')
%{
figure;
for i=1:nNeurons
h=axes;
[hPlot,scaleFac]=activityTracePhysicalSpacePlot(h,1:120,squeeze(normWF(i,:,(preSpikeSamples+82):(preSpikeSamples+postSpike0CrossLimSamples+1))),En,'traceColor','r','DrawElectrodeNumbers',1);hold on;
[hPlot]=activityTracePhysicalSpacePlot(h,1:120,squeeze(tmp(i,:,:)),En,'scaleFac',scaleFac);
title(['Max ch=' num2str(pMaxElec(i))]);
pause;
delete(h);
end
%}
for i=1:nNeurons %go over neurons and collect the closest N channel around the spike peak for determining I or E
fieldPar.IEScore(i)=mean(firstNon0Idx(i,pNeighbors{neuronNames(1,i)}));
end
fieldPar.IEScore=fieldPar.IEScore/Fs*1000; %convert from samples to ms
pExcit=find(fieldPar.IEScore>=classIEThreshMs);
pInhib=find(fieldPar.IEScore<classIEThreshMs);
elseif strcmp(IEclassificationMethod,'kernelProd')
load('IESIFTemplate','IESIFTemplate','tTemplate_ms');
tTemplate_ms=tTemplate_ms+5;
%resample template to fit the times of the measured data
resampledTemplate = interp1(tTemplate_ms,IESIFTemplate',timeVec,'spline')';
%put zeros in resampled template if these times are outside the IESIFTemplate time limits
resampledTemplate(:,timeVec>tTemplate_ms(end) | timeVec<tTemplate_ms(1))=0;
%calculate correlation between template and the signals
fieldPar.IEScore(1,:)=corr(maxChWF(:, preSpikeSamples:(preSpikeSamples+postSpikeCorrSamples) )',resampledTemplate(1,preSpikeSamples:(preSpikeSamples+postSpikeCorrSamples))');
fieldPar.IEScore(2,:)=corr(maxChWF(:,preSpikeSamples:(preSpikeSamples+postSpikeCorrSamples))',resampledTemplate(2,preSpikeSamples:(preSpikeSamples+postSpikeCorrSamples))');
pExcit=find(fieldPar.IEScore(1,:)>0 & fieldPar.IEScore(2,:)<0);
pInhib=find(fieldPar.IEScore(1,:)<0 & fieldPar.IEScore(2,:)>0);
pNotClassified=find((fieldPar.IEScore(1,:)<0 & fieldPar.IEScore(2,:)<0) | (fieldPar.IEScore(1,:)>0 & fieldPar.IEScore(2,:)>0));
%plot corr analysis for a given neuron
%{
f=figure;
h=subplot(1,2,1);
plot(timeVec,maxChWF(i,:)');hold on;
plot(timeVec(preSpikeSamples:(preSpikeSamples+postSpikeCorrSamples)),maxChWF(i, preSpikeSamples:(preSpikeSamples+postSpikeCorrSamples) )');
mx=max(maxChWF(i, preSpikeSamples:(preSpikeSamples+postSpikeCorrSamples)));
mn=min(maxChWF(i, preSpikeSamples:(preSpikeSamples+postSpikeCorrSamples)));
plot(timeVec,resampledTemplate(1,:)*abs(mn),'--');
plot(timeVec,resampledTemplate(2,:)*abs(mx),'--');
title(['Max ch=',num2str(pMaxField(i))]);
h=subplot(1,2,2);
[hPlot,scaleFac]=activityTracePhysicalSpacePlot(h,1:120,squeeze(avgWF(i,:,:)),En,'traceColor','r','DrawElectrodeNumbers',1);hold on;
[hPlot]=activityTracePhysicalSpacePlot(h,1:120,squeeze(normWF(i,:,:)),En,'scaleFac',scaleFac);
title(['neuron ' num2str(neuronNames(:,i)')]);
%}
else
error('Input I-E classification method does not exist');
end
fieldPar.classIE=ones(1,nNeurons);
fieldPar.classIE(pExcit)=3; %excitatory
fieldPar.classIE(pInhib)=2; %inhibitory
fieldPar.classIE(~toClassify)=classIE(~toClassify); %give the neurons that should not be classified their original classification
fieldPar.fieldScore=abs(fieldPar.IEScore(1,:)-fieldPar.IEScore(2,:));
%!!!! check if to give the classified cells a constant firstNon0Idx value instead of calculating it
else
pExcit=find(classIE==3);
pInhib=find(classIE==2);
preBaseline=median(lowpassWF(:,:,1:(preSpikeSamples-preSpikePeakSamples)),3);
normWF=bsxfun(@minus,lowpassWF,preBaseline); %baseline substruction
fieldPar.classIE=classIE;
end
if plotIEClass
f=figure;cMap=lines;
hand.classificationPlot=axes;hold on;
scatter(fieldPar.IEScore(1,pExcit),fieldPar.IEScore(2,pExcit),[],cMap(1,:));hold on;
scatter(fieldPar.IEScore(1,pInhib),fieldPar.IEScore(2,pInhib),[],cMap(2,:));
scatter(fieldPar.IEScore(1,pNotClassified),fieldPar.IEScore(2,pNotClassified),[],'k');
scatter(fieldPar.IEScore(1,fieldPar.IEScore==0),fieldPar.IEScore(2,fieldPar.IEScore==0),[],cMap(2,:));
%scatter(fieldPar.IEScore(1,:),fieldPar.IEScore(2,:),[],abs(fieldPar.IEScore(1,:)-fieldPar.IEScore(2,:)));
xlim([-1 1]);ylim([-1 1]);
line([ECorrTh ECorrTh],ylim,'color','k');
line(xlim,[ICorrTh ICorrTh],'color','k');
xlabel('E score');
ylabel('I score');
l=legend({'E','I','?'},'Box','off');
%text(fieldPar.IEScore(1,:),fieldPar.IEScore(2,:),num2str(neuronNames'));
%text(fieldPar.IEScore(1,127),fieldPar.IEScore(2,127),num2str(neuronNames(:,127)'));
%{
subplot(1,2,1);plot(maxChWFnorm(:,preSpikeSamples:postSpikeFieldEndSamples)');hold on;plot(normTemplate(1,preSpikeSamples:postSpikeFieldEndSamples)','b','lineWidth',3);plot(normTemplate(2,preSpikeSamples:postSpikeFieldEndSamples)','g','lineWidth',3);plot(normTemplate(3,preSpikeSamples:postSpikeFieldEndSamples)','r','lineWidth',3);
subplot(1,2,2);plot(maxChWF(:,preSpikeSamples:postSpikeFieldEndSamples)');hold on;plot(resampledTemplate(1,preSpikeSamples:postSpikeFieldEndSamples)','b','lineWidth',3);plot(resampledTemplate(2,preSpikeSamples:postSpikeFieldEndSamples)','g','lineWidth',3);plot(resampledTemplate(3,preSpikeSamples:postSpikeFieldEndSamples)','r','lineWidth',3);
maxChWFnorm=bsxfun(@rdivide,bsxfun(@minus,maxChWF,mean(maxChWF(:,preSpikeSamples:postSpikeFieldEndSamples),2)),std(maxChWF(:,preSpikeSamples:postSpikeFieldEndSamples),[],2));
normTemplate=bsxfun(@rdivide,bsxfun(@minus,resampledTemplate,mean(resampledTemplate(:,preSpikeSamples:postSpikeFieldEndSamples),2)),std(resampledTemplate(:,preSpikeSamples:postSpikeFieldEndSamples),[],2));
subplot(1,2,1);plot(maxChWFnorm(pExcit,:)','b');hold on;plot(maxChWFnorm(pInhib,:)','r');
subplot(1,2,2);plot(normTemplate(1,:)','b');hold on;plot(normTemplate(2,:)','r');plot(normTemplate(3,:)','g');
subplot(1,2,1);plot(maxChWFnorm(pExcit,preSpikeSamples:postSpikeFieldEndSamples)','b');hold on;plot(maxChWFnorm(pInhib,preSpikeSamples:postSpikeFieldEndSamples)','r');
subplot(1,2,2);plot(normTemplate(1,preSpikeSamples:postSpikeFieldEndSamples)','b');hold on;plot(normTemplate(2,preSpikeSamples:postSpikeFieldEndSamples)','r');
%}
end
if plotMaxWFAll
%define number of subplots
n=ceil(sqrt(min(maxFields4Plot,nNeurons)/3/5));%define images in a 3 x 5 ratio
xPlots=n*5;
yPlots=n*3;
nPlotPerPage=xPlots*yPlots;
cMap=lines(2);
cMap=[cMap;0 0 0;0 0 0];
f=figure('Position',[50 50 1800 900],'Visible','off');
for i=1:nNeurons
h=subaxis(f,yPlots,xPlots,i,'S',0.001,'M',0.001);
plot(timeVec,squeeze(avgWF(i,pMaxField(i),:)));hold on;
plot(timeVec,squeeze(lowpassWF(i,pMaxField(i),:)),'r');axis tight;
set(h,'XTickLabel',[],'YTick',[],'XTick',0,'TickLength',h.TickLength*5);
%text(h.XLim(2),h.YLim(2),[num2str(neuronNames(1,i)) '-' num2str(neuronNames(2,i))],'VerticalAlignment','top','HorizontalAlignment','right');
text(h.XLim(1),h.YLim(1),'*','color',cMap(4-fieldPar.classIE(i),:),'FontSize',18)
text(h.XLim(2),h.YLim(2),[num2str(i) ',' num2str(neuronNames(1,i)) '-' num2str(neuronNames(2,i))],'VerticalAlignment','top','HorizontalAlignment','right');
end
f.Visible='on';
end
%{
for i=1:nNeurons
f=figure;
h=axes;
[hPlot,scaleFac]=activityTracePhysicalSpacePlot(h,1:120,squeeze(avgWF(i,:,:)),En,'traceColor','r','DrawElectrodeNumbers',1);hold on;
[hPlot]=activityTracePhysicalSpacePlot(h,1:120,squeeze(lowpassWF(i,:,:)),En,'scaleFac',scaleFac);
title(['neuron ' num2str(neuronNames(:,i)') ', class = ' num2str(fieldPar.classIE(i))]);
pause;
delete(f);
end
%}
%% calculate post spike fields
fprintf('\nCalculating PSDs...');
pRelevantSamples=(preSpikeSamples+postSpikeFieldStartSamples):(preSpikeSamples+postSpikeFieldEndSamples);
switch PSFMethod
case 'max'
%peak voltage normalized by pre spike peak
%fieldPar.val(pInhib,:)=max(lowpassWF(pInhib,:,pRelevantSamples),[],3)-mean(lowpassWF(pInhib,:,1:(preSpikeSamples-preSpikePeakSamples)),3);
%fieldPar.val(pExcit,:)=-(min(lowpassWF(pExcit,:,(1+preSpikeSamples):(preSpikeSamples+postSpike0CrossLimSamples)),[],3)-mean(lowpassWF(pExcit,:,1:(preSpikeSamples-preSpikePeakSamples)),3));
fieldPar.val(pInhib,:)=max(lowpassWF(pInhib,:,pRelevantSamples),[],3)-mean(lowpassWF(pInhib,:,(preSpikeSamples-spikePeakWidthSamples/2):(preSpikeSamples+spikePeakWidthSamples/2)),3);
fieldPar.val(pExcit,:)=-(min(lowpassWF(pExcit,:,(1+preSpikeSamples):(preSpikeSamples+postSpike0CrossLimSamples)),[],3)-mean(lowpassWF(pExcit,:,(preSpikeSamples-spikePeakWidthSamples/2):(preSpikeSamples+spikePeakWidthSamples/2)),3));
%set not classified the same as inhibitory
fieldPar.val(pNotClassified,:)=max(lowpassWF(pNotClassified,:,pRelevantSamples),[],3)-mean(lowpassWF(pNotClassified,:,(preSpikeSamples-spikePeakWidthSamples/2):(preSpikeSamples+spikePeakWidthSamples/2)),3);
%{
IE=['?';'I';'E'];
pTmp=find(timeVec==0);
spikeMarker=ones(120,1)*nan(1,numel(timeVec));
spikeMarker(:,pTmp)=min(lowpassWF(:));
spikeMarker(:,pTmp+1)=max(lowpassWF(:));
for i=1:nNeurons;
h1=subplot(3,4,[1 11]);
[hPlot,scaleFac]=activityTracePhysicalSpacePlot(h1,1:120,squeeze(avgWF(i,:,:)),En,'traceColor','r');hold on;
activityTracePhysicalSpacePlot(h1,1:120,squeeze(lowpassWF(i,:,:)),En,'scaleFac',scaleFac,'DrawElectrodeNumbers',1);
activityTracePhysicalSpacePlot(h1,1:120,spikeMarker,En,'scaleFac',scaleFac,'DrawElectrodeNumbers',1,'traceColor',[0.7 0.7 0.7]);
title(['Neuron=' num2str(neuronNames(:,i)') 'index=' num2str(i) ', Max ch=' num2str(pMaxField(i)) ', C=' num2str(fieldPar.fieldScore(i))]);
h2=subplot(3,4,8);hCB=IntensityPhysicalSpacePlot(ch,fieldPar.val(i,:),En,'h',h2,'plotElectrodeNumbers',0);
title(IE(fieldPar.classIE(i)));
pause;
delete([h1 h2]);
end
%}
case 'integral'
%mean voltage normalized by pre spike mean
fieldPar.val(pInhib,:)=mean(lowpassWF(pInhib,:,pRelevantSamples),3)-mean(lowpassWF(pInhib,:,(preSpikeSamples-spikePeakWidthSamples/2):(preSpikeSamples-spikePeakWidthSamples/2)),3); %for inhibitory cells
fieldPar.val(pNotClassified,:)=mean(lowpassWF(pNotClassified,:,pRelevantSamples),3)-mean(lowpassWF(pNotClassified,:,(preSpikeSamples-spikePeakWidthSamples/2):(preSpikeSamples-spikePeakWidthSamples/2)),3); %for inhibitory cells
%for inhibitory cells - in places where no threshold crossing occured, a NaN is placed
postSpike0CrossLimSamplesCell=mat2cell(firstNon0Idx(pExcit,:),ones(1,numel(pExcit)),ones(1,nCh));
tmp = num2cell( normWF(pExcit,:,(1+preSpikeSamples):(preSpikeSamples+postSpike0CrossLimSamples)) , 3);
fieldPar.val(pExcit,:)= -cellfun(@(x,y) mean(x(1:y)), tmp, postSpike0CrossLimSamplesCell); %baseline alreadys substructed for normWF
%tmp = num2cell( lowpassWF(pExcit,:,(1+preSpikeSamples):(preSpikeSamples+postSpike0CrossLimSamples)) , 3);
%fieldPar.val(pExcit,:)= cellfun(@(x,y) mean(x(1:y)), tmp, postSpike0CrossLimSamplesCell)-mean(lowpassWF(pExcit,:,1:(preSpikeSamples-preSpikePeakSamples)),3);
case 'interpInt' %!!!! Has to be rewritten to support separation between excitatory and inhibitory
%angle and magnitude of integral voltage maximium divided by the average profile before spike
sideSamples=[1:(preSpikeSamples-preSpikePeakSamples) postSpikeFieldEndSamples:nSamples];
fieldPar.val=zeros(nNeurons,nCh);
for i=1:nNeurons
vq = interp1(sideSamples,squeeze(lowpassWF(i,:,sideSamples))',pRelevantSamples); %calculate the linear line between the two noise ends (before and after PSD)
fieldPar.val(i,:)=mean(squeeze(lowpassWF(i,:,pRelevantSamples))-vq',2);
%{
h=axes;[hPlot]=activityTracePhysicalSpacePlot(h,1:120,squeeze(lowpassWF(i,:,:)),En);hold on;
test=squeeze(lowpassWF(i,:,:));test(:,pRelevantSamples)=vq';
[hPlot]=activityTracePhysicalSpacePlot(h,1:120,test,En);
%}
end
otherwise
error('SIF calculation method not valid');
end
makeGaussianFit=0;
if makeGaussianFit
gaussFit.mX=zeros(1,nNeurons);
gaussFit.mY=zeros(1,nNeurons);
gaussFit.sX=zeros(1,nNeurons);
gaussFit.sY=zeros(1,nNeurons);
gaussFit.A=zeros(1,nNeurons);
gaussFit.Theta=zeros(1,nNeurons);
for i=1:nNeurons
[fitresult] = fmgaussfit(Xc,Yc,fieldPar.val(i,:)); %[amp, ang, sx, sy, xo, yo, zo]
gaussFit.A(i)=fitresult(1);
gaussFit.Theta(i)=fitresult(2);
gaussFit.sX(i)=fitresult(3);
gaussFit.sY(i)=fitresult(4);
gaussFit.mX(i)=fitresult(5);
gaussFit.mY(i)=fitresult(6);
end
end
if removeEdges
[~,pMax]=max(fieldPar.val,[],2);
[m,n]=size(En);
fieldPar.edgeNeurons=zeros(1,nNeurons);
for i=1:nNeurons
[pX,pY]=find(En==neuronNames(1,i));
if pX==1 || pX==n || pY==1 || pY==m
fieldPar.edgeNeurons(i)=1;
else
surroundingSquare=En(pY-1:pY+1,pX-1:pX+1);
if any(any(isnan(surroundingSquare)))
fieldPar.edgeNeurons(i)=2;
end
end
end
else
fieldPar.edgeNeurons=zeros(1,nNeurons); %set all neuron as ones not at the edge
end
fprintf('\nCalculating field peak...');
switch fieldPositionMethod
case 'interpolatedMaxima'
[m,n]=size(En);
Z=nan([m,n]);
%Z=zeros([m,n]);
fieldCoord=zeros(2,nNeurons);
for i=1:nNeurons
Z(sub2ind([m,n],Xc(ch)/electrodePitch,Yc(ch)/electrodePitch))=fieldPar.val(i,:);
[fieldCoord(:,i)] = peakfit2d(Z);
end
fieldPar.Xfield=fieldCoord(1,:)*electrodePitch;
fieldPar.Yfield=fieldCoord(2,:)*electrodePitch;
case 'COM' %biased by array edges
fieldPar.Xfield=(sum(bsxfun(@times,fieldPar.val,Xc),2)./sum(fieldPar.val,2))';
fieldPar.Yfield=(sum(bsxfun(@times,fieldPar.val,Yc),2)./sum(fieldPar.val,2))';
case 'maxima'
[PSF,pChPSF]=max(fieldPar.val,[],2);%location of field integral maxima
fieldPar.Xfield=Xc(ch(pChPSF));
fieldPar.Yfield=Yc(ch(pChPSF));
end
%incorporate cell position
if triangulateCellPosition && isempty(cellPosition) %run cell position estimation
avgSpkWF=avgWF(:,:, (preSpikeSamples-preSpikeHPSamples+1):(preSpikeSamples+postSpikeHPSamples) )-lowpassWF(:,:, (preSpikeSamples-preSpikeHPSamples+1):(preSpikeSamples+postSpikeHPSamples) );
[est,hest]=spikePositionEstimation(avgSpkWF,ch,preSpikeHPMs,Fs,En,fieldPar.classIE,'plot3D',0);
cellPosition(1,:)=est.X;
cellPosition(2,:)=est.Y;
%{
figure;
for i=1:nNeurons
h=axes;
[hPlot,scaleFac]=activityTracePhysicalSpacePlot(h,1:120,squeeze(avgSpkWF(i,:,:)),En,'traceColor','b','DrawElectrodeNumbers',1);hold on;title(neuronNames(:,i));
pause;
delete(h);
end
%}
elseif ~triangulateCellPosition && isempty(cellPosition) %use max spike electrode as a cell position estimator
cellPosition(1,:)=Xc(neuronNames(1,:));
cellPosition(1,:)=Yc(neuronNames(1,:));
end
%create projection vectors
X=[cellPosition(1,:);fieldPar.Xfield];
Y=[cellPosition(2,:);fieldPar.Yfield];
if size(cellPosition,2)==1 && size(cellPosition,1)~=2
error('cellPosition was not entered in the correct format');
end
mag=sqrt((X(2,:)-X(1,:)).^2 + (Y(2,:)-Y(1,:)).^2);
angle=atan2(Y(2,:)-Y(1,:),X(2,:)-X(1,:));
if ~isempty(polarPlotDistanceThreshold)
pp=find(mag>=polarPlotDistanceThreshold(1) & mag<=polarPlotDistanceThreshold(2));
mag(pp)=0;
end
pPosMagI=intersect(find(mag>0 & fieldPar.edgeNeurons==0),pInhib);
pPosMagE=intersect(find(mag>0 & fieldPar.edgeNeurons==0),pExcit);
%% Plotting results
if polarPlot
%prepare for plotting
f=figure('position',[100 100 500 500]);
P = panel(f);
P.pack(2,2);
P.margin=8;
angleBins=(dAngle4Plot/360/2*pi):(dAngle4Plot/360*pi):(pi*2);
if polarPlotRemoveOuliers
maximalMag=median(mag([pPosMagI pPosMagE]))+6*mad(mag([pPosMagI pPosMagE]),1);
else
maximalMag=max(mag([pPosMagI pPosMagE]));
end
%inhibitory
hand.polar(1,1)=P(1, 1).select();
hRose=rose(angle(pPosMagI),angleBins);
hRose.Color=[0.8 0.2 0.2];
XdataRose = get(hRose,'Xdata');XdataRose=reshape(XdataRose,[4,numel(XdataRose)/4]);
YdataRose = get(hRose,'Ydata');YdataRose=reshape(YdataRose,[4,numel(YdataRose)/4]);
hPatch=patch(XdataRose,YdataRose,[0.8 0.2 0.2]);
set(gca,'color','k');
%compass(U,V)
hand.polar(1,2)=P(1, 2).select();
polar(0,maximalMag,'-k');hold on; %set scale for polar plot
hTmp=polar(angle(pPosMagI),mag(pPosMagI),'.r');
if neuronIdxPolarPlot
text(hTmp.XData',hTmp.YData',num2str(neuronNames(:,pPosMagI)'),'FontSize',8);
end
%excitatory
hand.polar(2,1)=P(2, 1).select();
hRose=rose(angle(pPosMagE),angleBins);
XdataRose = get(hRose,'Xdata');XdataRose=reshape(XdataRose,[4,numel(XdataRose)/4]);
YdataRose = get(hRose,'Ydata');YdataRose=reshape(YdataRose,[4,numel(YdataRose)/4]);
hPatch=patch(XdataRose,YdataRose,[0.2 0.2 0.8]);
set(gca,'color','k');
hand.polar(2,2)=P(2, 2).select();
polar(0,maximalMag,'-k');hold on; %set scale for polar plot
hTmp=polar(angle(pPosMagE),mag(pPosMagE),'.');
if neuronIdxPolarPlot
text(hTmp.XData',hTmp.YData',num2str(neuronNames(:,pPosMagE)'),'FontSize',8);
text(hTmp.XData',hTmp.YData',num2str(pPosMagE'),'FontSize',8);
end
end
%DSI=(prefered - (prefered+pi))/(prefered + (prefered+pi))
if plotFieldVectors
f=figure('position',[100 100 700 700]);
hand.hVec=axes;
hand.hVec.WarpToFill='off'; %to avoid error in arrow3 function
if plotElectrodeNames
hand.electrodeText=text(Xc,Yc,num2str(ch'),'fontsize',8,'Parent',hand.hVec,'horizontalAlignment','center');
xlim([min(Xc)-electrodePitch max(Xc)+electrodePitch]);
ylim([min(Yc)-electrodePitch max(Yc)+electrodePitch]);
hold(hand.hVec,'on');
end
%hQ=quiver(Xc(neuronNames(1,:)),Yc(neuronNames(1,:)),intdX,intdY,'filled','lineWidth',2,'MaxHeadSize',0.1,'color','k','MarkerSize',2,'MarkerFaceColor','k');
[tmpX,tmpY]=pol2cart(angle,50);
nInhib2Display=numel(pPosMagI);
cMapR=flipud([ones(1,60);(0:0.01:0.59);(0:0.01:0.59)]');
normColorI = ceil(min(mag(pPosMagI)./maximalMag,1).*60);
if ~isempty(pPosMagI)
hand.hArrowI=arrow3([X(1,pPosMagI);Y(1,pPosMagI)]',[X(1,pPosMagI)+tmpX(pPosMagI);Y(1,pPosMagI)+tmpY(pPosMagI)]','^r2',0.5,1);hold on;
for i=1:nInhib2Display
hand.hArrowI(i+1).FaceColor=cMapR(normColorI(i) ,:,:);
end
end
nExcit2Display=numel(pPosMagE);
cMapB=flipud([(0:0.01:0.59);(0:0.01:0.59);ones(1,60)]');
normColorE = ceil(min(mag(pPosMagE)./maximalMag,1).*60);
if ~isempty(pPosMagE)
hand.hArrowE=arrow3([X(1,pPosMagE);Y(1,pPosMagE)]',[X(1,pPosMagE)+tmpX(pPosMagE);Y(1,pPosMagE)+tmpY(pPosMagE)]','^b2',0.5,1);
for i=1:nExcit2Display
hand.hArrowE(i+1).FaceColor=cMapB(normColorE(i) ,:,:);
end
end
xlabel('X [\mum]','FontSize',14);
ylabel('Y [\mum]','FontSize',14);
end
if plotFieldMapAllNeurons
if normalizeColorCode
Ilim=0;
else
Ilim=[min(fieldPar.val(:)) max(fieldPar.val(:))];
end
n=ceil(sqrt(min(maxFields4Plot,nNeurons)/3/5));%define images in a 3 x 5 ratio
xPlots=n*5;
yPlots=n*3;
nPlotPerPage=xPlots*yPlots;
f=figure;
P = panel(f);
P.pack(yPlots,xPlots);
P.margin=0.001;
for i=1:nNeurons
hand.hAllFieldAxes(i)=P(ceil(i/xPlots),i-(ceil(i/xPlots)-1)*xPlots).select();
IntensityPhysicalSpacePlot(1:120,fieldPar.val(i,:),En,'plotElectrodeNumbers',0,'plotGridLines',0,'plotColorBar',0,'markerSize',markerSizeAllFields,'h',hand.hAllFieldAxes(i),'Ilim',Ilim);
text(Xc(neuronNames(1,i))/electrodePitch-0.5,Yc(neuronNames(1,i))/electrodePitch-0.5,'o','horizontalAlignment','center','fontsize',6);
if plotNeuronNumbersAllFields
text(0,0,num2str(i),'horizontalAlignment','left','verticalAlignment','bottom','fontsize',6);
end
line( [Xc(neuronNames(1,i)) fieldPar.Xfield(i)]/electrodePitch - 0.5 , [Yc(neuronNames(1,i)) fieldPar.Yfield(i)]/electrodePitch - 0.5 ,'color','k');
end
end