https://github.com/hasselmonians/mle_rhythmicity
Tip revision: 7c50ba73fa34dbe2586fb0f9e0204bd1e28f3209 authored by jrclimer on 11 July 2016, 16:29:52 UTC
Resolves #7
Resolves #7
Tip revision: 7c50ba7
theta_index.m
function [thetaindex,p,f,F,theta_index_ci,lowsig,highsig,blow,bhigh] = theta_index(x_,varargin)
%THETA_INDEX Calculates the theta index and confidence intervals
% Calculates the theta-index as in Yartsev et al, 2011, Nature. See also:
% Boccara et al, 2010, Nature Neurosci; Langston et al, 2010 Science; Wills
% et al, 2010, Science; and Deshmukh et al, 2010, J. Neurophysiol.
%
% Using a model of the autocorrelogram as a series of Poisson counts, also
% calculates confidence intervals on the theta index.
%
% INPUT
% x: Data. Can either be spike timestamps, a cell array of lags, or a
% histogram of lag counts.
% PARAMETERS
% calcp (true): Bootstaps the null distribution by shuffling lags by 1/2
% of a cycle of the peak frequency detected. If false, does not run
% and p=NaN, but runs much faster.
% pmethod (bootstrap): Can be "bootstrap" or "shuffle". If "shuffle", x
% must be spike timestamps and generates the null distribution by
% jittering spike time as specified by shufflet. If "bootstrap",
% jitters spike lags within the AC window by the amount specified by
% shufflet.
% shufflet ('adapt'): If 'adapt', jitters spike/lag times by +/- (1/(f-1)/2)
% seconds (see output). Can also be a set number (i.e. 10 seconds).
% t (0:0.01:0.5): The edges of the lag bins.
% ishist (false): Set to true if input data is a histogram.
% calcci (true): Calculates the region of confidence (0.95) around the
% autocorrelogram for the true underlying rates, and finds the least
% and most theta-rhythmic (by the theta index) rate profiles in this
% range. If false, does not run and
% theta_index_ci,lowsig,highsig,blow and bhigh are all NaN, but runs
% much faster
% RETURNS
% thetaindex: The theta index - the ratio of the average power within 1
% Hz of the peak in the theta (5-11 Hz) range and the average power
% in the whole spectrum of the zero-mean spike time autocorrelation
% p: The boostrapped significance of the autocorrelation
% f: The peak theta frequency detected
% F: The bootstrapped null distribution
% theta_index_ci: The confidence intervals on the theta index.
% lowsig: The rate profile found with the lowest theta index.
% highsig: The rate profile found with the highest theta index.
% blow: The low side of the 95% confidence range for the rate profile.
% bhigh: The high side of the 95% confidence range for the rate profile.
%
% Copyright (c) 2014, Trustees of Boston University
% All rights reserved.
%
% This file is part of mle_rhythmicity
%
% This code has been freely distributed by the authors under the BSD
% licence (http://opensource.org/licenses/BSD-2-Clause). If used or
% modified, we would appreciate it if you cited our paper:
%
% Climer, J. R., DiTullio, R., Newman, E. L., Hasselmo, M. E., Eden, U. T.
% (2014), Examination of rhythmicity of extracellularly recorded neurons in
% the entorhinal cortex. Hippocampus, Epub ahead of print. doi:
% 10.1002/hipo.22383.
%% Parse input
p = inputParser;
p.addParamValue('calcp',true);
p.addParamValue('ishist',false);
p.addParamValue('calcci',true);
p.addParamValue('t',0:0.01:0.5);
p.addParamValue('pmethod','bootstrap');
p.addParamValue('shufflet',10);
p.parse(varargin{:});
for j = fields(p.Results)'
eval([j{1} ' = p.Results.' j{1} ';']);
end
T = max(t);
if ishist
b = x_(:);
elseif iscell(x_)
x = x_(:);
x_ = [];
try
b = histc(cat(1,x{:}),t);
catch err
b = histc(cat(2,x{:}),t);
end
b = b(1:end-1);
else
spk_ts = x_(:);
x_ = x_(:)';
x = arrayfun(@(x)spk_ts(spk_ts>x&spk_ts<=x+T)-x,spk_ts,'UniformOutput',false);
b = histc(cat(1,x{:}),t);
b = b(1:end-1);
end
b = b(:);
if numel(b)==numel(t)-1
b = [flipud(b);max(b(:));b];
end
% Calculate theta index
Fs = 0.01^-1;
NFFT = 2^16;
f = Fs/2*linspace(0,1,NFFT/2+1);
Y = fft(b-mean(b),NFFT);
Y = abs(Y(1:NFFT/2+1)).^2;
Y = conv(Y,ones(1,round(2/mode(diff(f)))),'same')';
[~,pk] = nanmax((f(:)>5&f(:)<11).*Y(:));
pk0 = pk;
thetaindex = mean(Y(abs(f-f(pk))<=1))/mean(Y);
p = NaN;
F = NaN;
theta_index_ci = NaN;
%% Calculate confidence intervals on theta index
if calcci
if (isempty(x_)||~iscell(x_))&&iscell(x)
n = numel(x);
elseif iscell(x_)
n = numel(x_);
end
b2 = b(numel(t)+1:end);
blow = b2*0;
blow(b2~=0) = arrayfun(@(b2)fzero(@(mu)poisscdf(b2,mu*n)-1+0.05/2,[0 10*b2/n]),b2(b2~=0))*n;
bhigh = arrayfun(@(b2)fzero(@(mu)poisscdf(b2,n*mu)-0.05,[0 10*max(b2,1)/n]),b2)*n;
theta_index_ci = [0 0];
% Find underlying rate profile with lowest theta index
[lowsig,theta_index_ci(1)] = fmincon(...
@(x)confun(x,bhigh,blow)...
,b2...
,[],[],[],[]...
,blow...
,bhigh...
,[]...
,optimset('Algorithm','active-set','TolFun',1e-4,'TolX',1e-4)...
);
% Find underlying rate profile with highest theta index
[highsig,theta_index_ci(2)] = fmincon(...
@(x)-confun(x,bhigh,blow)...
,b2...
,[],[],[],[]...
,blow...
,bhigh...
,[]...
,optimset('Algorithm','active-set','TolFun',1e-3,'TolX',0.01)...
);
theta_index_ci(2) = -theta_index_ci(2);
end
%% Bootstrap: uniformly jitter lag by 1/2 cycle and recalculate
N = 1000;
if calcp
% Calc shufflet if nessesary
if isequal(shufflet,'adapt')
shufflet = 1/(f(pk0)-1)/2;
end
F = NaN(N,1);
switch pmethod
case 'bootstrap'
for j=1:N
% jitter
try
shuffled_b = abs(unifrnd(cat(1,x{:})-shufflet,cat(1,x{:})+shufflet));
catch err
shuffled_b = abs(unifrnd(cat(2,x{:})-shufflet,cat(2,x{:})+shufflet));
end
% Make jittered histogram
shuffled_b(shuffled_b>T) = 2*T-shuffled_b(shuffled_b>T);
shuffled_b(shuffled_b<=0) = -shuffled_b(shuffled_b<=0);
shuffled_b = histc(shuffled_b,t);
shuffled_b = shuffled_b(1:end-1);
shuffled_b = shuffled_b(:);
shuffled_b = [flipud(shuffled_b);max(shuffled_b);shuffled_b];
% Calculate theta index
Y = fft(shuffled_b-mean(shuffled_b),NFFT);
Y = abs(Y(1:NFFT/2+1)).^2;
Y = smooth(Y,2/mode(diff(f)));
[~,pk] = nanmax((f>5&f<11).*Y');
F(j) = mean(Y(abs(f-f(pk))<=1))/mean(Y);
end
case 'shuffle'
for i=1:N
% Calculate theta index
F(i) = theta_index(spk_ts(:)+rand(numel(spk_ts),1)*shufflet*2-shufflet,'calcp',false,'calcci',false,'t',t);
end
otherwise
warning('theta_index:BadPMETHOD',['pmethod ''' pmethod ''' not implemented.']);
end
p = sum(F>thetaindex)/N;
end
f = f(pk0);
end
function [ c ] = confun( x, high, low )
c = theta_index(x,'calcp',false,'ishist',true,'calcci',false);
end