Changeset 215
- Timestamp:
- 10/16/08 13:45:00 (3 months ago)
- Files:
-
- trunk/INSTALL (modified) (1 diff)
- trunk/README (modified) (1 diff)
- trunk/examples/single_neuron/simple_single_neuron.py (modified) (1 diff)
- trunk/src/__init__.py (modified) (1 diff)
- trunk/src/analysis.py (modified) (1 diff)
- trunk/src/io.py (copied) (copied from branches/cleanup/src/io.py)
- trunk/src/plotting.py (modified) (3 diffs)
- trunk/src/signals.py (modified) (31 diffs)
- trunk/src/spikes.py (deleted)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/INSTALL
r148 r215 1 NeuroTools Insallation: 1 NeuroTools Insallation 2 ====================== 2 3 3 4 First download the package files: 4 svn co https://neuralensemble.kip.uni-heidelberg.de/svn/NeuroTools/trunk NeuroTools5 cd NeuroTools6 5 7 As root 6 svn co https://neuralensemble.org/svn/NeuroTools/trunk NeuroTools 7 cd NeuroTools 8 8 9 $ python setup.py install 9 Install as root (if you want a global install) 10 10 11 or for those without root access, to a local location, something like: 11 $ python setup.py install 12 12 13 # python setup.py install --prefix=$HOME/opt/mystuff 13 or for those without root access, install to a writable location, something like: 14 15 # python setup.py install --prefix=$HOME/opt/mystuff 14 16 15 17 Then you need to add the location: 16 18 17 $HOME/opt/mystuff/lib/python2. 4/site-packages/19 $HOME/opt/mystuff/lib/python2.5/site-packages/ 18 20 19 21 to your PYTHON_PAH or (in python) your sys.path 20 22 21 Note, here lib is replaced by lib64 on 64bit systems, and python2. 4is23 Note, here lib is replaced by lib64 on 64bit systems, and python2.5 is 22 24 (obviously) replaced by your python version. 23 25 24 Developpers of NeuroTools may be intersted in having their lastly updated version from SVN used by python (and therefore on python's path). A solution is to symbolically link the src folder to a folder included in the path: 25 cd my_local_site-packages_folder 26 ln -s where_I_check-out_neuralensemble/NeuroTools/trunk/src NeuroTools 26 Developpers of NeuroTools may be interested in having their lastly updated version from SVN used by python (and therefore on python's path). A solution is to symbolically link the src folder to a folder included in the path: 27 28 cd my_local_site-packages_folder 29 ln -s where_I_check-out_neuralensemble/NeuroTools/trunk/src NeuroTools 30 27 31 and voila! 28 32 trunk/README
r6 r215 1 NeuroTools SVN : see https://facets-vm3.kip.uni-heidelberg.de/trac/NeuroTools/wiki 1 For more info see the NeuroTools trac http://neuralensemble.org/trac/NeuroTools trunk/examples/single_neuron/simple_single_neuron.py
r177 r215 23 23 import pyNN.nest2 as sim 24 24 # the link to read SpikeList files with NeuroTools 25 from NeuroTools.s pikes import loadSpikeList25 from NeuroTools.signals import loadSpikeList 26 26 # using parameters utility 27 27 from NeuroTools.parameters import ParameterSet trunk/src/__init__.py
r190 r215 1 __all__ = ['analysis', 'benchmark', 'parameters', 'plotting', 'sandbox', 's pikes', 'signals', 'stgen', 'utilities']1 __all__ = ['analysis', 'benchmark', 'parameters', 'plotting', 'sandbox', 'signals', 'stgen', 'utilities', 'io'] 2 2 3 3 """from tables import __version__ trunk/src/analysis.py
r188 r215 9 9 import os, numpy 10 10 11 def ccf(x, y, axis=None): 12 """Computes the cross-correlation function of two series `x` and `y`. 13 Note that the computations are performed on anomalies (deviations from 14 average). 15 Returns the values of the cross-correlation at different lags. 16 Lags are given as [0,1,2,...,n,n-1,n-2,...,-2,-1] (not any more) 17 18 :Parameters: 19 `x` : 1D MaskedArray 20 Time series. 21 `y` : 1D MaskedArray 22 Time series. 23 `axis` : integer *[None]* 24 Axis along which to compute (0 for rows, 1 for cols). 25 If `None`, the array is flattened first. 26 """ 27 assert(x.ndim == y.ndim, "Inconsistent shape !") 28 # assert(x.shape == y.shape, "Inconsistent shape !") 29 if axis is None: 30 if x.ndim > 1: 31 x = x.ravel() 32 y = y.ravel() 33 npad = x.size + y.size 34 xanom = (x - x.mean(axis=None)) 35 yanom = (y - y.mean(axis=None)) 36 Fx = numpy.fft.fft(xanom, npad, ) 37 Fy = numpy.fft.fft(yanom, npad, ) 38 iFxy = numpy.fft.ifft(Fx.conj()*Fy).real 39 varxy = numpy.sqrt(numpy.inner(xanom,xanom) * numpy.inner(yanom,yanom)) 40 else: 41 npad = x.shape[axis] + y.shape[axis] 42 if axis == 1: 43 if x.shape[0] != y.shape[0]: 44 raise ValueError, "Arrays should have the same length!" 45 xanom = (x - x.mean(axis=1)[:,None]) 46 yanom = (y - y.mean(axis=1)[:,None]) 47 varxy = numpy.sqrt((xanom*xanom).sum(1) * (yanom*yanom).sum(1))[:,None] 48 else: 49 if x.shape[1] != y.shape[1]: 50 raise ValueError, "Arrays should have the same width!" 51 xanom = (x - x.mean(axis=0)) 52 yanom = (y - y.mean(axis=0)) 53 varxy = numpy.sqrt((xanom*xanom).sum(0) * (yanom*yanom).sum(0)) 54 Fx = numpy.fft.fft(xanom, npad, axis=axis) 55 Fy = numpy.fft.fft(yanom, npad, axis=axis) 56 iFxy = numpy.fft.ifft(Fx.conj()*Fy,n=npad,axis=axis).real 57 # We juste turn the lags into correct positions: 58 iFxy = numpy.concatenate((iFxy[len(iFxy)/2:len(iFxy)],iFxy[0:len(iFxy)/2])) 59 return iFxy/varxy 11 60 12 def record(output, cfilename = 'SpikeTrainPlay.wav', fs=44100, enc = 'pcm26'):13 """ record the 'sound' produced by a neuron. Takes a spike train as the14 output.15 16 >>> record(my_spike_train)17 18 """19 20 21 # from the spike list22 simtime_seconds = (output.t_stop - output.t_start)/1000.23 #time = numpy.linspace(0, simtime_seconds , fs*simtime_seconds)24 (trace,time) = numpy.histogram(output.spike_times*1000., fs*simtime_seconds)25 26 27 # TODO convolve with proper spike...28 spike = numpy.ones((fs/1000.,)) # one ms29 30 trace = numpy.convolve(trace, spike, mode='same')#/2.031 trace /= numpy.abs(trace).max() * 1.132 33 from scikits.audiolab import wavwrite34 wavwrite(trace, cfilename, fs = fs, enc = enc)35 36 def play(output):37 """38 plays a spike list to the audio output39 40 play(spike_list) where spike_list is a spike_list object41 42 see playing_with_simple_single_neuron.py for a sample use43 44 >>> play(my_spike_train)45 46 TODO: make it possible to play multiple spike trains in stereo47 """48 49 50 from tempfile import mkstemp51 fd, cfilename = mkstemp('SpikeListPlay.wav')52 try:53 record(output, cfilename)54 import pyaudio55 import wave56 57 chunk = 102458 wf = wave.open(cfilename, 'rb')59 p = pyaudio.PyAudio()60 61 # open stream62 stream = p.open(format =63 p.get_format_from_width(wf.getsampwidth()),64 channels = wf.getnchannels(),65 rate = wf.getframerate(),66 output = True)67 68 # read data69 data = wf.readframes(chunk)70 71 # play stream72 while data != '':73 stream.write(data)74 data = wf.readframes(chunk)75 76 stream.close()77 p.terminate()78 except:79 print "Error playing the SpikeTrain "80 # finally81 os.remove(cfilename)82 83 # Python 2.4 compatibility84 # finally:85 os.remove(cfilename)86 61 87 62 def _dict_max(D): trunk/src/plotting.py
r186 r215 1 1 2 import numpy #, pylab 3 import sys 2 import numpy, pylab, sys 4 3 from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas 5 4 from matplotlib.figure import Figure … … 38 37 39 38 40 def raster_plot(spike_list,output=None):# limits of the plot41 import pylab42 DATA=spike_list.as_list_id_list_time()43 pylab.plot(DATA[1],DATA[0],'.')44 pylab.ylabel('neuron ID')45 pylab.xlabel('time (s)')46 pylab.axis([spike_list.t_start, spike_list.t_stop, 0, spike_list.N])47 if not(output==None):48 pylab.savefig(output)49 #else:50 #pylab.show()51 52 53 54 55 39 def set_frame(ax,boollist,linewidth=2): 56 40 assert len(boollist) == 4 … … 65 49 if draw: 66 50 ax.add_line(side) 51 52 67 53 68 54 class SimpleMultiplot(object): trunk/src/signals.py
r205 r215 5 5 """ 6 6 7 import numpy 8 import os 7 import numpy, os, logging, re 8 from NeuroTools import analysis 9 from NeuroTools import io 10 9 11 try : 10 12 import pylab 11 except Exception: 12 print "Warning: pylab not present" 13 from NeuroTools import analysis 14 import logging 13 ENABLE_PLOTS = True 14 except ImportError: 15 ENABLE_PLOTS = False 16 MATPLOTLIB_ERROR = """ 17 Matplotlib not detected so plots are disabled. 18 To turn on plots, please install the Matplotlib package 19 """ 20 print MATPLOTLIB_ERROR 21 15 22 16 23 class SpikeTrain(object): 17 24 """ 18 This class defines a spike train as a list of the events times. 25 SpikeTrain(spikes_times, dt=None, t_start=None, t_stop=None) 26 This class defines a spike train as a list of times events. 19 27 20 28 Event times are given in a list (sparse representation) in milliseconds. 21 29 22 >>> s1 = SpikeTrain([0.0, 0.1, 0.2, 0.5]) 23 >>> s2 = SpikeTrain(numpy.array([0, 1, 2, 5]), dt=0.1) 24 >>> assert all(s1.spike_times == s2.spike_times) 25 >>> print s1.format(relative=True) 26 [ 0. 0.1 0.1 0.3] 27 >>> s1.isi() 28 array([ 0.1, 0.1, 0.3]) 29 >>> s1.mean_rate() 30 8.0 31 >>> s1.cv_isi() 32 0.565685424949 30 Inputs: 31 spike_times - a list/numpy array of spike times (in milliseconds) 32 t_start - beginning of the SpikeTrain (if not, this is infered) 33 t_stop - end of the SpikeTrain (if not, this is infered) 34 dt - time precision of the spike events 35 36 Examples: 37 >>> s1 = SpikeTrain([0.0, 0.1, 0.2, 0.5]) 38 >>> s2 = SpikeTrain([0, 1, 2, 5], dt=0.1) 39 >>> assert all(s1.spike_times == s2.spike_times) 40 >>> s1.isi() 41 array([ 0.1, 0.1, 0.3]) 42 >>> s1.mean_rate() 43 8.0 44 >>> s1.cv_isi() 45 0.565685424949 33 46 """ 34 # TODO in the definition, should a spike train be ordered?35 36 # TODO : should we handle different population shapes differently?37 47 38 48 ####################################################################### … … 41 51 def __init__(self, spike_times, dt=None, t_start=None, t_stop=None): 42 52 """ 43 `spike_times` is a list/numpy array of spike times (in milliseconds) 44 45 TODO: We proposed initially that : 46 If `dt` is specified, the time values should be ints, 47 and will be multiplied by `dt`, otherwise time values should be floats. 48 Markus suggested that the internal representation should be integer and 49 that analysis methods also. 50 51 If `t_start` and `t_stop` are not specified, they are inferred from the data. 52 53 the format adopted for the representation is relative=False, quantized=False 53 Constructor of the SpikeTrain object 54 55 See also 56 SpikeTrain 54 57 55 58 """ 56 59 57 60 if dt is not None: 58 if dt <=0:61 if dt <= 0: 59 62 raise ValueError("dt must be greater than zero") 60 63 #self.spike_times *= dt 61 64 62 self.dt = dt 63 self.t_start = t_start 64 self.t_stop = t_stop 65 65 self.dt = dt 66 self.t_start = t_start 67 self.t_stop = t_stop 66 68 self.spike_times = numpy.array(spike_times, 'float') 67 69 … … 69 71 # the spikes with t >= t_start 70 72 if self.t_start is not None: 71 idx = numpy.where(self.spike_times >= self.t_start)[0] 72 self.spike_times = self.spike_times[idx] 73 assert numpy.all(self.spike_times >= self.t_start), \ 74 "Spike times out of range (t_start=%s, min(spike_times)=%s" % (self.t_start,self.spike_times.min()) 73 self.spike_times = numpy.extract((self.spike_times >= self.t_start), self.spike_times) 75 74 76 75 # If t_stop is not None, we resize the spike_train keeping only 77 76 # the spikes with t <= t_stop 78 77 if self.t_stop is not None: 79 idx = numpy.where(self.spike_times <= self.t_stop)[0]80 self.spike_times = self.spike_times[idx] 81 assert numpy.all(self.spike_times <= self.t_stop), \82 "Spike times out of range (t_stop=%s, max(spike_times)=%s" % (self.t_stop,self.spike_times.max())83 78 self.spike_times = numpy.extract((self.spike_times <= self.t_stop), self.spike_times) 79 80 # We sort the spike_times. May be slower, but is necessary by the way for quite a 81 # lot of methods... 82 self.spike_times = numpy.sort(self.spike_times) 84 83 # Here we deal with the t_start and t_stop values if the SpikeTrain 85 84 # is empty, with only one element or several elements, if we … … 91 90 size = len(spike_times) 92 91 if size == 0: 93 if self.t_start is None: 92 if self.t_start is None: 94 93 self.t_start = 0 95 94 if self.t_stop is None: … … 111 110 112 111 if self.t_start >= self.t_stop : 113 raise Exception("Incompatible time interval for the creation of the SpikeTrain. t_start=%s, t_stop=%s" % (self.t_start, self.t_stop))112 raise Exception("Incompatible time interval : t_start = %s, t_stop = %s" % (self.t_start, self.t_stop)) 114 113 if self.t_start < 0: 115 114 raise ValueError("t_start must not be negative") … … 122 121 def __len__(self): 123 122 return len(self.spike_times) 123 124 def __getslice__(self, i, j): 125 """ 126 Return a sublist of the spike_times vector of the SpikeTrain 127 """ 128 return self.spike_times[i:j] 129 130 def copy(self): 131 """ 132 Return a copy of the SpikeTrain object 133 """ 134 return SpikeTrain(self.spike_times, self.dt, self.t_start, self.t_stop) 135 136 def __getdisplay__(self,display): 137 """ 138 Return a pylab object with a plot() function to draw the plots. 139 140 Inputs: 141 display - if True, a new figure is created. Otherwise, if display is a 142 subplot object, this object is returned. 143 """ 144 if display is False: 145 return None 146 elif display is True: 147 pylab.figure() 148 return pylab 149 else: 150 return display 151 152 def __labels__(self, subplot, xlabel, ylabel): 153 """ 154 Function to put some labels on a plot 155 156 Inputs: 157 subplot - the targeted plot 158 xlabel - a string for the x label 159 ylabel - a string for the y label 160 """ 161 if hasattr(subplot, 'xlabel'): 162 subplot.xlabel(xlabel) 163 subplot.ylabel(ylabel) 164 else: 165 subplot.set_xlabel(xlabel) 166 subplot.set_ylabel(ylabel) 124 167 125 168 def duration(self): 169 """ 170 Return the duration of the SpikeTrain 171 """ 126 172 return self.t_stop - self.t_start 173 174 def merge(self, spiketrain): 175 """ 176 Add the spike times from a spiketrain to the current SpikeTrain 177 178 Inputs: 179 spiketrain - The SpikeTrain that should be added 180 181 Examples: 182 >> a = SpikeTrain(range(0,100,10),0.1,0,100) 183 >> b = SpikeTrain(range(400,500,10),0.1,400,500) 184 >> a.merge(b) 185 >> a.spike_times 186 >> [ 0., 10., 20., 30., 40., 50., 60., 70., 80., 187 90., 400., 410., 420., 430., 440., 450., 460., 470., 188 480., 490.] 189 >> a.t_stop 190 >> 500 191 """ 192 self.spike_times = numpy.concatenate((self.spike_times, spiketrain.spike_times)) 193 self.spike_times = numpy.sort(self.spike_times) 194 self.t_start = min(self.t_start, spiketrain.t_start) 195 self.t_stop = max(self.t_stop, spiketrain.t_stop) 127 196 128 197 def format(self, relative=False, quantized=False): 129 198 """ 130 a function to format a spike train from one format to another. 131 outputs a numpy array 132 199 Return an array with a new representation of the spike times 200 201 Inputs: 202 relative - if True, spike times are expressed in a relative 203 time compared to the previsous one 204 quantized - a value to divide spike times with before rounding 205 206 Examples: 207 >>> st.spikes_times=[0, 2.1, 3.1, 4.4] 208 >>> st.format(relative=True) 209 >>> [0, 2.1, 1, 1.3] 210 >>> st.format(quantized=2) 211 >>> [0, 1, 2, 2] 133 212 """ 134 213 spike_times = self.spike_times.copy() 135 spike_times.sort() 136 137 if relative and len(spike_times)>0: 214 215 if relative and len(spike_times) > 0: 138 216 spike_times[1:] = spike_times[1:] - spike_times[:-1] 139 217 … … 145 223 return spike_times 146 224 225 226 147 227 ####################################################################### 148 228 ## Analysis methods that can be applied to a SpikeTrain object ## 149 229 ####################################################################### 230 150 231 def isi(self): 151 # TODO this needs some thinking to know how to handle the border, in particular the 152 # first spike and t_start 153 return self.format(relative=True, quantized=False)[1:] 154 155 # Returns the mean firing rate of the SpikeTrain 232 """ 233 Return an array with the inter-spike intervals of the SpikeTrain 234 235 Examples: 236 >>> st.spikes_times=[0, 2.1, 3.1, 4.4] 237 >>> st.isi() 238 >>> [2.1, 1., 1.3] 239 240 See also 241 cv_isi 242 """ 243 return numpy.diff(self.spike_times) 244 156 245 def mean_rate(self, t_start=None, t_stop=None): 157 """ Mean firing rate between t_start and t_stop in Hz 158 159 NOTE: avoided calling where when defaults settings t_start=self.t_start, t_stop=self.t_stop 160 """ 161 if (t_start==None) & (t_stop==None): 162 t_start=self.t_start 163 t_stop=self.t_stop 164 idx = self.spike_times 165 else: 166 if t_start==None: t_start=self.t_start 167 if t_stop==None: t_stop=self.t_stop 246 """ 247 Return the mean firing rate between t_start and t_stop, in Hz 248 249 Inputs: 250 t_start - in ms. If not defined, the one of the SpikeTrain object is used 251 t_stop - in ms. If not defined, the one of the SpikeTrain object is used 252 """ 253 if (t_start == None) & (t_stop == None): 254 t_start = self.t_start 255 t_stop = self.t_stop 256 idx = self.spike_times 257 else: 258 if t_start == None: t_start=self.t_start 259 if t_stop == None: t_stop=self.t_stop 168 260 idx = numpy.where((self.spike_times >= t_start) & (self.spike_times <= t_stop))[0] 169 261 return 1000.*len(idx)/(t_stop-t_start) 170 262 171 # Returns the cv of the isi of the SpikeTrain172 263 def cv_isi(self): 173 264 """ 265 Return the coefficient of variation of the isis. 266 174 267 cv_isi is the ratio between the standard deviation and the mean of the ISI 175 176 268 The irregularity of individual spike trains is measured by the squared 177 269 coefficient of variation of the corresponding inter-spike interval (ISI) … … 181 273 Poisson-type behavior. As a measure for irregularity in the network one 182 274 can use the average irregularity across all neurons. 183 184 TODO: is it useful to get the std of CV? 275 276 See also 277 isi 278 185 279 """ 186 280 isi = self.isi() 187 #TODO return an exception if mean.isi= 0188 281 if len(isi) > 0: 189 282 return numpy.std(isi)/numpy.mean(isi) … … 192 285 193 286 def fano_factor_isi(self): 194 """ returns the fano factor of this spike trains ISI (see SpikeList.fano_factor)""" 287 """ 288 Return the fano factor of this spike trains ISI. 289 290 The Fano Factor is defined as the variance of the isi divided by the mean of the isi 291 292 See also 293 isi, cv_isi 294 """ 195 295 isi = self.isi() 196 296 if len(isi) > 0: 197 #firing_rate = self.time_histogram(time_bin,False)198 297 fano = numpy.var(isi)/numpy.mean(isi) 199 298 return fano … … 201 300 raise Exception("No spikes in the SpikeTrain !") 202 301 203 def time_axis(self, time_bin ):302 def time_axis(self, time_bin=10): 204 303 """ 205 304 Return a time axis between t_start and t_stop according to a time_bin 305 306 Inputs: 307 time_bin - the bin width 308 309 Examples: 310 >>> st = SpikeTrain(range(100),0.1,0,100) 311 >>> st.time_axis(10) 312 >>> [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90] 313 314 See also 315 time_histogram 316 206 317 """ 207 318 return numpy.arange(self.t_start, self.t_stop, time_bin) 208 319 209 def raster_plot(self, t_start=None, t_stop=None, color='b'):320 def raster_plot(self, t_start=None, t_stop=None, display=True, kwargs={}): 210 321 """ 211 322 Generate a raster plot with the SpikeTrain in a subwindow of interest, 212 defined by t_start and t_stop. Those are not the global t_start and t_stop 213 of the SpikeTrain objects. If not defined, we use the one of the SpikeTrain 214 object 215 """ 216 if t_start is None: 217 t_start = self.t_start 218 if t_stop is None: 219 t_stop = self.t_stop 220 idx = numpy.where((self.spike_times >= t_start) & (self.spike_times <= t_stop))[0] 221 spikes = self.spike_times[idx] 222 if len(spikes) > 0: 223 pylab.figure() 224 pylab.scatter(spikes,numpy.ones(len(spikes)), c=color) 225 pylab.xlabel("Time (ms)", size="x-large") 226 pylab.ylabel("Neuron #", size="x-large") 227 228 # Method to sort a SpikeTrain 229 def sort_by_time(self): 230 self.spike_time = sort(self.spike_time) 231 232 def subSpikeTrain(self, t_start, t_stop): 233 """ Returns a spike train sliced between t_start and t_stop 234 t_start and t_stop may either be single values or sequences of start 235 and stop times. 236 """ 237 if hasattr(t_start, '__len__'): 238 assert len(t_start) == len(t_stop) 239 mask = False 240 for t0,t1 in zip(t_start, t_stop): 241 mask = mask | (self.spike_times >= t0) & (self.spike_times <= t1) 242 t_start = t_start[0] 243 t_stop = t_stop[-1] 244 else: 245 mask = (self.spike_times >= t_start) & (self.spike_times <= t_stop) 246 idx = numpy.where(mask)[0] 247 spikes = self.spike_times[idx] 323 defined by t_start and t_stop. 324 325 Inputs: 326 t_start - in ms. If not defined, the one of the SpikeTrain object is used 327 t_stop - in ms. If not defined, the one of the SpikeTrain object is used 328 display - if True, a new figure is created. Could also be a subplot 329 kwargs - dictionary contening extra parameters that will be sent to the plot 330 function 331 332 Examples: 333 >>> z = subplot(221) 334 >>> st.raster_plot(display=z, kwargs={'color':'r'}) 335 336 See also 337 SpikeList.raster_plot 338 """ 339 if t_start is None: t_start = self.t_start 340 if t_stop is None: t_stop = self.t_stop 341 spikes = numpy.extract((self.spike_times >= t_start) & (self.spike_times <= t_stop), self.spike_times) 342 subplot = self.__getdisplay__(display) 343 if not subplot or not ENABLE_PLOTS: 344 print MATPLOTLIB_ERROR 345 return 346 else: 347 if len(spikes) > 0: 348 xlabel = "Time (ms)" 349 ylabel = "Neurons #" 350 self.__labels__(subplot, xlabel, ylabel) 351 subplot.scatter(spikes,numpy.ones(len(spikes)),**kwargs) 352 pylab.draw() 353 354 def add_offset(self, offset): 355 """ 356 Add an offset to the SpikeTrain object. t_start and t_stop are 357 shifted from offset, so does all the spike times. 358 359 Inputs: 360 offset - the time offset, in ms 361 362 Examples: 363 >>>spktrain = SpikeTrain(arange(0,100,10)) 364 >>>spktrain.add_offset(50) 365 >>>spklist.spike_times 366 >>>[ 50., 60., 70., 80., 90., 100., 110., 367 120., 130., 140.] 368 """ 369 self.t_start += offset 370 self.t_stop += offset 371 self.spike_times += offset 372 373 def time_slice(self, t_start, t_stop): 374 """ 375 Return a new SpikeTrain obtained by slicing between t_start and t_stop 376 377 Inputs: 378 t_start - begining of the new SpikeTrain, in ms. 379 t_stop - end of the new SpikeTrain, in ms. 380 381 """ 382 spikes = numpy.extract((self.spike_times >= t_start) & (self.spike_times <= t_stop), self.spike_times) 248 383 return SpikeTrain(spikes, self.dt, t_start, t_stop) 249 384 250 def time_histogram(self, time_bin , normalized=True): 385 386 def time_histogram(self, time_bin=10, normalized=True): 251 387 """ 252 388 Bin the spikes with the specified bin width. The first and last bins 253 389 are calculated from `self.t_start` and `self.t_stop`. 254 If `normalized` is True, the bin values are scaled so as to represent 255 firing rates in spikes/second, otherwise it's the number of spikes per bin. 256 """ 257 if hasattr(time_bin, '__len__'): 258 bins = time_bin 259 else: 260 bins = self.time_axis(time_bin) 261 262 (hist, lower_edges ) = numpy.histogram(self.spike_times, bins) 390 391 Inputs: 392 time_bin - the bin width for gathering spikes_times 393 normalized - if True, the bin values are scaled to represent firing rates 394 in spikes/second, otherwise otherwise it's the number of spikes 395 per bin. 396 397 Examples: 398 >>> st=SpikeTrain(range(0,100,5),0.1,0,100) 399 >>> st.time_histogram(10) 400 >>> [200, 200, 200, 200, 200, 200, 200, 200, 200, 200] 401 >>> st.time_histogram(10, normalized=False) 402 >>> [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] 403 404 See also 405 time_axis 406 """ 407 bins = self.time_axis(time_bin) 408 hist, lower_edges = numpy.histogram(self.spike_times, bins) 263 409 if normalized and isinstance(time_bin, int): # what about normalization if time_bin is a sequence? 264 410 hist *= 1000.0/time_bin … … 267 413 def relative_times(self): 268 414 """ 269 Rescale spike times to make them relative to t_start. 270 t_start becomes 0.""" 415 Rescale the spike times to make them relative to t_start. 416 417 Note that the SpikeTrain object itself is modified, t_start 418 is substracted to spike_times, t_start and t_stop 419 """ 271 420 if self.t_start != 0: 272 421 self.spike_times -= self.t_start 273 self.t_stop -= self.t_start 274 self.t_start = 0.0 275 422 self.t_stop -= self.t_start 423 self.t_start = 0.0 424 425 def VictorPurpuraDistance(self, spktrain, cost): 426 """ 427 Function to calculate the Victor-Purpura distance between two spike trains. 428 See J. D. Victor and K. P. Purpura, 429 Nature and precision of temporal coding in visual cortex: a metric-space 430 analysis., 431 J Neurophysiol,76(2):1310-1326, 1996 432 433 Inputs: 434 spktrain - the other SpikeTrain 435 cost - The cost parameter. See the paper for more informations 436 """ 437 nspk_1 = len(self) 438 nspk_2 = len(spktrain) 439 if cost == 0: 440 return abs(nspk_1-nspk_2) 441 elif cost > 1e9 : 442 return nspk_1+nspk_2 443 scr = numpy.zeros((nspk_1+1,nspk_2+1)) 444 scr[:,0] = numpy.arange(0,nspk_1+1) 445 scr[0,:] = numpy.arange(0,nspk_2+1) 446 447 if nspk_1 > 0 and nspk_2 > 0: 448 for i in xrange(1,nspk_1+1): 449 for j in xrange(1,nspk_2+1): 450 scr[i,j] = min(scr[i-1,j]+1,scr[i,j-1]+1) 451 scr[i,j] = min(scr[i,j],scr[i-1,j-1]+cost*abs(self.spike_times[i-1]-spktrain.spike_times[j-1])) 452 return scr[nspk_1,nspk_2] 453 454 455 def KreuzDistance(self, spktrain): 456 """ 457 Function to calculate the Kreuz/Politi distance between two spike trains 458 See Kreuz, T.; Haas, J.S.; Morelli, A.; Abarbanel, H.D.I. & Politi, 459 A. Measuring spike train synchrony. 460 J Neurosci Methods, 2007, 165, 151-161 461 462 Inputs: 463 spktrain - the other SpikeTrain 464 """ 465 N = (self.t_stop-self.t_start)/self.dt 466 vec_1 = numpy.zeros(N) 467 vec_2 = numpy.zeros(N) 468 result = numpy.zeros(N) 469 idx_spikes = self.spike_times/self.dt 470 previous_spike = 0 471 for spike in idx_spikes: 472 vec_1[previous_spike:spike] = (spike-previous_spike)*self.dt 473 previous_spike = spike 474 vec_1[previous_spike-1:N] = vec_1[previous_spike-2] 475 idx_spikes = spktrain.spike_times/self.dt 476 previous_spike = 0 477 for spike in idx_spikes: 478 vec_2[previous_spike:spike] = (spike-previous_spike)*self.dt 479 previous_spike = spike 480 vec_2[previous_spike-1:N] = vec_2[previous_spike-2] 481 idx = numpy.where(vec_1 <= vec_2)[0] 482 result[idx] = vec_1[idx]/vec_2[idx] - 1 483 idx = numpy.where(vec_1 > vec_2)[0] 484 result[idx] = -(vec_2[idx]/vec_1[idx] -1) 485 return numpy.sum(numpy.abs(result)) 486 487 488 def record(self, filename = 'SpikeTrain.wav', fs=44100): 489 """ 490 Fancy tool, not really useful but still... 491 Record the 'sound' produced by a SpikeTrain. Need the scikits.audiolab 492 package 493 494 Inputs: 495 filename - the name of the output file (should have .wav extension) 496 fs - the sampling rate 497 498 Examples: 499 >>> spktrain.record("my_sound.wav") 500 """ 501 # from the spike list 502 simtime_seconds = (self.t_stop - self.t_start)/1000. 503 (trace,time) = numpy.histogram(self.spike_times*1000., fs*simtime_seconds) 504 # TODO convolve with proper spike... 505 spike = numpy.ones((fs/1000.,)) # one ms 506 trace = numpy.convolve(trace, spike, mode='same')#/2.0 507 trace /= numpy.abs(trace).max() * 1.1 508 try: 509 from scikits.audiolab import wavwrite 510 except ImportError: 511 print "You need the scikits.audiolab package to produce sounds !" 512 wavwrite(trace, filename, fs = fs, enc = 'pcm26') 513 514 #################################################################### 515 ### TOO SPECIFIC METHOD ? 516 ### Better documentation 517 #################################################################### 276 518 def tuning_curve(self, var_array, normalized=False, method='sum'): 277 519 """ … … 320 562 return tuning_curve 321 563 564 565 #################################################################### 566 ### TOO SPECIFIC METHOD ? 567 ### Better documentation 568 #################################################################### 322 569 def frequency_spectrum(self, time_bin): 323 570 """ … … 325 572 frequency axis. 326 573 """ 327 hist = self.time_histogram(time_bin, normalized=False)574 hist = self.time_histogram(time_bin, normalized=False) 328 575 freq_spect = analysis.simple_frequency_spectrum(hist) 329 freq_bin = 1000.0/self.duration() # Hz330 freq_axis = numpy.arange(len(freq_spect)) * freq_bin576 freq_bin = 1000.0/self.duration() # Hz 577 freq_axis = numpy.arange(len(freq_spect)) * freq_bin 331 578 return freq_spect, freq_axis 332 579 580 581 #################################################################### 582 ### TOO SPECIFIC METHOD ? 583 ### Better documentation 584 #################################################################### 333 585 def f1f0_ratio(self, time_bin, f_stim): 334 586 """ … … 346 598 raise Exception(errmsg) 347 599 return F1/F0 348 349 def merge(self, spiketrain, relative_times=False): 350 """ 351 Add the spike times from `spiketrain` to this `SpikeTrain`s spike list. 352 """ 353 if relative_times: 354 self.relative_times() 355 spiketrain.relative_times() 356 self.spike_times = numpy.concatenate((self.spike_times, spiketrain.spike_times)) 357 self.spike_times.sort() 358 self.t_start = min(self.t_start, spiketrain.t_start) 359 self.t_stop = max(self.t_stop, spiketrain.t_stop) 360 600 601 361 602 362 603 class SpikeList(object): 363 604 """ 364 A SpikeList object is a list of SpikeTrain objects.365 366 >>> sl = SpikeList(3, [(0, 0.1), (1, 0.1), (0, 0.2)])367 >>> type( sl.spiketrains[0] ) 368 <type SpikeTrain>369 >>> sl.spiketrains[0].spike_times370 array([ 0.1, 0.2])371 >>> sl.as_ids_times()372 (array([0,0,1]), array([0.1,0.2,0.1]))373 >>> sl.as_ids_times(relative=True)374 (array([0,1,0]), array([0.1,0.0,0.1]))375 >>> sl.as_ids_times(quantized=0.01)376 (array([0,0,1]), array([10,20,10]))377 >>> sl.as_list_id_time()378 [(0,0.1), (0,0.2), (1,0.1)]379 >>> sl.as_id_list_times()380 [(0, array([0.1, 0.2])), (1, array([0.1]))]381 >>> sl.as_time_list_ids()382 [(0.1, [0,1]), (0.2, [0])]383 >>> sl.as_2byN_array()384 >>> array([[0,0,1],[0.1,0.2,0.1]])605 SpikeList(spikes, id_list, dt=None, t_start=None, t_stop=None, dims=None) 606 607 Return a SpikeList object which will be a list of SpikeTrain objects. 608 609 Inputs: 610 spikes - a list of (id,time) tuples (id being in id_list) 611 is_list - the list of the ids of all recorded cells (needed for silent cells) 612 dt - if dt is specified, time values should be floats 613 t_start - begining of the SpikeList, in ms. If None, will be infered from the data 614 t_stop - end of the SpikeList, in ms. If None, will be infered from the data 615 dims - dimensions of the recorded population, if not 1D population 616 617 dt, t_start and t_stop are shared for all SpikeTrains object within the SpikeList 618 619 Examples: 620 >>> sl = SpikeList(3, [(0, 0.1), (1, 0.1), (0, 0.2)]) 621 >>> type( sl[0] ) 622 >>> <type SpikeTrain> 623 624 See also 625 loadSpikeList 385 626 386 627 """ … … 388 629 ## Constructor and key methods to manipulate the SpikeList objects ## 389 630 ####################################################################### 390 def __init__(self, spikes, id_list, dt=None, t_start=None, t_stop=None, label=''): 391 """ 392 `spikes` is a list/tuple of (id,t) tuples (id in id_list) 393 `id_list` is the list of ids of all recorded cells (needed for silent cells) 394 If `dt`is specified, the time values should be ints, 395 and will be multiplied by `dt`, otherwise time values should be floats. 396 If `t_start` and `t_stop` are not specified, they are inferred from the data. 397 398 dt, t_start and t_stop are shared for all SpikeTrains 399 400 """ 401 self.id_list = id_list 402 self.t_start = t_start 403 self.t_stop = t_stop 404 &n
