123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- function [map,stats] = Map(v,z,varargin)
- %Map - Map z on (x,y) where x, y and z are time-varying variables (samples).
- %
- % Compute a continuous map, where one time-varying variable z is represented
- % as a function of one or two time-varying variables x and y. The variable z
- % can either be a point process (typically, a list of spike timestamps) or a
- % continuous measure (e.g. the instantaneous velocity of the animal, the
- % spectral power of an LFP channel in a given frequency band, the coherence
- % between two oscillating LFP channels, etc.) Typical examples of x and y
- % include spatial coordinates and angular directions.
- %
- % An occupancy map is also computed.
- %
- % USAGE
- %
- % map = Map([t x y],z,<options>)
- %
- % t timestamps for x and y
- % x x values in [0,1]
- % y optional y values in [0,1]
- % z list of timestamps or (timestamp,value) pairs
- % <options> optional list of property-value pairs (see table below)
- %
- % =========================================================================
- % Properties Values
- % -------------------------------------------------------------------------
- % 'smooth' smoothing size in bins (0 = no smoothing, default = 2)
- % 'nBins' number of horizontal and vertical bins (default = [50 50])
- % 'minTime' minimum time spent in each bin (in s, default = 0)
- % 'maxGap' z values recorded during time gaps between successive (x,y)
- % samples exceeding this threshold (e.g. undetects) will not
- % be interpolated; also, such long gaps in (x,y) sampling
- % will be clipped to 'maxGap' to compute the occupancy map
- % (default = 0.100 s)
- % 'type' 'linear' if z is linear (default), 'circular' otherwise
- % =========================================================================
- %
- % OUTPUT
- %
- % map.x x bins
- % map.y y bins
- % map.z average map (z continuous)
- % or rate map (z point process)
- % map.count count map (z point process)
- % map.time occupancy map (in s)
- %
- % NOTES
- %
- % x values are arranged in columns and y values in rows in all output matrices
- % (e.g. 'map.z').
- %
- % SEE
- %
- % See also MapStats, FiringMap, PlotColorMap, Accumulate.
- % Copyright (C) 2002-2011 by Michael Zugaro
- %
- % This program is free software; you can redistribute it and/or modify
- % it under the terms of the GNU General Public License as published by
- % the Free Software Foundation; either version 3 of the License, or
- % (at your option) any later version.
- % Check number of parameters
- if nargin < 2 | mod(length(varargin),2) ~= 0,
- error('Incorrect number of parameters');
- end
- % Check parameter sizes
- if size(v,2) < 2,
- error('Parameter ''[t x y]'' should have at least 2 columns');
- end
- if (size(z,2) < 1 || size(z,2) > 2) && ~isempty(z),
- error('Parameter ''z'' should have 1 or 2 columns');
- end
- % Default values
- maxGap = 0.1;
- map.x = [];
- map.y = [];
- map.count = [];
- map.time = [];
- map.z = [];
- smooth = 1;
- nBins = [100 1];
- minTime = 0;
- type = 'linear';
- % Parse parameter list
- for i = 1:2:length(varargin),
- if ~ischar(varargin{i}),
- error(['Parameter ' num2str(i+2) ' is not a property']);
- end
- switch(lower(varargin{i})),
- case 'smooth',
- smooth = varargin{i+1};
- if ~isdvector(smooth) | length(smooth) > 2,
- error('Incorrect value for property ''smooth''');
- end
- case 'nbins',
- nBins = varargin{i+1};
- if ~isivector(nBins) | length(nBins) > 2,
- error('Incorrect value for property ''nBins''');
- end
- case 'mintime',
- minTime = varargin{i+1};
- if ~isdscalar(minTime,'>=0'),
- error('Incorrect value for property ''minTime''');
- end
- case 'maxgap',
- maxGap = varargin{i+1};
- if ~isdscalar(maxGap,'>=0'),
- error('Incorrect value for property ''maxGap''');
- end
- case 'type',
- type = lower(varargin{i+1});
- if ~isstring(type,'circular','linear'),
- error('Incorrect value for property ''type''');
- end
- otherwise,
- error(['Unknown property ''' num2str(varargin{i}) '''']);
- end
- end
- if isempty(v), return; end
- % Some info about x, y and z
- pointProcess = (isempty(z) | size(z,2) == 1);
- t = v(:,1);
- x = v(:,2);
- if size(v,2) >= 3,
- y = v(:,3);
- else
- y = [];
- end
- % Number of bins for x and y
- nBinsX = nBins(1);
- if length(nBins) == 1,
- nBinsY = nBinsX;
- nBins(2) = nBins;
- else
- nBinsY = nBins(2);
- end
- % Bin x and y
- x = Bin(x,[0 1],nBinsX);
- if ~isempty(y),
- y = Bin(y,[0 1],nBinsY);
- end
- % Duration for each (X,Y) sample (clipped to maxGap)
- dt = diff(t);dt(end+1)=dt(end);dt(dt>maxGap) = maxGap;
- if pointProcess,
- % Count occurrences for each (x,y) timestamp
- n = CountInIntervals(z,[t t+dt]);
- % n = CountInIntervals(z,[t(1:end-1) t(2:end)]);
- % n(end+1) = 0;
- else
- % Interpolate z at (x,y) timestamps
- [z,discarded] = Interpolate(z,t,'maxGap',maxGap);
- if isempty(z), return; end
- if strcmp(type,'circular'),
- range = isradians(z(:,2));
- z(:,2) = exp(j*z(:,2));
- end
- n = 1;
- end
- % Computations
- if isempty(y),
- % 1D (only x)
- map.x = linspace(0,1,nBinsX);
- map.count = Smooth(Accumulate(x,n,nBinsX),smooth)';
- map.time = Smooth(Accumulate(x,dt,nBinsX),smooth)';
- if pointProcess,
- map.z = map.count./(map.time+eps);
- else
- map.z = Smooth(Accumulate(x(~discarded),z(:,2),nBinsX),smooth)';
- map.z = map.z./(map.count+eps);
- end
- else
- % 2D (x and y)
- map.x = linspace(0,1,nBinsX);
- map.y = linspace(0,1,nBinsY);
- map.count = Smooth(Accumulate([x y],n,nBins),smooth)';
- map.time = Smooth(Accumulate([x y],dt,nBins),smooth)';
- if pointProcess,
- map.z = map.count./(map.time+eps);
- else
- map.z = Smooth(Accumulate([x(~discarded) y(~discarded)],z(:,2),nBins),smooth).';
- map.z = map.z./(map.count+eps);
- end
- end
- % Circular z
- if strcmp(type,'circular'), map.z = wrap(angle(map.z),range); end
- % Discard regions with insufficient sampling
- map.z(map.time<=minTime) = 0;
|