Changeset 207

Show
Ignore:
Timestamp:
09/22/08 17:03:25 (4 months ago)
Author:
pierre
Message:

Implement some distances for my personal work, the Victor Purpura one and the Kreuz one, for the SpikeLists objects

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/cleanup/src/io.py

    r203 r207  
    1414            raise Exception("The file %s does not exists !" %filename) 
    1515     
     16     
     17    ### Function to load/save data with the pickle package. Much more faster than a simple 
     18    ### plain text file. Useful if you don't care about reading the spike files 
    1619    def pickle_load(self): 
    1720        return cPickle.load(file(self.filename,"r")) 
     
    2023        return cPickle.dump(object, file(filename, "w")) 
    2124     
     25     
     26    ### Function to load/save data in a text format. 
    2227    def txt_load(self, sepchar = "\t", skipchar = "#"): 
    2328        myfile = open(self.filename, "r", DEFAULT_BUFFER_SIZE) 
     
    7984     
    8085    def get_spikelist(self, id_list=None, dt=None, t_start=None, t_stop=None, dims=None, label=None): 
    81          
    8286        # First, we try to see if the data are stored in a pickled way (MUCH FASTER) 
    8387        try : 
     
    9094                logging.debug("dt is infered from the file header") 
    9195                dt = self.header['dt'] 
    92             if (id_list is None) and (('first_id' in self.header) and ('last_id' in self.header)): 
    93                 logging.debug("id_list is infered from the file header") 
    94                 n_cells = int(self.header['last_id']) - int(self.header['first_id']) + 1 
    95                 id_list = n_cells 
    96             else: 
    97                 raise Exception("id_list not provided and cannot be inferred from file header.") 
     96            if (id_list is None): 
     97                if (('first_id' in self.header) and ('last_id' in self.header)): 
     98                    logging.debug("id_list is infered from the file header") 
     99                    n_cells = int(self.header['last_id']) - int(self.header['first_id']) + 1 
     100                    id_list = n_cells 
     101                else: 
     102                    raise Exception("id_list not provided and cannot be inferred from file header.") 
    98103            if dims is None and 'dimensions' in self.header: 
    99104                dims = self.header['dimensions'] 
     
    121126 
    122127 
    123 class TxtAnalogSignalLoader(object): 
     128class AnalogSignalIO(object): 
    124129    """ 
    125130    Convenient object to load txt file and process them in order 
     
    144149        return 0 
    145150     
    146     def get_SpikeList(self, id_list=None, dt=None, t_start=None, t_stop=None, dims=None, label=None): 
     151    def get_AnalogSignal(self, id_list=None, dt=None, t_start=None, t_stop=None, dims=None, label=None): 
    147152        header = self.parse_header() 
    148153         
  • branches/cleanup/src/signals.py

    r202 r207  
    166166         
    167167        Inputs: 
    168             spiketrain     - The SpikeTrain that should be added 
     168            spiketrain - The SpikeTrain that should be added 
    169169         
    170170        Examples: 
     
    394394            self.t_start      = 0.0 
    395395 
     396    def VictorPurpuraDistance(self, spktrain, cost): 
     397        """ 
     398        Function to calculate the Victor-Purpura distance between two spike trains. 
     399        See J. D. Victor and K. P. Purpura, 
     400            Nature and precision of temporal coding in visual cortex: a metric-space 
     401            analysis., 
     402            J Neurophysiol,76(2):1310-1326, 1996 
     403         
     404        Inputs: 
     405            spktrain - the other SpikeTrain 
     406            cost     - The cost parameter. See the paper for more informations 
     407        """ 
     408        nspk_1      = len(self) 
     409        nspk_2      = len(spktrain) 
     410        if cost == 0:  
     411            return abs(nspk_1-nspk_2) 
     412        elif cost > 1e9 : 
     413            return nspk_1+nspk_2 
     414        scr = numpy.zeros((nspk_1+1,nspk_2+1)) 
     415        scr[:,0] = numpy.arange(0,nspk_1+1) 
     416        scr[0,:] = numpy.arange(0,nspk_2+1) 
     417             
     418        if nspk_1 > 0 and nspk_2 > 0: 
     419            for i in xrange(1,nspk_1+1): 
     420                for j in xrange(1,nspk_2+1): 
     421                    scr[i,j] = min(scr[i-1,j]+1,scr[i,j-1]+1) 
     422                    scr[i,j] = min(scr[i,j],scr[i-1,j-1]+cost*abs(self.spike_times[i-1]-spktrain.spike_times[j-1])) 
     423        return scr[nspk_1,nspk_2] 
     424 
     425 
     426    def KreuzDistance(self, spktrain): 
     427        """ 
     428        Function to calculate the Kreuz/Politi distance between two spike trains 
     429        See Kreuz, T.; Haas, J.S.; Morelli, A.; Abarbanel, H.D.I. & Politi,  
     430        A. Measuring spike train synchrony.  
     431        J Neurosci Methods, 2007, 165, 151-161 
     432 
     433        Inputs: 
     434            spktrain - the other SpikeTrain 
     435        """ 
     436        N              = (self.t_stop-self.t_start)/self.dt 
     437        vec_1          = numpy.zeros(N) 
     438        vec_2          = numpy.zeros(N) 
     439        result         = numpy.zeros(N) 
     440        idx_spikes     = self.spike_times/self.dt 
     441        previous_spike = 0 
     442        for spike in idx_spikes: 
     443            vec_1[previous_spike:spike] = (spike-previous_spike)*self.dt 
     444            previous_spike = spike 
     445        vec_1[previous_spike-1:N] = vec_1[previous_spike-2] 
     446        idx_spikes     = spktrain.spike_times/self.dt 
     447        previous_spike = 0 
     448        for spike in idx_spikes: 
     449            vec_2[previous_spike:spike] = (spike-previous_spike)*self.dt 
     450            previous_spike = spike 
     451        vec_2[previous_spike-1:N] = vec_2[previous_spike-2] 
     452        idx = numpy.where(vec_1 <= vec_2)[0] 
     453        result[idx] = vec_1[idx]/vec_2[idx] - 1 
     454        idx = numpy.where(vec_1 > vec_2)[0] 
     455        result[idx] = -(vec_2[idx]/vec_1[idx] -1) 
     456        return numpy.sum(numpy.abs(result)) 
    396457 
    397458    #################################################################### 
     
    746807         
    747808     
    748     def save(self, filename): 
    749         """ 
    750         Save the SpikeList in a text file 
    751          
    752         Inputs: 
    753             filename - name of the file 
    754         """ 
    755         ## Should implement a way of saving the new SpikeList, using io class 
    756         pass 
     809    def save(self, filename, method="text"): 
     810        """ 
     811        Save the SpikeList in a text or binary file 
     812         
     813        Inputs: 
     814            filename - name of the output file 
     815            method   - "text"   -> a classical human readible text file 
     816                       "pickle" -> binary backup, much more faster to load/save,  
     817                                   but no longer human readible 
     818                       "hdf5"   -> a compress an optimized structure, not 
     819                                   implemented yet 
     820        """ 
     821        spike_loader = io.SpikeListIO(filename) 
     822        if method == "pickle": 
     823            spike_loader.save_spikelist_pickle(self, filename) 
     824        if method == "text": 
     825            spike_loader.save_spikelist_txt(self, filename) 
    757826 
    758827 
     
    876945    def mean_rate_std(self, t_start=None, t_stop=None): 
    877946        """ 
    878         Standard deviation of the Mean firing rate averaged accross all SpikeTrains  
     947        Standard deviation of the firing rates accross all SpikeTrains  
    879948        between t_start and t_stop 
    880949 
     
    897966    def mean_rates(self, t_start=None, t_stop=None): 
    898967        """  
    899         Returns a vector of the size of id_list giving the mean rate for each neuron 
     968        Returns a vector of the size of id_list giving the mean firing rate for each neuron 
    900969 
    901970        Inputs: 
     
    11221191 
    11231192 
    1124     def pairwise_cc(self, pairs, time_bin=1., averaged=False, display=False, kwargs={}): 
     1193    def pairwise_cc(self, pairs, spklist=None, time_bin=1., averaged=False, display=False, kwargs={}): 
    11251194        """ 
    11261195        Function to generate an array of cross correlations computed 
     
    11291198        Inputs: 
    11301199            pairs    - Could be an int, and then N random pairs of cells will be selected,  
    1131                        or could be a list of tuple (id cell_1, id cell_2) 
     1200                       or it could be a list of tuple (id cell_1, id cell_2) 
    11321201            time_bin - The time bin used to gather the spikes 
     1202            spklist  - The other SpikeList object where cells should be taken. By default,  
     1203                       if None, this is the one calling the function 
    11331204            averaged - If true, only the averaged CC among all the pairs is returned (less memory needed) 
    11341205            display  - if True, a new figure is created. Could also be a subplot. The averaged 
     
    11411212        if type(pairs) == int: 
    11421213            spk1 = self.id_slice(pairs) 
    1143             spk2 = self.id_slice(pairs) 
     1214            spk2 = spklist.id_slice(pairs) 
    11441215            N    = pairs 
    11451216        else: 
     
    11471218            N      = len(pairs[:,0]) 
    11481219            spk1   = self.id_slice(pairs[:,0]) 
    1149             spk2   = self.id_slice(pairs[:,1]) 
     1220            spk2   = spklist.id_slice(pairs[:,1]) 
    11501221        hist_1 = spk1.spike_histogram(time_bin) 
    11511222        hist_2 = spk2.spike_histogram(time_bin) 
     
    11801251            pylab.draw() 
    11811252 
     1253     
     1254    def VictorPurpuraDistance(self, id_list, spklist=None, cost=0.5): 
     1255        """ 
     1256        Function to calculate the Victor-Purpura distance averaged over N pairs in the SpikeList 
     1257        See J. D. Victor and K. P. Purpura, 
     1258            Nature and precision of temporal coding in visual cortex: a metric-space 
     1259            analysis., 
     1260            J Neurophysiol,76(2):1310-1326, 1996 
     1261         
     1262        Inputs: 
     1263            id_list - Could be an int, and then N random pairs will be selected,  
     1264                      or it could be a list cells ids 
     1265            spklist - The other SpikeList object where cells should be taken. By default,  
     1266                      if None, this is the one calling the function 
     1267            cost    - The cost parameter. See the paper for more informations. BY default, set to 0.5 
     1268 
     1269        """ 
     1270         
     1271        if type(id_list) == int: 
     1272            spk1 = self.id_slice(id_list) 
     1273            spk2 = spklist.id_slice(spk1.id_list) 
     1274            N    = id_list 
     1275        else: 
     1276            N    = len(id_list) 
     1277            spk1 = self.id_slice(id_list) 
     1278            spk2 = spklist.id_slice(id_list) 
     1279         
     1280        distance   = 0. 
     1281         
     1282        for idx in xrange(len(spk1)): 
     1283            distance += spk1[spk1.id_list[idx]].VictorPurpuraDistance(spk2[spk2.id_list[idx]], cost) 
     1284        return distance/N 
     1285     
     1286     
     1287    def KreuzDistance(self, id_list, spklist=None): 
     1288        """ 
     1289        Function to calculate the Kreuz/Politi distance between two spike trains 
     1290        See Kreuz, T.; Haas, J.S.; Morelli, A.; Abarbanel, H.D.I. & Politi,  
     1291        A. Measuring spike train synchrony.  
     1292        J Neurosci Methods, 2007, 165, 151-161 
     1293 
     1294        Inputs: 
     1295            id_list - Could be an int, and then N random pairs will be selected,  
     1296                      or it could be a list cells ids 
     1297            spklist  - The other SpikeList object where cells should be taken. By default,  
     1298                       if None, this is the one calling the function 
     1299        """ 
     1300        if type(id_list) == int: 
     1301            spk1 = self.id_slice(id_list) 
     1302            spk2 = spklist.id_slice(spk1.id_list) 
     1303            N    = id_list 
     1304        else: 
     1305            N    = len(id_list) 
     1306            spk1 = self.id_slice(id_list) 
     1307            spk2 = spklist.id_slice(id_list) 
     1308         
     1309        distance   = 0. 
     1310         
     1311        for idx in xrange(len(spk1)): 
     1312            distance += spk1[spk1.id_list[idx]].KreuzDistance(spk2[spk2.id_list[idx]]) 
     1313        return distance/N 
     1314 
     1315    def mean_rate_variance(self, time_bin): 
     1316        """ 
     1317        Return the standard deviation of the firing rate along time, 
     1318        if events are binned with a time bin. 
     1319         
     1320        Inputs: 
     1321            time_bin - time bin to bin events 
     1322         
     1323        See also 
     1324            mean_rate, mean_rates, mean_rate_covariance, firing_rate 
     1325        """ 
     1326        firing_rate = self.firing_rate(time_bin) 
     1327        return numpy.var(numpy.sum(firing_rate, axis=0)/self.N) 
    11821328 
    11831329    def mean_rate_covariance(self, spikelist, time_bin): 
    11841330        """ 
    1185         Function to extract the covariance of the firing rate along time, 
    1186         if events are binned with a time bin. We need a second SpikeList 
    1187         object with same time parameters to calculate the covariance 
     1331        Return the covariance of the firing rate along time, 
     1332        if events are binned with a time bin. 
     1333         
     1334        Inputs: 
     1335            spikelist - the other spikelist to compute covariance  
     1336            time_bin  - time bin to bin events 
     1337         
     1338        See also 
     1339            mean_rate, mean_rates, mean_rate_variance, firing_rate 
    11881340        """ 
    11891341        if not isinstance(spikelist, SpikeList): 
     
    11931345        frate_1 = self.firing_rate(time_bin) 
    11941346        frate_1 = numpy.sum(frate_1, axis=0)/self.N 
    1195         frate_2 = SpkList.firing_rate(time_bin) 
     1347        frate_2 = spikelist.firing_rate(time_bin) 
    11961348        frate_2 = numpy.sum(frate_2, axis=0)/spikelist.N 
    1197         N       = len(frate_1) 
    1198         cov     = numpy.sum(frate_1*frate_2)/N-numpy.sum(frate_1)*numpy.sum(frate_2)/(N*N) 
     1349        N = len(frate_1) 
     1350        cov = numpy.sum(frate_1*frate_2)/N-numpy.sum(frate_1)*numpy.sum(frate_2)/(N*N) 
    11991351        return cov 
    12001352 
     
    14331585 
    14341586 
     1587 
     1588 
    14351589def load_spikelist(filename, id_list=None, dt = None, t_start=None, t_stop=None, dims=None, label=None): 
    14361590    """ 
     
    14511605 
    14521606    If dims, dt, t_start, t_stop or id_list are None, they will be infered from either the data or from the header. 
    1453     All times are in milliseconds. 
    1454      
    1455     Examples: 
    1456  
    1457     See also 
    1458  
     1607    All times are in milliseconds. The format of the file (text, pickle or hdf5) will be inferred automatically 
    14591608    """ 
    1460  
    1461     spike_loader = io.TxtSpikeListLoader(filename) 
     1609    spike_loader = io.SpikeListIO(filename) 
    14621610    return spike_loader.get_spikelist(id_list, dt, t_start, t_stop, dims, label) 
     1611 
     1612 
     1613 
     1614 
     1615 
     1616 
     1617 
     1618 
     1619 
     1620 
     1621 
     1622 
     1623 
    14631624 
    14641625 
     
    14981659            raise("Incompatible time interval for the creation of the AnalogSignal") 
    14991660 
     1661    def __getslice__(self, i, j): 
     1662        """ 
     1663        Return a sublist of the spike_times vector of the SpikeTrain 
     1664        """ 
     1665        return self.signal[i:j] 
     1666 
     1667    def duration(self): 
     1668        """ 
     1669        Return the duration of the SpikeTrain 
     1670        """ 
     1671        return self.t_stop - self.t_start 
     1672 
    15001673    def __str__(self): 
    15011674        return str(self.signal) 
     
    15091682 
    15101683class AnalogSignalList(object): 
    1511  
     1684    """ 
     1685    AnalogSignalList(signals, id_list, dt=None, t_start=None, t_stop=None) 
     1686     
     1687    Return a AnalogSignalList object which will be a list of AnalogSignal objects. 
     1688 
     1689    Inputs: 
     1690        signals - a list of the AnalogSignal 
     1691        id_list - the list of the ids of all recorded cells (needed for silent cells) 
     1692        dt      - if dt is specified, time values should be floats 
     1693        t_start - begining of the SpikeList, in ms. If None, will be infered from the data 
     1694        t_stop  - end of the SpikeList, in ms. If None, will be infered from the data 
     1695        dims    - dimensions of the recorded population, if not 1D population 
     1696        label   - optionnal name to identify the SpikeList 
     1697     
     1698    dt, t_start and t_stop are shared for all SpikeTrains object within the SpikeList 
     1699     
     1700    Examples: 
     1701        >>> sl = SpikeList(3, [(0, 0.1), (1, 0.1), (0, 0.2)]) 
     1702        >>> type( sl[0] ) 
     1703        >>> <type SpikeTrain> 
     1704     
     1705    See also 
     1706        loadCurrentTraces, loadMembraneTrace, loadConductanceTraces 
     1707 
     1708    """ 
    15121709    def __init__(self, signals, id_list, dt=None, t_start=None, t_stop=None): 
    15131710        self.id_list = id_list 
    1514         self.N = len(id_list) 
     1711        self.N       = len(id_list) 
    15151712        self.t_start = t_start 
    15161713        self.t_stop  = t_stop 
    1517         self.dt = dt 
     1714        self.dt      = dt 
    15181715        self.analog_signals = {} 
    15191716        for id in id_list: 
     
    15421739        else: 
    15431740            raise Exception("No Analog Signals !") 
     1741     
     1742    def __getdisplay__(self,display): 
     1743        """ 
     1744        Return a pylab object with a plot() function to draw the plots. 
     1745         
     1746        Inputs: 
     1747            display - if True, a new figure is created. Otherwise, if display is a 
     1748                      subplot object, this object is returned. 
     1749        """ 
     1750        if display is False: 
     1751            return None 
     1752        elif display is True: 
     1753            pylab.figure() 
     1754            return pylab 
     1755        else: 
     1756            return display 
     1757     
     1758    def __labels__(self, subplot, xlabel, ylabel): 
     1759        """ 
     1760        Function to put some labels on a plot 
     1761         
     1762        Inputs: 
     1763            subplot - the targeted plot 
     1764            xlabel  - a string for the x label 
     1765            ylabel  - a string for the y label 
     1766        """ 
     1767        if hasattr(subplot, 'xlabel'): 
     1768            subplot.xlabel(xlabel) 
     1769            subplot.ylabel(ylabel) 
     1770        else: 
     1771            subplot.set_xlabel(xlabel) 
     1772            subplot.set_ylabel(ylabel) 
    15441773 
    15451774    def __getitem__(self, i):