ET_PDToolkit/PDToolkit/utils/TFCEobj.m

178 lines
7.7 KiB
Mathematica
Raw Normal View History

2018-06-12 14:49:55 +02:00
classdef TFCEobj<handle
properties
%default values for H and E represpenting area under the curve
H=0;
E=1; %NB there is one E value per dimension.
D=[]; %A 2D (future N-D) matrix where dim1 is instance (i.e. independend TFCE's to be calculated,
%dim2 is time .
%In the future, dim 3, dim 4, and dim 5 could become space dimensions (more akin to smith et al)
nstep=100; %number of stepts to use over your range
hmax=100;
TFCE=[];
S=[]; %place holder for surrogate data
STFCE=[]; %place holder for TFCE values of surrogate data
P=struct('uncorrected',[]); %place holder for P values
end
%% put the public functions here
methods
function T=TFCEobj(varargin) %constructor
%% TFCE Object for performing Threshold free cluster enhancement
%
% Example usage: T = TFCEobj('D', X, 'H' 0, 'E', 1, 'HMAX', 1);
%
% Input parameter:
% - D / data = 2-dimensional data matrix
% - H = Height parameter in the TFCE
% - E = Extent parameter in the TFCE
% - HMAX = Hmax parameter
for k=1:2:nargin;
if k+1<=nargin;
switch varargin{k}
case {'D','d','data','DATA'}
T.D=varargin{k+1};
T.InitTFCE;
case {'H','h'}
T.H=varargin{k+1};
case {'E','e'}
T.E=varargin{k+1};
case {'n','N','nstep','NSTEP'}
T.nstep=varargin{k+1};
case {'hmax','HMAX'}
T.hmax=varargin{k+1};
otherwise
error('invalid name-value pair');
end
end
end
end
function set.hmax(T,hmax)
if ~isnumeric(hmax);error('use a numeric value for hmax');end
T.hmax=hmax;
T.Check_hmax;
end
function set.D(T,D)
if size(D,2)<2||size(D,1)==0; error('don''t be silly, now I''ve nothing to do');end
if any(~isnumeric(D)); error('data is not a numerica matrix');end
T.D=D;
end
function varargout=Surrogate(T,storeflag,n)
% Create surrogate data.
% function call S=T.Surrogate(n)
% n: number of surrogates to create
% S is a 3D matrix of size(D) by n
%build surrogate timecourses using the DVV toolbox by Danilo P. Mandic
%http://www.commsp.ee.ic.ac.uk/~mandic/dvv.htm
if isempty(n);n=25;end
if ~isnumeric(n);error('invalid number of surrogates to create');end
if isempty(storeflag);storeflag=false;end
if nargout<1&&~storeflag;error('don''t be silly. Now I''ve nowhere to store my results');end
S=zeros([size(T.D),n]);
% loop over instances
h=waitbar(0,'generating surrogate data');
for k=1:size(T.D,1);
S(k,:,:)=surrogate(T.D(k,:),n);
waitbar(k./size(T.D,1),h);
end
close(h);
if storeflag;
T.S=S;
end
if nargout==1;varargout{1}=S;end
end
function varargout=SurrogateTFCE(T,storeflag,n)
if nargout<1&&~storeflag;error('don''t be silly. Now I''ve nowhere to store my results');end
if isempty(T.S);
S=T.Surrogate(false,n);
else
S=T.S;
end
STFCE=zeros(size(S));
hsteps=linspace(0,T.hmax,T.nstep);
for k=1:size(S,3); %loop over surrogate data
for v=1:size(S,1);%loop over instances
STFCE(v,:,k)=T.TFCECore(squeeze(S(v,:,k)),hsteps);
end
end
if storeflag;T.STFCE=STFCE;end
if nargout==1;varargout{1}=STFCE;end
end
function Pvalues(T,n)
if isempty(T.TFCE);error('calculate TFCE before running stats');end;
PosCount=zeros(size(T.TFCE));
NegCount=zeros(size(T.TFCE));
Count=zeros(size(T.TFCE));
if isempty(T.STFCE) && ~isempty(T.S)
T.SurrogateTFCE;
end
if ~isempty(T.STFCE);
n=size(T.STFCE,3);
for k=1:n;
PosCount=PosCount+squeeze(T.STFCE(:,:,k))>T.TFCE;
NegCount=NegCount+squeeze(T.STFCE(:,:,k))<T.TFCE;
end
else
for k=1:n; %count over number of permutations;
T.Surrogate(true,1);
T.SurrogateTFCE(true);
PosCount=PosCount+squeeze(T.STFCE(:,:))>T.TFCE;
NegCount=NegCount+squeeze(T.STFCE(:,:))<T.TFCE;
end
end
T.P=struct('Pos_Uncorr',PosCount./n,...
'Neg_Uncorr',NegCount./n);
end
end
%% put the private functions here. NB during testing these will still be public
methods
function InitTFCE(T)
T.TFCE=zeros(size(T.D));
end
function TFCECalc(T)
hsteps=linspace(0,T.hmax,T.nstep);
for v=1:size(T.D,1);%loop over instances
I=T.D(v,:);
if any(~isfinite(I));continue;end%if NaN go to next one.
T.TFCE(v,:)=T.TFCECore(I,hsteps);
end
end
end
methods
%below are the support methods for the TFCE object. They won't alter any fields within the object
function Check_hmax(T)
m=max(T.D(:));
if ~isempty(m)
if T.hmax<m; warning('maximum value for integration set below the maximum value in T.D'); end
end
end
function TFCEtmp=TFCECore(T,I,hsteps)
%this function will actually calculate the TFCE values.
%It supports the function TFCECalc.
TFCEtmp=zeros(size(I));
for h=hsteps;
%% positive part
[L,n]=bwlabel(I>h); % find beta > h and get clusters %all numbers belonging to cluster 1 get a 1, to cluster 2 a 2 etc.
if n==0;
else
ind=1:numel(L);
S=sparse(L(logical(L)),ind(logical(L)),1);
% a bit of a trick, but it seems to work :-)
E=sum(repmat(diag(S*transpose(S)),1,size(S,2)).*S); %#ok<PROP>
TFCEtmp(logical(E))=TFCEtmp(logical(E))+E(logical(E)).^T.E*h.^T.H; %#ok<PROP> % get tfce value by tfce=tfce_h(-1)+h^ch*e^ce per voxel
end
%% negative part
[L2,n2]=bwlabel(I<-h);
if n2==0;
else
ind=1:numel(L2);
S=sparse(L2(logical(L2)),ind(logical(L2)),1);
% a bit of a trick, but it seems to work :-)
E2=sum(repmat(diag(S*transpose(S)),1,size(S,2)).*S);
TFCEtmp(logical(E2))=TFCEtmp(logical(E2))-E2(logical(E2)).^T.E*h.^T.H; % get tfce value by tfce=tfce_h(-1)+h^ch*e^ce per voxel
end
end
end
end
end