Changeset 208

Show
Ignore:
Timestamp:
09/23/08 16:06:27 (4 months ago)
Author:
pierre
Message:

Put also all the IO stuff for reading/writing analog signals into the io.py file. Need to developp the tools for such analog signals

Files:

Legend:

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

    r207 r208  
    11import numpy, os, logging, cPickle 
    22DEFAULT_BUFFER_SIZE = 10000 
     3 
     4try: 
     5    import pytable 
     6    ENABLE_HDF5 = True 
     7except ImportError: 
     8    ENABLE_HDF5 = False 
     9 
    310 
    411 
     
    1118    def __init__(self, filename): 
    1219        self.filename = filename 
    13         if not os.path.exists(filename): 
    14             raise Exception("The file %s does not exists !" %filename) 
    15      
    1620     
    1721    ### Function to load/save data with the pickle package. Much more faster than a simple 
    1822    ### plain text file. Useful if you don't care about reading the spike files 
    1923    def pickle_load(self): 
     24        """ 
     25        Try to load a binary format 
     26        """ 
    2027        return cPickle.load(file(self.filename,"r")) 
    2128     
    2229    def pickle_write(self, object, filename): 
     30        """ 
     31        Dump an object to a binary format 
     32        """ 
    2333        return cPickle.dump(object, file(filename, "w")) 
    2434     
     
    2636    ### Function to load/save data in a text format. 
    2737    def txt_load(self, sepchar = "\t", skipchar = "#"): 
     38        """ 
     39        Load a text file and returns a list of data 
     40        """ 
    2841        myfile = open(self.filename, "r", DEFAULT_BUFFER_SIZE) 
    2942        contents = myfile.readlines() 
     
    4659 
    4760class SpikeListIO(object): 
     61    """ 
     62    Convenient object to load txt file and process them in order 
     63    to get a SpikeList object 
     64    """ 
     65    def __init__(self, filename): 
     66        self.filename = filename 
     67        self.data_io  = DataIO(self.filename) 
     68        self.header   = {} 
     69     
     70    def parse_header(self): 
     71        """ 
     72        Read the informations that may be contained in the header of 
     73        the SpikeList object, if saved in a text file 
     74        """ 
     75        f      = open(self.filename, 'r') 
     76        line   = f.readline() 
     77        while line[0] == '#': 
     78            key, value = line[1:].strip().replace(" ","").split("=") 
     79            if key == "dimensions": 
     80                value = value.split(" ") 
     81                try: 
     82                    value.remove('') 
     83                except Exception: 
     84                    pass 
     85                for idx in xrange(len(value)): 
     86                    value[idx] = eval(value[idx]) 
     87                self.header[key] = value 
     88            else: 
     89                self.header[key] = eval(value) 
     90            line = f.readline() 
     91        f.close() 
     92     
     93    def write_header(self, spikelist, filename): 
     94        """ 
     95        Write the header of a SpikeList object into a file 
     96        """ 
     97        f = open(filename,"w") 
     98        f.write("# dimensions = %s\n" % spikelist.dimensions) 
     99        f.write("# first_id = %d\n" % numpy.min(spikelist.id_list+1)) 
     100        f.write("# last_id = %d\n" % numpy.max(spikelist.id_list+1)) 
     101        f.write("# dt = %g\n" % spikelist.dt) 
     102        f.close() 
     103         
     104     
     105    def get_spikelist(self, id_list=None, dt=None, t_start=None, t_stop=None, dims=None): 
     106        """ 
     107        Return the SpikeList object created after reading the file. Extra parameters may 
     108        be used to define the header, if informations are not available in the file 
     109        """ 
     110        # First, we try to see if the data are stored in a pickled way (MUCH FASTER) 
     111        try : 
     112            res = self.data_io.pickle_load() 
     113            return res 
     114        except Exception: 
     115        # Otherwise we try the text mode.... 
     116            self.parse_header() 
     117            if dt is None and 'dt' in self.header: 
     118                logging.debug("dt is infered from the file header") 
     119                dt = self.header['dt'] 
     120            if id_list is None: 
     121                if ('first_id' in self.header) and ('last_id' in self.header): 
     122                    logging.debug("id_list is infered from the file header") 
     123                    n_cells = int(self.header['last_id']) - int(self.header['first_id']) + 1 
     124                    id_list = n_cells 
     125                else: 
     126                    raise Exception("id_list not provided and cannot be inferred from file header.") 
     127            if dims is None and 'dimensions' in self.header: 
     128                dims = self.header['dimensions'] 
     129            if isinstance(id_list, int): # allows to just specify the number of neurons 
     130                id_list = range(id_list) 
     131            from NeuroTools import signals 
     132            return signals.SpikeList(self.data_io.txt_load(), id_list, dt, t_start, t_stop, dims) 
     133 
     134    def save_spikelist_pickle(self, spikelist, filename): 
     135        """ 
     136        Save the SpikeList object into a binary format 
     137        """ 
     138        self.data_io.pickle_write(spikelist, filename) 
     139     
     140    def save_spikelist_txt(self, spikelist, filename): 
     141        """ 
     142        Save the SpikeList into a text format 
     143        """ 
     144        self.write_header(spikelist, filename) 
     145        data = numpy.array(spikelist.convert(format="[times, ids]")) 
     146        data = data.reshape(data.shape[1],data.shape[0]) 
     147        self.data_io.txt_write(data, filename+".tmp") 
     148        os.system("cat %s >> %s" %(filename+".tmp", filename)) 
     149        os.system("rm %s" %(filename+".tmp")) 
     150 
     151 
     152class AnalogSignalIO(object): 
    48153    """ 
    49154    Convenient object to load txt file and process them in order 
     
    73178            line = f.readline() 
    74179        f.close() 
    75      
    76     def write_header(self, spikelist, filename): 
     180 
     181    def write_header(self, analogsignal, filename): 
    77182        f = open(filename,"w") 
    78         f.write("# dimensions = %s\n" % spikelist.dimensions) 
    79         f.write("# first_id = %d\n" % numpy.min(spikelist.id_list)+1) 
    80         f.write("# last_id = %d\n" % numpy.max(spikelist.id_list)+1) 
    81         f.write("# dt = %g\n" % spikelist.dt) 
    82         f.close() 
     183        f.write("# dimensions = %s\n" % analogsignal.dimensions) 
     184        f.write("# first_id = %d\n" % numpy.min(analogsignal.id_list+1)) 
     185        f.write("# last_id = %d\n" % numpy.max(analogsignal.id_list+1)) 
     186        f.write("# dt = %g\n" % analogsignal.dt) 
     187        f.close() 
     188 
     189    def read_header(self, id_list=None, dt=None, t_start=None, t_stop=None, dims=None): 
    83190         
    84      
    85     def get_spikelist(self, id_list=None, dt=None, t_start=None, t_stop=None, dims=None, label=None): 
    86         # First, we try to see if the data are stored in a pickled way (MUCH FASTER) 
    87         try : 
    88             res = self.data_io.pickle_load() 
    89             return res 
    90         except Exception: 
    91         # Otherwise we try the text mode.... 
    92             self.parse_header() 
    93             if dt is None and 'dt' in self.header: 
    94                 logging.debug("dt is infered from the file header") 
    95                 dt = self.header['dt'] 
    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.") 
    103             if dims is None and 'dimensions' in self.header: 
    104                 dims = self.header['dimensions'] 
    105             if label is None: 
    106                 label = self.data_io.filename 
    107             if isinstance(id_list, int): # allows to just specify the number of neurons 
    108                 id_list = range(id_list) 
    109             from NeuroTools import signals 
    110             return signals.SpikeList(self.data_io.txt_load(), id_list, dt, t_start, t_stop, dims, label) 
    111  
    112     def save_spikelist_pickle(self, spikelist, filename): 
    113         self.data_io.pickle_write(spikelist, filename) 
    114      
    115     def save_spikelist_txt(self, spikelist, filename): 
    116         self.write_header(spikelist, filename) 
    117         data = numpy.array(spikelist.convert(format="[times, ids]")) 
    118         data = data.reshape(data.shape[1],data.shape[0]) 
     191        self.parse_header() 
     192        if dt is None and 'dt' in self.header: 
     193            logging.debug("dt is infered from the file header") 
     194            dt = self.header['dt'] 
     195        else: 
     196            raise Exception("dt must be defined for creation of an AnalogSignal") 
     197 
     198        if id_list is None: 
     199            if ('first_id' in self.header) and ('last_id' in self.header): 
     200                logging.debug("id_list is infered from the file header") 
     201                n_cells = int(self.header['last_id']) - int(self.header['first_id']) + 1 
     202                id_list = n_cells 
     203            else: 
     204                raise Exception("id_list not provided and cannot be inferred from file header.") 
     205     
     206        if dims is None and 'dimensions' in self.header: 
     207            dims = self.header['dimensions'] 
     208 
     209        if isinstance(id_list, int): # allows to just specify the number of neurons 
     210            id_list = range(id_list) 
     211 
     212        return [id_list, dt, t_start, t_stop, dims] 
     213 
     214    def get_vmlist(self, id_list=None, dt=None, t_start=None, t_stop=None, dims=None): 
     215        from NeuroTools import signals 
     216        try: 
     217            res = self.data_io.pickle_load() 
     218            return res 
     219        except Exception: 
     220            d = self.read_header(id_list, dt, t_start, t_stop, dims)  
     221            return signals.VmList(self.data_io.txt_load(), d[0], d[1], d[2], d[3], d[4]) 
     222 
     223    def get_conductancelist(self, id_list=None, dt=None, t_start=None, t_stop=None, dims=None): 
     224        from NeuroTools import signals 
     225        try: 
     226            res = self.data_io.pickle_load() 
     227            return res 
     228        except Exception: 
     229            d = self.read_header(id_list, dt, t_start, t_stop, dims)  
     230            return signals.ConductanceList(self.data_io.txt_load(), d[0], d[1], d[2], d[3], d[4]) 
     231 
     232    def get_currentlist(self, id_list=None, dt=None, t_start=None, t_stop=None, dims=None): 
     233        from NeuroTools import signals 
     234        try: 
     235            res = self.data_io.pickle_load() 
     236            return res 
     237        except Exception: 
     238            d = self.read_header(id_list, dt, t_start, t_stop, dims)  
     239            return signals.CurrentList(self.data_io.txt_load(), d[0], d[1], d[2], d[3], d[4]) 
     240 
     241    def save_analogsignal_pickle(self, analogsignal, filename): 
     242        """ 
     243        Save the AnalogSignal object into a binary format 
     244        """ 
     245        self.data_io.pickle_write(analogsignal, filename) 
     246     
     247    def save_analogsignal_txt(self, analogsignal, filename): 
     248        """ 
     249        Save the AnalogSignal into a text format 
     250        """ 
     251        self.write_header(analogsignal, filename) 
     252        ###data = test 
    119253        self.data_io.txt_write(data, filename+".tmp") 
    120254        os.system("cat %s >> %s" %(filename+".tmp", filename)) 
    121255        os.system("rm %s" %(filename+".tmp")) 
    122256 
    123 #class HDF5DataLoader(object): 
    124 #class HDF5SpikeListLoader(object): 
    125  
    126  
    127  
    128 class AnalogSignalIO(object): 
    129     """ 
    130     Convenient object to load txt file and process them in order 
    131     to get a SpikeList object 
    132     """ 
    133     def __init__(self, filename, signal_type): 
    134         self.filename = filename 
    135         self.loader   = TxtDataLoader(self.filename) 
    136      
    137     def parse_header(self): 
    138         cmd = '' 
    139         f   = open(self.filename, 'r') 
    140         for line in f.readlines(): 
    141             if line[0] == '#': 
    142                 cmd += line[1:].strip() + ';' 
    143         f.close() 
    144         header = {} 
    145         exec cmd in None, header 
    146         return header 
    147  
    148     def get_dims(self, header): 
    149         return 0 
    150      
    151     def get_AnalogSignal(self, id_list=None, dt=None, t_start=None, t_stop=None, dims=None, label=None): 
    152         header = self.parse_header() 
    153          
    154         if dt is None and 'dt' in header: 
    155             logging.debug("dt is infered from the file header") 
    156             dt = header['dt'] 
    157  
    158         if (id_list is None) and (('first_id' in header) and ('last_id' in header)): 
    159             logging.debug("id_list is infered from the file header") 
    160             n_cells = int(header['last_id']) - int(header['first_id']) + 1 
    161             id_list = n_cells 
    162         else: 
    163             raise Exception("id_list not provided and cannot be inferred from file header.") 
    164      
    165         if dims is None and 'dimensions' in header: 
    166             dims = self.get_dims(header['dimensions']) 
    167          
    168         if label is None: 
    169             label = self.loader.filename 
    170  
    171         if isinstance(id_list, int): # allows to just specify the number of neurons 
    172             id_list = range(id_list) 
    173  
    174         from NeuroTools import signals 
    175         return signals.SpikeList(self.loader.readData(), id_list, dt, t_start, t_stop, dims, label) 
    176  
    177  
    178  
    179257############################################## 
    180258### WORK IN PROGRESS 
     
    184262 
    185263 
    186 def load_conductancetracelist(filename, id_list, dt = None, t_start=None, t_stop=None): 
    187     if isinstance(id_list,int): # allows to just specify the number of neurons 
    188         id_list = range(id_list) 
    189     analog_signals = readFile(filename) 
    190     return ConductanceTraceList(analog_signals, id_list, dt, t_start, t_stop) 
    191  
    192  
    193 def load_membranetracelist(filename, id_list, dt = None, t_start=None, t_stop=None): 
    194     if isinstance(id_list,int): # allows to just specify the number of neurons 
    195         id_list = range(id_list) 
    196     analog_signals = readFile(filename) 
    197     return MembraneTraceList(analog_signals, id_list, dt, t_start, t_stop) 
    198  
    199  
    200 def load_currenttracelist(filename, id_list, dt = None, t_start=None, t_stop=None): 
    201     if isinstance(id_list,int): # allows to just specify the number of neurons 
    202         id_list = range(id_list) 
    203     analog_signals = readFile(filename) 
    204     return CurrentTraceList(analog_signals, id_list, dt, t_start, t_stop) 
  • branches/cleanup/src/signals.py

    r207 r208  
    1010try : 
    1111    import pylab 
    12     ENABLE_PLOTS = True 
     12    ENABLE_PLOTS     = True 
    1313except ImportError: 
    14     ENABLE_PLOTS = False 
    15     print "Warning: pylab not detected, plots will be disabled" 
     14    ENABLE_PLOTS     = False 
     15    MATPLOTLIB_ERROR = """ 
     16    Matplotlib not detected so plots are disabled.  
     17    To turn on plots, please install the Matplotlib package 
     18    """ 
     19    print MATPLOTLIB_ERROR 
    1620 
    1721 
     
    331335        subplot = self.__getdisplay__(display) 
    332336        if not subplot or not ENABLE_PLOTS: 
    333             print "Plots are unfortunately disabled... Please install matplotlib" 
     337            print MATPLOTLIB_ERROR 
    334338            return 
    335339        else: 
     
    574578    ## Constructor and key methods to manipulate the SpikeList objects   ## 
    575579    ####################################################################### 
    576     def __init__(self, spikes, id_list, dt=None, t_start=None, t_stop=None, dims=None, label=''): 
     580    def __init__(self, spikes, id_list, dt=None, t_start=None, t_stop=None, dims=None): 
    577581        """ 
    578582        Constructor of the SpikeList object 
     
    585589        self.t_stop  = t_stop 
    586590        self.dt      = dt 
    587         self.label   = label 
    588591        self.dimensions  = dims 
    589592        self.N           = len(id_list) 
     
    13861389 
    13871390        if not subplot or not ENABLE_PLOTS: 
    1388             print "Plots are unfortunately disabled... Please install matplotlib" 
     1391            print MATPLOTLIB_ERROR 
    13891392        else: 
    13901393            ids, spike_times = spk.convert(format="[ids, times]") 
     
    14181421                              (2, nb_cells) with the x (first line) and y (second line) coordinates of 
    14191422                              the cells 
     1423            bounds          - The common color bounds used during all the movies frame. This is a tuple 
     1424                              of values (min, max), in spikes per frame. 
    14201425            display         - if True, a new figure is created. Could also be a subplot. The averaged 
    14211426                              spike_histogram over the whole population is then plotted 
     
    14271432         
    14281433        Examples: 
    1429             >> spklist.activity_map(0,1000,display=True) 
    1430          
    1431         See also 
    1432             activity_movie 
    1433         """ 
    1434         time  = self.t_start 
    1435         files = [] 
    1436         while (time < self.t_stop): 
    1437             subSpkList = self.time_slice(time, time + time_bin) 
    1438             activity_map = subSpkList.activity_map(dims, bounds, display=True) 
    1439             caption = time+time_bin/2 
    1440             pylab.title("Time = %g ms" %caption) 
    1441             fname = "_tmp_%g.jpg" %caption 
    1442             print " Saving Frame", fname 
    1443             pylab.savefig(fname) 
    1444             pylab.close() 
    1445             files.append(fname) 
    1446             time += time_bin 
    1447         print 'Making movie %s - this make take a while' %output 
    1448         command = "mencoder 'mf://_tmp_*.jpg' -mf type=jpg:fps=%d -ovc lavc -lavcopts vcodec=wmv2 -oac copy -o %s" %(fps,output) 
    1449         print command 
    1450         os.system(command) 
    1451         ## cleanup 
    1452         print "Clean up...." 
    1453         for fname in files: os.remove(fname) 
    1454     #clim(bounds[0],bounds[1]) 
    1455     #count = 0 
    1456     #manager = get_current_fig_manager() 
    1457      
    1458     #while (t < t_stop): 
    1459         #for idx in xrange(len(spk)): 
    1460             #activity_maps[idx] = zeros((N,N)) 
    1461             #tmp_idx = idefix[idx] 
    1462             #while((time[idx][tmp_idx] < t + dt) and (tmp_idx < len(position[idx])-1)): 
    1463                 #activity_maps[idx][tuple(position[idx][tmp_idx])] = activity_maps[idx][tuple(position[idx][tmp_idx])] + 1 
    1464                 #tmp_idx += 1 
    1465             #idefix[idx] = tmp_idx 
    1466             #im[idx].set_array(activity_maps[idx]) 
    1467         ##title("time = %d ms" %t) 
    1468         #manager.canvas.draw() 
    1469         #clim(bounds[0],bounds[1]) 
    1470         #fname = "_tmp_spikes_%05d.png" %count 
    1471         #print " Saving Frame", fname 
    1472         #savefig(fname) 
    1473         #files.append(fname) 
    1474         #t += dt 
    1475         #count += 1 
    1476  
     1434            >> spklist.activity_movie(10,0,1000,bounds=(0,5),display=subplot(221),output="test.mpg") 
     1435         
     1436        See also 
     1437            activity_map 
     1438        """ 
     1439        subplot = self.__getdisplay__(display) 
     1440        if t_start is None: t_start = spk.t_start 
     1441        if t_stop is None:  t_stop  = spk.t_stop 
     1442        if not subplot or not ENABLE_PLOTS: 
     1443            print MATPLOTLIB_ERROR 
     1444        else: 
     1445            clim(bounds[0],bounds[1]) 
     1446            count     = 0 
     1447            manager   = get_current_fig_manager() 
     1448            t         = t_start 
     1449            if t_start != spk.t_start or t_stop != spk.t_stop: 
     1450                spk   = spk.time_slice(t_start, t_stop) 
     1451            else: 
     1452                spk   = self 
     1453            time, pos = spk.convert("times, ids") 
     1454            # We sort the spikes to allow faster process later 
     1455            idx       = time.ravel().argsort() 
     1456            time      = time[idx] 
     1457            pos       = pos[idx] 
     1458            if float_positions is None: 
     1459                if self.dimensions is None: 
     1460                    raise Exception("Dimensions of the population are not defined ! Set spikelist.dims") 
     1461            while (t < t_stop): 
     1462                activity_maps = zeros(spk.dimensions) 
     1463                while (time[count] < t + time_bin): 
     1464                    addr = spk.id2position(pos[idx]) 
     1465                    activity_maps[addr] = activity_maps[addr] + 1 
     1466                    count += 1 
     1467                im.set_array(activity_maps) 
     1468                title("time = %d ms" %t) 
     1469                manager.canvas.draw() 
     1470                clim(bounds[0],bounds[1]) 
     1471                fname = "_tmp_spikes_%05d.png" %count 
     1472                print " Saving Frame", fname 
     1473                savefig(fname) 
     1474                files.append(fname) 
     1475                t     += dt 
     1476                count += 1 
     1477            print 'Making movie %s - this make take a while' %output 
     1478            command = "mencoder 'mf://_tmp_*.jpg' -mf type=jpg:fps=%d -ovc lavc -lavcopts vcodec=wmv2 -oac copy -o %s" %(fps,output) 
     1479            print command 
     1480            os.system(command) 
     1481            ## cleanup 
     1482            print "Clean up...." 
     1483            for fname in files: os.remove(fname) 
     1484             
    14771485 
    14781486    #################################################################### 
     
    15871595 
    15881596 
    1589 def load_spikelist(filename, id_list=None, dt = None, t_start=None, t_stop=None, dims=None, label=None): 
     1597class AnalogSignal(object): 
     1598    """ 
     1599    AnalogSignal(signal, dt, t_start=None, t_stop=None) 
     1600     
     1601    Return a AnalogSignal object which will be a analog signal trace 
     1602 
     1603    Inputs: 
     1604        signal  - the vector with the data of the AnalogSignal 
     1605        dt      - the time step between two data points of the sampled analog signal 
     1606        t_start - begining of the signal, in ms. If None, will be set to 0 
     1607        t_stop  - end of the SpikeList, in ms. If None, will be infered from the data 
     1608     
     1609    Examples: 
     1610        >>> as = AnalogSignal(range(100), dt=0.1, t_start=0, t_stop=10) 
     1611 
     1612    See also 
     1613        AnalogSignalList, load_currenttraces, load_membranetrace, load_conductancetraces 
     1614 
     1615    """ 
     1616    def __init__(self, signal, dt, t_start=None, t_stop=None): 
     1617 
     1618        self.signal  = numpy.array(signal,float) 
     1619        self.dt      = dt 
     1620        self.t_start = t_start 
     1621        self.t_stop  = t_stop 
     1622 
     1623        # If t_start is not None, we resize the signal keeping only 
     1624        # elements with t >= t_start 
     1625        if self.t_start is not None: 
     1626            self.signal = self.signal[(self.t_start/self.dt):] 
     1627 
     1628        # If t_stop is not None, we resize the signal keeping only 
     1629        # elements with t <= t_stop 
     1630        if self.t_stop is not None: 
     1631            self.signal = self.signal[:(self.t_stop-self.t_start)/self.dt] 
     1632 
     1633        if len(self.signal) > 0: # spike list may be empty 
     1634            if self.t_start is None: 
     1635                self.t_start = 0. 
     1636            if self.t_stop is None: 
     1637                self.t_stop = len(self.signal)*self.dt 
     1638 
     1639        # TODO raise an error if some data is outside [t_start, t_stop] ? 
     1640        #TODO return an exception if self.t_stop < self.t_start (when not empty) 
     1641        if self.t_start >= self.t_stop : 
     1642            raise Exception("Incompatible time interval for the creation of the AnalogSignal") 
     1643 
     1644    def __getslice__(self, i, j): 
     1645        """ 
     1646        Return a sublist of the spike_times vector of the SpikeTrain 
     1647        """ 
     1648        return self.signal[i:j] 
     1649 
     1650    def duration(self): 
     1651        """ 
     1652        Return the duration of the SpikeTrain 
     1653        """ 
     1654        return self.t_stop - self.t_start 
     1655 
     1656    def __str__(self): 
     1657        return str(self.signal) 
     1658 
     1659    def __len__(self): 
     1660        return len(self.signal) 
     1661 
     1662    def time_axis(self): 
     1663        return numpy.arange(self.t_start, self.t_stop, self.dt) 
     1664 
     1665    def time_slice(self, t_start, t_stop): 
     1666        """  
     1667        Return a new AnalogSignal obtained by slicing between t_start and t_stop 
     1668         
     1669        Inputs: 
     1670            t_start - begining of the new SpikeTrain, in ms. 
     1671            t_stop  - end of the new SpikeTrain, in ms. 
     1672 
     1673        """ 
     1674        signal = signal[t_start/self.dt,t_stop/self.dt] 
     1675        return AnalogSignal(signal, self.dt, t_start, t_stop) 
     1676         
     1677 
     1678 
     1679class AnalogSignalList(object): 
     1680    """ 
     1681    AnalogSignalList(signals, id_list, dt=None, t_start=None, t_stop=None) 
     1682     
     1683    Return a AnalogSignalList object which will be a list of AnalogSignal objects. 
     1684 
     1685    Inputs: 
     1686        signals - a list of the AnalogSignals objects 
     1687        id_list - the list of the ids of all recorded cells (needed for silent cells) 
     1688        dt      - if dt is specified, time values should be floats 
     1689        t_start - begining of the SpikeList, in ms. If None, will be infered from the data 
     1690        t_stop  - end of the SpikeList, in ms. If None, will be infered from the data 
     1691        dims    - dimensions of the recorded population, if not 1D population 
     1692        label   - optionnal name to identify the SpikeList 
     1693     
     1694    dt, t_start and t_stop are shared for all SpikeTrains object within the SpikeList 
     1695     
     1696    Examples: 
     1697        >>> sl = SpikeList(3, [(0, 0.1), (1, 0.1), (0, 0.2)]) 
     1698        >>> type( sl[0] ) 
     1699        >>> <type SpikeTrain> 
     1700     
     1701    See also 
     1702        loadCurrentTraces, loadMembraneTrace, loadConductanceTraces 
     1703 
     1704    """ 
     1705    def __init__(self, signals, id_list, dt=None, t_start=None, t_stop=None, dims=None): 
     1706        self.id_list = id_list 
     1707        self.N       = len(id_list) 
     1708        self.t_start = t_start 
     1709        self.t_stop  = t_stop 
     1710        self.dt      = dt 
     1711        self.dimensions     = dims 
     1712        self.analog_signals = {} 
     1713        for id in id_list: 
     1714            self.analog_signals[id] = [] 
     1715        for id,value in signals: 
     1716            self.analog_signals[id].append(value) 
     1717 
     1718        if t_start is None: 
     1719            self.t_start = 0 
     1720 
     1721        # writing as a list of SpikeTrains 
     1722        for id,signal in self.analog_signals.items(): #TODO: handle missing fields 
     1723            self.analog_signals[id] = AnalogSignal(signal, dt=dt, t_start=self.t_start, t_stop=self.t_stop) 
     1724        if t_start is None or t_stop is None: 
     1725            self.__calc_startstop() 
     1726 
     1727 
     1728    def __calc_startstop(self): 
     1729        """ 
     1730        t_start and t_stop are shared for all neurons, so we take min and max values respectively. 
     1731        TO DO : check the t_start and t_stop parameters for a SpikeList. Is it commun to 
     1732        all the spikeTrains within the spikelist or each spikelistes do need its own. 
     1733        """ 
     1734        if len(self) > 0: 
     1735            if self.t_start is None: 
     1736                start_times  = numpy.array([self.analog_signals[idx].t_start for idx in self.id_list]) 
     1737                self.t_start = numpy.min(start_times) 
     1738                logging.debug("Warning, t_start is infered from the data : %f" %self.t_start) 
     1739                for id in self.analog_signals.keys(): 
     1740                    self.analog_signals[id].t_start = self.t_start 
     1741            if self.t_stop is None: 
     1742                stop_times  = numpy.array([self.analog_signals[idx].t_stop for idx in self.id_list]) 
     1743                self.t_stop = numpy.max(stop_times) 
     1744                logging.debug("Warning, t_stop  is infered from the data : %f" %self.t_stop) 
     1745                for id in self.analog_signals.keys(): 
     1746                    self.analog_signals[id].t_stop = self.t_stop 
     1747        else: 
     1748            raise Exception("No Analog Signals !") 
     1749     
     1750    def __getdisplay__(self,display): 
     1751        """ 
     1752        Return a pylab object with a plot() function to draw the plots. 
     1753         
     1754        Inputs: 
     1755            display - if True, a new figure is created. Otherwise, if display is a 
     1756                      subplot object, this object is returned. 
     1757        """ 
     1758        if display is False: 
     1759            return None 
     1760        elif display is True: 
     1761            pylab.figure() 
     1762            return pylab 
     1763        else: 
     1764            return display 
     1765     
     1766    def __labels__(self, subplot, xlabel, ylabel): 
     1767        """ 
     1768        Function to put some labels on a plot 
     1769         
     1770        Inputs: 
     1771            subplot - the targeted plot 
     1772            xlabel  - a string for the x label 
     1773            ylabel  - a string for the y label 
     1774        """ 
     1775        if hasattr(subplot, 'xlabel'): 
     1776            subplot.xlabel(xlabel) 
     1777            subplot.ylabel(ylabel) 
     1778        else: 
     1779            subplot.set_xlabel(xlabel) 
     1780            subplot.set_ylabel(ylabel) 
     1781 
     1782    def __getitem__(self, i): 
     1783        return self.analog_signals[i] 
     1784 
     1785    def __setitem__(self, i, val): 
     1786        assert isinstance(val, SpikeTrain), "An AnalogSignalList object can only contain AnalogSignal objects" 
     1787        self.analog_signals[i] = val 
     1788        self.__calc_startstop() 
     1789 
     1790    def __len__(self): 
     1791        return len(self.analog_signals) 
     1792 
     1793    def __get_id_list(self, sub_list=None): 
     1794        if sub_list == None: 
     1795            return self.id_list 
     1796        if type(sub_list) == int: 
     1797            return numpy.random.permutation(self.id_list)[0:sub_list] 
     1798        if type(sub_list) == list: 
     1799            return sub_list 
     1800 
     1801    def append(self, id, signal): 
     1802        assert isinstance(signal, AnalogSignal), "An AnalogSignalList object can only contain AnalogSignal objects" 
     1803        if id in self.id_list: 
     1804            raise Exception("Id already present in AnalogSignalList.Use setitem instead()") 
     1805        else: 
     1806            self.analog_signals[id] = signal 
     1807            self.id_list.append(id) 
     1808            self.N += 1 
     1809        self.__calc_startstop() 
     1810 
     1811    def time_axis(self): 
     1812        return numpy.arange(self.t_start,self.t_stop,self.dt) 
     1813 
     1814    def id_slice(self, id_list): 
     1815        pass  
     1816     
     1817    def save(self, filename, method="text"): 
     1818        """ 
     1819        Save the AnalogSignal in a text or binary file 
     1820         
     1821        Inputs: 
     1822            filename - name of the output file 
     1823            method   - "text"   -> a classical human readible text file 
     1824                       "pickle" -> binary backup, much more faster to load/save,  
     1825                                   but no longer human readible 
     1826                       "hdf5"   -> a compress an optimized structure, not 
     1827                                   implemented yet 
     1828        """ 
     1829        as_loader = io.AnalogSignalIO(filename) 
     1830        if method == "pickle": 
     1831            as_loader.save_analogsignal_pickle(self, filename) 
     1832        if method == "text": 
     1833            as_loader.save_analogsignal_txt(self, filename) 
     1834         
     1835     
     1836    def time_slice(self, t_start, t_stop): 
     1837        pass 
     1838     
     1839 
     1840 
     1841 
     1842class VmList(AnalogSignalList): 
     1843 
     1844    def plot(self, id_list=None, v_thresh=None, display=True, kwargs={}): 
     1845        subplot   = self.__getdisplay__(display) 
     1846        id_list   = self._AnalogSignalList__get_id_list(id_list) 
     1847        time_axis = self.time_axis()   
     1848        if not subplot or not ENABLE_PLOTS: 
     1849            print MATPLOTLIB_ERROR 
     1850        else: 
     1851            xlabel = "Time (ms)" 
     1852            ylabel = "Membrane Potential (mV)" 
     1853            self.__labels__(subplot, xlabel, ylabel) 
     1854            for id in id_list: 
     1855                to_be_plot = self.analog_signals[id].signal 
     1856                if v_thresh is not None: 
     1857                    to_be_plot = pylab.where(to_be_plot>=v_thresh-0.05,0.0,to_be_plot) 
     1858                subplot.plot(time_axis, to_be_plot, **kwargs) 
     1859                subplot.hold(1) 
     1860            pylab.draw() 
     1861 
     1862 
     1863class CurrentList(AnalogSignalList): 
     1864 
     1865    def plot(self, id_list=None, v_thresh=None, display=True, kwargs={}): 
     1866        subplot   = self.__getdisplay__(display) 
     1867        id_list   = self._AnalogSignalList__get_id_list(id_list) 
     1868        time_axis = self.time_axis()   
     1869        if not subplot or not ENABLE_PLOTS: 
     1870            print MATPLOTLIB_ERROR 
     1871        else: 
     1872            xlabel = "Time (ms)" 
     1873            ylabel = "Current (nA)" 
     1874            self.__labels__(subplot, xlabel, ylabel) 
     1875            for id in id_list: 
     1876                subplot.plot(time_axis, self.analog_signals[id].signal, **kwargs) 
     1877                subplot.hold(1) 
     1878            pylab.draw() 
     1879 
     1880class ConductanceList(AnalogSignalList): 
     1881 
     1882    def plot(self, id_list=None, v_thresh=None, display=True, kwargs={}): 
     1883        subplot   = self.__getdisplay__(display) 
     1884        id_list   = self._AnalogSignalList__get_id_list(id_list) 
     1885        time_axis = self.time_axis()   
     1886        if not subplot or not ENABLE_PLOTS: 
     1887            print MATPLOTLIB_ERROR 
     1888        else: 
     1889            xlabel = "Time (ms)" 
     1890            ylabel = "Conductance (nS)" 
     1891            self.__labels__(subplot, xlabel, ylabel) 
     1892            for id in id_list: 
     1893                subplot.plot(time_axis, self.analog_signals[id].signal, **kwargs) 
     1894                subplot.hold(1) 
     1895            pylab.draw() 
     1896 
     1897 
     1898 
     1899############################################################# 
     1900## Object Loaders. Functions used to create NeuroTools 
     1901## objects from data generated by pyNN (the most simple form 
     1902## supported right now) 
     1903############################################################# 
     1904 
     1905def load_spikelist(filename, id_list=None, dt = None, t_start=None, t_stop=None, dims=None): 
    15901906    """ 
    15911907    Returns a SpikeList object from a file. If the file has been generated by PyNN,  
     
    16081924    """ 
    16091925    spike_loader = io.SpikeListIO(filename) 
    1610     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  
    1624  
    1625  
    1626  
    1627  
    1628  
    1629  
    1630  
    1631 class AnalogSignal(object): 
    1632  
    1633     def __init__(self, signal, dt, t_start=None, t_stop=None): 
    1634  
    1635         self.signal  = numpy.array(signal,float) 
    1636         self.dt      = dt 
    1637         self.t_start = t_start 
    1638         self.t_stop  = t_stop 
    1639  
    1640         # If t_start is not None, we resize the signal keeping only 
    1641         # elements with t >= t_start 
    1642         if self.t_start is not None: 
    1643             self.signal = self.signal[(self.t_start/self.dt):] 
    1644  
    1645         # If t_stop is not None, we resize the signal keeping only 
    1646         # elements with t <= t_stop 
    1647         if self.t_stop is not None: 
    1648             self.signal = self.signal[:(self.t_stop-self.t_start/self.dt)] 
    1649  
    1650         if len(signal) > 0: # spike list may be empty 
    1651             if self.t_start is None: 
    1652                 self.t_start = 0. 
    1653             if self.t_stop is None: 
    1654                 self.t_stop = len(self.signal)*self.dt 
    1655  
    1656         # TODO raise an error if some data is outside [t_start, t_stop] ? 
    1657         #TODO return an exception if self.t_stop < self.t_start (when not empty) 
    1658         if self.t_start >= self.t_stop : 
    1659             raise("Incompatible time interval for the creation of the AnalogSignal") 
    1660  
    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  
    1673     def __str__(self): 
    1674         return str(self.signal) 
    1675  
    1676     def __len__(self): 
    1677         return len(self.signal) 
    1678  
    1679     def time_axis(self): 
    1680         return numpy.arange(self.t_start, self.t_stop, self.dt) 
    1681  
    1682  
    1683 class AnalogSignalList(object): 
     1926    return spike_loader.get_spikelist(id_list, dt, t_start, t_stop, dims) 
     1927 
     1928 
     1929 
     1930def load_conductancelist(filename, id_list=None, dt = None, t_start=None, t_stop=None, dims=None): 
    16841931    """ 
    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  
     1932    Returns a ConductanceList object from a file. If the file has been generated by PyNN,  
     1933    a header should be found with following parameters: 
     1934     ---> dims, dt, id of the first cell, id of the last cell.  
     1935    They must be specified otherwise.  Then the classical PyNN format for text file is: 
     1936     ---> one line per event:  data value, GID 
     1937     
    16891938    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  
     1939        filename - the name of the spike file 
     1940        id_list  - the list of the recorded ids. Can be an int (meaning cells in the range (0,..,N)),  
     1941                   or a list.  
     1942        dims     - if the cells were aranged on a 2/3D grid, a tuple with the dimensions 
     1943        dt       - the discretization step, in ms 
     1944        t_start  - begining of the simulation, in ms. 
     1945        t_stop   - end of the simulation, in ms 
     1946 
     1947    If dims, dt, t_start, t_stop or id_list are None, they will be infered from either the data or from the header. 
     1948    All times are in milliseconds. The format of the file (text, pickle or hdf5) will be inferred automatically 
    17081949    """ 
    1709     def __init__(self, signals, id_list, dt=None, t_start=None, t_stop=None): 
    1710         self.id_list = id_list 
    1711         self.N       = len(id_list) 
    1712         self.t_start = t_start 
    1713         self.t_stop  = t_stop 
    1714         self.dt      = dt 
    1715         self.analog_signals = {} 
    1716         for id in id_list: 
    1717             self.analog_signals[id] = [] 
    1718         for id,value in signals: 
    1719             self.analog_signals[id].append(value) 
    1720  
    1721         # writing as a list of SpikeTrains 
    1722         for id,signal in self.analog_signals.items(): #TODO: handle missing fields 
    1723             self.analog_signals[id] = AnalogSignal(signal, dt=dt, t_start=self.t_start, t_stop=self.t_stop) 
    1724         if t_start is None or t_stop is None: 
    1725             self.__calc_startstop() 
    1726             #self.spiketrains.append( SpikeTrain(spike_array[i_neuron], dt=dt )) 
    1727  
    1728     def __calc_startstop(self): 
    1729         """ 
    1730         t_start and t_stop are shared for all neurons, so we take min and max values respectively. 
    1731         TO DO : check the t_start and t_stop parameters for a SpikeList. Is it commun to 
    1732         all the spikeTrains within the spikelist or each spikelistes do need its own. 
    1733         """ 
    1734         if len(self) > 0: 
    1735             if self.t_start is None: 
    1736                 self.t_start = 0. 
    1737             #if self.t_stop is None: 
    1738             # 
    1739         else: 
    1740             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) 
    1773  
    1774     def __getitem__(self, i): 
    1775         return self.analog_signals[i] 
    1776  
    1777     def __setitem__(self, i, val): 
    1778