Changeset 200
- Timestamp:
- 09/19/08 10:27:04 (4 months ago)
- Files:
-
- branches/cleanup/src/signals.py (modified) (38 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/cleanup/src/signals.py
r199 r200 9 9 try : 10 10 import pylab 11 ENABLE_PLOTS = True 11 12 except ImportError: 13 ENABLE_PLOTS = False 12 14 print "Warning: pylab not detected, plots will be disabled" 13 15 … … 17 19 class SpikeTrain(object): 18 20 """ 21 SpikeTrain(spikes_times, dt=None, t_start=None, t_stop=None) 19 22 This class defines a spike train as a list of times events. 20 23 21 24 Event times are given in a list (sparse representation) in milliseconds. 22 25 23 >>> s1 = SpikeTrain([0.0, 0.1, 0.2, 0.5]) 24 >>> s2 = SpikeTrain([0, 1, 2, 5], dt=0.1) 25 >>> assert all(s1.spike_times == s2.spike_times) 26 >>> s1.isi() 27 array([ 0.1, 0.1, 0.3]) 28 >>> s1.mean_rate() 29 8.0 30 >>> s1.cv_isi() 31 0.565685424949 26 Inputs: 27 spike_times - a list/numpy array of spike times (in milliseconds) 28 t_start - beginning of the SpikeTrain (if not, this is infered) 29 t_stop - end of the SpikeTrain (if not, this is infered) 30 dt - time precision of the spike events 31 32 Examples: 33 >>> s1 = SpikeTrain([0.0, 0.1, 0.2, 0.5]) 34 >>> s2 = SpikeTrain([0, 1, 2, 5], dt=0.1) 35 >>> assert all(s1.spike_times == s2.spike_times) 36 >>> s1.isi() 37 array([ 0.1, 0.1, 0.3]) 38 >>> s1.mean_rate() 39 8.0 40 >>> s1.cv_isi() 41 0.565685424949 32 42 """ 33 43 … … 37 47 def __init__(self, spike_times, dt=None, t_start=None, t_stop=None): 38 48 """ 39 `spike_times` is a list/numpy array of spike times (in milliseconds) 40 41 TODO: We proposed initially that : 42 If `dt`is specified, the time values should be ints, 43 and will be multiplied by `dt`, otherwise time values should be floats. 44 Markus suggested that the internal representation should be integer and that analysis methods also. 45 46 If `t_start` and `t_stop` are not specified, they are inferred from the data. 47 48 the format adopted for the representation is relative=False, quantized=False 49 Constructor of the SpikeTrain object 50 51 See also 52 SpikeTrain 49 53 50 54 """ … … 70 74 self.spike_times = numpy.extract((self.spike_times <= self.t_stop), self.spike_times) 71 75 76 # We sort the spike_times. May be slower, but is necessary by the way for quite a 77 # lot of methods... 78 self.spike_times = numpy.sort(self.spike_times) 72 79 # Here we deal with the t_start and t_stop values if the SpikeTrain 73 80 # is empty, with only one element or several elements, if we … … 111 118 return len(self.spike_times) 112 119 113 def __getslice(self, i, j): 120 def __getslice__(self, i, j): 121 """ 122 Return a sublist of the spike_times vector of the SpikeTrain 123 """ 114 124 return self.spike_times[i:j] 115 125 116 126 def __getdisplay__(self,display): 127 """ 128 Return a pylab object with a plot() function to draw the plots. 129 130 Inputs: 131 display - if True, a new figure is created. Otherwise, if display is a 132 subplot object, this object is returned. 133 """ 117 134 if display is False: 118 135 return None … … 124 141 125 142 def __labels__(self, subplot, xlabel, ylabel): 143 """ 144 Function to put some labels on a plot 145 146 Inputs: 147 subplot - the targeted plot 148 xlabel - a string for the x label 149 ylabel - a string for the y label 150 """ 126 151 if hasattr(subplot, 'xlabel'): 127 subplot.xlabel(xlabel , size="large")128 subplot.ylabel(ylabel , size="large")129 else: 130 subplot.set_xlabel(xlabel , size="large")131 subplot.set_ylabel(ylabel , size="large")152 subplot.xlabel(xlabel) 153 subplot.ylabel(ylabel) 154 else: 155 subplot.set_xlabel(xlabel) 156 subplot.set_ylabel(ylabel) 132 157 133 158 def duration(self): 159 """ 160 Return the duration of the SpikeTrain 161 """ 134 162 return self.t_stop - self.t_start 135 163 136 164 def format(self, relative=False, quantized=False): 137 165 """ 138 a function to format a spike train from one format to another. 139 outputs a numpy array 140 166 Return an array with a new representation of the spike times 167 168 Inputs: 169 relative - if True, spike times are expressed in a relative 170 time compared to the previsous one 171 quantized - a value to divide spike times with before rounding 172 173 Examples: 174 >>> st.spikes_times=[0, 2.1, 3.1, 4.4] 175 >>> st.format(relative=True) 176 >>> [0, 2.1, 1, 1.3] 177 >>> st.format(quantized=2) 178 >>> [0, 1, 2, 2] 141 179 """ 142 180 spike_times = self.spike_times.copy() 143 spike_times.sort()144 181 145 182 if relative and len(spike_times) > 0: … … 160 197 161 198 def isi(self): 162 # TODO this needs some thinking to know how to handle the border, in particular the 163 # first spike and t_start 199 """ 200 Return an array with the inter-spike intervals of the SpikeTrain 201 202 Examples: 203 >>> st.spikes_times=[0, 2.1, 3.1, 4.4] 204 >>> st.isi() 205 >>> [2.1, 1., 1.3] 206 207 See also 208 cv_isi 209 """ 164 210 return numpy.diff(self.spike_times) 165 211 … … 167 213 def mean_rate(self, t_start=None, t_stop=None): 168 214 """ 169 Mean firing rate between t_start and t_stop in Hz 170 By default, if t_start and t_stop are not defined, we used those of the SpikeTrain object 215 Return the mean firing rate between t_start and t_stop, in Hz 216 217 Inputs: 218 t_start - in ms. If not defined, the one of the SpikeTrain object is used 219 t_stop - in ms. If not defined, the one of the SpikeTrain object is used 171 220 """ 172 221 if (t_start == None) & (t_stop == None): … … 183 232 def cv_isi(self): 184 233 """ 234 Return the coefficient of variation of the isis. 235 185 236 cv_isi is the ratio between the standard deviation and the mean of the ISI 186 187 237 The irregularity of individual spike trains is measured by the squared 188 238 coefficient of variation of the corresponding inter-spike interval (ISI) … … 194 244 195 245 See also 196 SpikeList.cv_isi246 isi 197 247 198 248 """ 199 249 isi = self.isi() 200 #TODO return an exception if mean.isi= 0201 250 if len(isi) > 0: 202 251 return numpy.std(isi)/numpy.mean(isi) … … 209 258 210 259 See also 211 SpikeList.fano_factor260 isi, cv_isi 212 261 """ 213 262 isi = self.isi() … … 218 267 raise Exception("No spikes in the SpikeTrain !") 219 268 220 def time_axis(self, time_bin ):269 def time_axis(self, time_bin=10): 221 270 """ 222 271 Return a time axis between t_start and t_stop according to a time_bin 272 273 Inputs: 274 time_bin - the bin width 275 276 Examples: 277 >>> st = SpikeTrain(range(100),0.1,0,100) 278 >>> st.time_axis(10) 279 >>> [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90] 280 281 See also 282 time_histogram 283 223 284 """ 224 285 return numpy.arange(self.t_start, self.t_stop, time_bin) 225 286 226 287 227 def raster_plot(self, t_start=None, t_stop=None, color='b', display=True):288 def raster_plot(self, t_start=None, t_stop=None, display=True, kwargs={}): 228 289 """ 229 290 Generate a raster plot with the SpikeTrain in a subwindow of interest, 230 defined by t_start and t_stop. Those are not the global t_start and t_stop 231 of the SpikeTrain objects. If not defined, we use the one of the SpikeTrain 232 object 233 234 - color is a string color like in pylab plots 'k','r' 235 - display can be either a boolean (to ensure backward compatibilities) or a figure 236 object with a plot() method. 291 defined by t_start and t_stop. 292 293 Inputs: 294 t_start - in ms. If not defined, the one of the SpikeTrain object is used 295 t_stop - in ms. If not defined, the one of the SpikeTrain object is used 296 display - if True, a new figure is created. Could also be a subplot 297 kwargs - dictionary contening extra parameters that will be sent to the plot 298 function 299 300 Examples: 301 >>> z = subplot(221) 302 >>> st.raster_plot(display=z, kwargs={'color':'r'}) 237 303 238 304 See also 239 305 SpikeList.raster_plot 240 306 """ 241 if t_start is None: 242 t_start = self.t_start 243 if t_stop is None: 244 t_stop = self.t_stop 307 if t_start is None: t_start = self.t_start 308 if t_stop is None: t_stop = self.t_stop 245 309 spikes = numpy.extract((self.spike_times >= t_start) & (self.spike_times <= t_stop), self.spike_times) 246 310 subplot = self.__getdisplay__(display) 247 if not subplot :311 if not subplot or not ENABLE_PLOTS: 248 312 return spikes 249 313 else: … … 252 316 ylabel = "Neurons #" 253 317 self.__labels__(subplot, xlabel, ylabel) 254 subplot.scatter(spikes,numpy.ones(len(spikes)), c=color) 255 256 257 258 # Method to sort a SpikeTrain 259 def sort_by_time(self): 260 """ 261 Sort the spike times according to the time axis 262 """ 263 self.spike_time = sort(self.spike_time) 264 265 def subSpikeTrain(self, t_start, t_stop): 318 subplot.scatter(spikes,numpy.ones(len(spikes)),**kwargs) 319 pylab.draw() 320 321 322 def time_slice(self, t_start, t_stop): 266 323 """ 267 Return a spike train sliced between t_start and t_stop 268 t_start and t_stop may either be single values or sequences of start 269 and stop times. 270 """ 271 if hasattr(t_start, '__len__'): 272 assert len(t_start) == len(t_stop) 273 mask = False 274 for t0,t1 in zip(t_start, t_stop): 275 mask = mask | (self.spike_times >= t0) & (self.spike_times <= t1) 276 t_start = t_start[0] 277 t_stop = t_stop[-1] 278 else: 279 mask = (self.spike_times >= t_start) & (self.spike_times <= t_stop) 280 idx = numpy.where(mask)[0] 281 spikes = self.spike_times[idx] 324 Return a new SpikeTrain obtained by slicing between t_start and t_stop 325 326 Inputs: 327 t_start - begining of the new SpikeTrain, in ms. 328 t_stop - end of the new SpikeTrain, in ms. 329 330 """ 331 spikes = numpy.extract((self.spike_times >= t_start) & (self.spike_times <= t_stop), self.spike_times) 282 332 return SpikeTrain(spikes, self.dt, t_start, t_stop) 283 333 284 def time_histogram(self, time_bin , normalized=True): 334 335 def time_histogram(self, time_bin=10, normalized=True): 285 336 """ 286 337 Bin the spikes with the specified bin width. The first and last bins 287 338 are calculated from `self.t_start` and `self.t_stop`. 288 If `normalized` is True, the bin values are scaled so as to represent 289 firing rates in spikes/second, otherwise it's the number of spikes per bin. 290 """ 291 if hasattr(time_bin, '__len__'): 292 bins = time_bin 293 else: 294 bins = self.time_axis(time_bin) 295 296 (hist, lower_edges ) = numpy.histogram(self.spike_times, bins) 339 340 Inputs: 341 time_bin - the bin width for gathering spikes_times 342 normalized - if True, the bin values are scaled to represent firing rates 343 in spikes/second, otherwise otherwise it's the number of spikes 344 per bin. 345 346 Examples: 347 >>> st=SpikeTrain(range(0,100,5),0.1,0,100) 348 >>> st.time_histogram(10) 349 >>> [200, 200, 200, 200, 200, 200, 200, 200, 200, 200] 350 >>> st.time_histogram(10, normalized=False) 351 >>> [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] 352 353 See also 354 time_axis 355 """ 356 bins = self.time_axis(time_bin) 357 hist, lower_edges = numpy.histogram(self.spike_times, bins) 297 358 if normalized and isinstance(time_bin, int): # what about normalization if time_bin is a sequence? 298 359 hist *= 1000.0/time_bin … … 301 362 def relative_times(self): 302 363 """ 303 Rescale spike times to make them relative to t_start. 304 t_start becomes 0.""" 364 Rescale the spike times to make them relative to t_start. 365 366 Note that the SpikeTrain object itself is modified, t_start 367 is substracted to spike_times, t_start and t_stop 368 """ 305 369 if self.t_start != 0: 306 370 self.spike_times -= self.t_start … … 391 455 self.spike_times.sort() 392 456 self.t_start = min(self.t_start, spiketrain.t_start) 393 self.t_stop = max(self.t_stop, spiketrain.t_stop)457 self.t_stop = max(self.t_stop, spiketrain.t_stop) 394 458 395 459 … … 423 487 ## Constructor and key methods to manipulate the SpikeList objects ## 424 488 ####################################################################### 425 def __init__(self, spikes, id_list, dt=None, t_start=None, t_stop=None, label=''): 426 """ 427 `spikes` is a list/tuple of (id,t) tuples (id in id_list) 428 `id_list` is the list of ids of all recorded cells (needed for silent cells) 489 def __init__(self, spikes, id_list, dt=None, t_start=None, t_stop=None, dims=None, label=''): 490 """ 491 Constructor of the SpikeList object 492 493 spikes is a list of (id,t) tuples (id in id_list) 494 id_list is the list of ids of all recorded cells (needed for silent cells) 429 495 If `dt` is specified, the time values should be ints, 430 496 and will be multiplied by `dt`, otherwise time values should be floats. 431 If `t_start` and `t_stop` are not specified, they are inferred from the data. 497 t_start and t_stop are defined in ms. If they are not specified, they 498 are inferred from the data. 432 499 433 500 dt, t_start and t_stop are shared for all SpikeTrains in the SpikeList 501 502 See also 503 loadSpikeList 434 504 435 505 """ … … 439 509 self.dt = dt 440 510 self.label = label 511 self.dimensions = None 512 self.N = len(id_list) 441 513 self.spiketrains = {} 442 514 … … 454 526 self.__calc_startstop() 455 527 456 457 def N(self):458 return len(self.id_list)459 460 528 def __calc_startstop(self): 461 529 """ … … 468 536 start_times = numpy.array([self.spiketrains[idx].t_start for idx in self.id_list]) 469 537 self.t_start = numpy.min(start_times) 470 print "Warning, t_start is infered from the data : %f" %self.t_start538 logging.debug("Warning, t_start is infered from the data : %f" %self.t_start) 471 539 for id in self.spiketrains.keys(): 472 540 self.spiketrains[id].t_start = self.t_start … … 474 542 stop_times = numpy.array([self.spiketrains[idx].t_stop for idx in self.id_list]) 475 543 self.t_stop = numpy.max(stop_times) 476 print "Warning, t_stop is infered from the data : %f" %self.t_stop544 logging.debug("Warning, t_stop is infered from the data : %f" %self.t_stop) 477 545 for id in self.spiketrains.keys(): 478 546 self.spiketrains[id].t_stop = self.t_stop … … 510 578 def __labels__(self, subplot, xlabel, ylabel): 511 579 if hasattr(subplot, 'xlabel'): 512 subplot.xlabel(xlabel , size="large")513 subplot.ylabel(ylabel , size="large")514 else: 515 subplot.set_xlabel(xlabel , size="large")516 subplot.set_ylabel(ylabel , size="large")580 subplot.xlabel(xlabel) 581 subplot.ylabel(ylabel) 582 else: 583 subplot.set_xlabel(xlabel) 584 subplot.set_ylabel(ylabel) 517 585 518 586 def append(self, id, spktrain): … … 530 598 self.id_list.append(id) 531 599 self.t_start = min(self.t_start, spktrain.t_start) or spktrain.t_start # in case self.t_start is None 532 self.t_stop = max(self.t_stop, spktrain.t_stop)600 self.t_stop = max(self.t_stop, spktrain.t_stop) 533 601 534 602 def get_time_parameters(self): … … 578 646 579 647 580 def id subSpikeList(self, id_list):648 def id_slice(self, id_list): 581 649 """ 582 650 Generate a new SpikeList truncated from a particular sublist of cells. The … … 599 667 return new_SpkList 600 668 601 def time subSpikeList(self, t_start, t_stop):669 def time_slice(self, t_start, t_stop): 602 670 """ 603 671 Generate a new SpikeList truncated from particular time boundaries … … 608 676 new_SpkList = SpikeList([], [], self.dt, t_start, t_stop) 609 677 for id in self.id_list: 610 new_SpkList.append(id, self.spiketrains[id]. subSpikeTrain(t_start, t_stop))678 new_SpkList.append(id, self.spiketrains[id].time_slice(t_start, t_stop)) 611 679 new_SpkList.__calc_startstop() 612 680 return new_SpkList … … 647 715 values, xaxis = numpy.histogram(isis, bins=bins, normed=True) 648 716 subplot = self.__getdisplay__(display) 649 if not subplot :717 if not subplot or not ENABLE_PLOTS: 650 718 return values, xaxis 651 719 else: … … 688 756 values, xaxis = numpy.histogram(cvs, bins=bins, normed=True) 689 757 subplot = self.__getdisplay__(display) 690 if not subplot :758 if not subplot or not ENABLE_PLOTS: 691 759 return values, xaxis 692 760 else: … … 742 810 rates = self.mean_rates() 743 811 subplot = self.__getdisplay__(display) 744 if not subplot :812 if not subplot or not ENABLE_PLOTS: 745 813 return rates 746 814 else: … … 767 835 else: 768 836 nbins = numpy.ceil((self.t_stop-self.t_start)/float(time_bin)) 769 spike_hist = numpy.zeros((self.N (), nbins), float)837 spike_hist = numpy.zeros((self.N, nbins), float) 770 838 logging.debug("nbins = %d" % nbins) 771 839 subplot = self.__getdisplay__(display) … … 778 846 print self.spiketrains[id].t_start, self.spiketrains[id].t_stop 779 847 raise 780 if not subplot :848 if not subplot or not ENABLE_PLOTS: 781 849 return spike_hist 782 850 else: … … 784 852 xlabel = "Time (ms)" 785 853 self.__labels__(subplot, xlabel, ylabel) 786 subplot.plot(self.time_axis(time_bin),sum(spike_hist)/self.N (),**kwargs)854 subplot.plot(self.time_axis(time_bin),sum(spike_hist)/self.N,**kwargs) 787 855 pylab.draw() 788 856 … … 840 908 841 909 842 def activity_map(self, dims, t_start=None, t_stop=None, bounds=None, display=False):910 def activity_map(self, dims, t_start=None, t_stop=None, display=False, kwargs={}): 843 911 """ 844 912 Generate a 2D map of the activity averaged between t_start and t_stop. … … 857 925 """ 858 926 subplot = self.__getdisplay__(display) 927 928 if t_start == None: t_start = self.t_start 929 if t_stop == None: t_stop = self.t_stop 930 spklist = self.time_slice(t_start, t_stop) 931 859 932 if isinstance(dims, tuple) or isinstance(dims, list): 860 933 activity_map = numpy.zeros(dims,float) 861 rates = s elf.mean_rates()862 for id in s elf.id_list:863 position = s elf.id2position(id, dims)934 rates = spklist.mean_rates() 935 for id in spklist.id_list: 936 position = spklist.id2position(id, dims) 864 937 activity_map[position] = rates[id] 865 if not subplot :938 if not subplot or not ENABLE_PLOTS: 866 939 return activity_map 867 940 else: 868 subplot.imshow(activity_map, interpolation='bicubic')941 subplot.imshow(activity_map, **kwargs) 869 942 subplot.colorbar() 870 subplot.show() 871 if bounds is not None: 872 subplot.clim(bounds) 943 pylab.draw() 873 944 elif isinstance(dims, numpy.ndarray): 874 if not len(s elf.id_list) == len(dims[0]):945 if not len(spklist.id_list) == len(dims[0]): 875 946 raise Exception("Error, the number of positions does not match the number of cells in the SpikeList") 876 rates = s elf.mean_rates()877 if not subplot :947 rates = spklist.mean_rates() 948 if not subplot or not ENABLE_PLOTS: 878 949 return rates 879 950 else: 880 951 x = dims[0,:] 881 952 y = dims[1,:] 882 subplot.scatter(x,y,c=rates )953 subplot.scatter(x,y,c=rates, **kwargs) 883 954 subplot.colorbar() 884 if bounds is not None: 885 subplot.clim(bounds) 955 886 956 887 957 def pairwise_correlations(self, pairs, time_bin=1., display=False): … … 895 965 raise Exception("Pairs should have the same number of elements") 896 966 nb_pairs = len(pairs[0]) 897 spk1 = self.id subSpikeList(pairs[0])898 spk2 = self.id subSpikeList(pairs[1])967 spk1 = self.id_slice(pairs[0]) 968 spk2 = self.id_slice(pairs[1]) 899 969 hist_1 = spk1.spike_histogram(time_bin) 900 970 hist_2 = spk2.spike_histogram(time_bin) … … 929 999 """ 930 1000 firing_rate = self.firing_rate(time_bin) 931 return numpy.var(sum(firing_rate)/self.N ())1001 return numpy.var(sum(firing_rate)/self.N) 932 1002 933 1003 def mean_rate_covariance(self, SpkList, time_bin): … … 942 1012 raise Exception("Error, both SpikeLists should share common t_start, t_stop and dt") 943 1013 frate_1 = self.firing_rate(time_bin) 944 frate_1 = sum(frate_1)/self.N ()1014 frate_1 = sum(frate_1)/self.N 945 1015 frate_2 = SpkList.firing_rate(time_bin) 946 frate_2 = sum(frate_2)/SpkList.N ()1016 frate_2 = sum(frate_2)/SpkList.N 947 1017 N = len(frate_1) 948 1018 cov = sum(frate_1*frate_2)/N-sum(frate_1)*sum(frate_2)/(N*N) … … 960 1030 if id_list == None: 961 1031 id_list = self.id_list 962 spk = self.id subSpikeList(id_list)1032 spk = self.id_slice(id_list) 963 1033 elif id_list != self.id_list: 964 spk = self.id subSpikeList(id_list)1034 spk = self.id_slice(id_list) 965 1035 id_list = spk.id_list 966 1036 else: 967 spk = self.id subSpikeList(id_list)1037 spk = self.id_slice(id_list) 968 1038 969 1039 if t_start is None: t_start = self.t_start … … 1006 1076 files = [] 1007 1077 while (time < self.t_stop): 1008 subSpkList = self.time subSpikeList(time, time + time_bin)1078 subSpkList = self.time_slice(time, time + time_bin) 1009 1079 activity_map = subSpkList.activity_map(dims, bounds, display=True) 1010 1080 caption = time+time_bin/2

