Changeset 215

Show
Ignore:
Timestamp:
10/16/08 13:45:00 (3 years ago)
Author:
apdavison
Message:

Merged cleanup branch changes r198:214 into the trunk.

Location:
trunk
Files:
1 removed
7 modified
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/INSTALL

    r148 r215  
    1 NeuroTools Insallation: 
     1NeuroTools Insallation 
     2====================== 
    23 
    34First download the package files: 
    4 svn co https://neuralensemble.kip.uni-heidelberg.de/svn/NeuroTools/trunk NeuroTools 
    5 cd NeuroTools 
    65 
    7 As root 
     6        svn co https://neuralensemble.org/svn/NeuroTools/trunk NeuroTools 
     7        cd NeuroTools 
    88 
    9 $ python setup.py install 
     9Install as root (if you want a global install) 
    1010 
    11 or for those without root access, to a local location, something like: 
     11        $ python setup.py install 
    1212 
    13 # python setup.py install --prefix=$HOME/opt/mystuff 
     13or for those without root access, install to a writable location, something like: 
     14 
     15        # python setup.py install --prefix=$HOME/opt/mystuff 
    1416 
    1517Then you need to add the location:  
    1618 
    17 $HOME/opt/mystuff/lib/python2.4/site-packages/  
     19$HOME/opt/mystuff/lib/python2.5/site-packages/  
    1820 
    1921to your PYTHON_PAH or (in python) your sys.path 
    2022 
    21 Note, here lib is replaced by lib64 on 64bit systems, and python2.4 is 
     23Note, here lib is replaced by lib64 on 64bit systems, and python2.5 is 
    2224(obviously) replaced by your python version. 
    2325 
    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 
     26Developpers 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 
    2731and voila! 
    2832 
  • trunk/README

    r6 r215  
    1 NeuroTools SVN : see https://facets-vm3.kip.uni-heidelberg.de/trac/NeuroTools/wiki 
     1For more info see the NeuroTools trac http://neuralensemble.org/trac/NeuroTools 
  • trunk/examples/single_neuron/simple_single_neuron.py

    r177 r215  
    2323import pyNN.nest2 as sim 
    2424# the link to read SpikeList files with NeuroTools 
    25 from NeuroTools.spikes import loadSpikeList 
     25from NeuroTools.signals import loadSpikeList 
    2626# using parameters utility 
    2727from NeuroTools.parameters import ParameterSet 
  • trunk/src/__init__.py

    r190 r215  
    1 __all__ = ['analysis', 'benchmark', 'parameters', 'plotting', 'sandbox', 'spikes', 'signals', 'stgen', 'utilities'] 
     1__all__ = ['analysis', 'benchmark', 'parameters', 'plotting', 'sandbox', 'signals', 'stgen', 'utilities', 'io'] 
    22 
    33"""from tables import __version__ 
  • trunk/src/analysis.py

    r188 r215  
    99import os, numpy 
    1010 
     11def 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 
    1160 
    12 def record(output, cfilename = 'SpikeTrainPlay.wav', fs=44100, enc = 'pcm26'): 
    13     """ record the 'sound' produced by a neuron. Takes a spike train as the 
    14     output. 
    15  
    16     >>> record(my_spike_train) 
    17  
    18     """ 
    19  
    20  
    21     # from the spike list 
    22     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 ms 
    29  
    30     trace = numpy.convolve(trace, spike, mode='same')#/2.0 
    31     trace /= numpy.abs(trace).max() * 1.1 
    32  
    33     from scikits.audiolab import wavwrite 
    34     wavwrite(trace, cfilename, fs = fs, enc = enc) 
    35  
    36 def play(output): 
    37     """ 
    38     plays a spike list to the audio output 
    39  
    40     play(spike_list) where spike_list is a spike_list object 
    41  
    42     see playing_with_simple_single_neuron.py for a sample use 
    43  
    44     >>> play(my_spike_train) 
    45  
    46     TODO: make it possible to play multiple spike trains in stereo 
    47     """ 
    48  
    49  
    50     from tempfile import mkstemp 
    51     fd, cfilename   = mkstemp('SpikeListPlay.wav') 
    52     try: 
    53         record(output, cfilename) 
    54         import pyaudio 
    55         import wave 
    56  
    57         chunk = 1024 
    58         wf = wave.open(cfilename, 'rb') 
    59         p = pyaudio.PyAudio() 
    60  
    61         # open stream 
    62         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 data 
    69         data = wf.readframes(chunk) 
    70  
    71         # play stream 
    72         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         # finally 
    81         os.remove(cfilename) 
    82  
    83     # Python 2.4 compatibility 
    84     # finally: 
    85     os.remove(cfilename) 
    8661 
    8762def _dict_max(D): 
  • trunk/src/plotting.py

    r186 r215  
    11 
    2 import numpy #, pylab 
    3 import sys 
     2import numpy, pylab, sys 
    43from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas 
    54from matplotlib.figure import Figure 
     
    3837 
    3938 
    40 def raster_plot(spike_list,output=None):# limits of the plot 
    41     import pylab 
    42     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  
    5539def set_frame(ax,boollist,linewidth=2): 
    5640    assert len(boollist) == 4 
     
    6549            if draw: 
    6650                ax.add_line(side) 
     51 
     52 
    6753 
    6854class SimpleMultiplot(object): 
  • trunk/src/signals.py

    r205 r215  
    55""" 
    66 
    7 import numpy 
    8 import os 
     7import numpy, os, logging, re 
     8from NeuroTools import analysis 
     9from NeuroTools import io 
     10 
    911try : 
    1012    import pylab 
    11 except Exception: 
    12     print "Warning: pylab not present" 
    13 from NeuroTools import analysis 
    14 import logging 
     13    ENABLE_PLOTS     = True 
     14except 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 
    1522 
    1623class SpikeTrain(object): 
    1724    """ 
    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. 
    1927 
    2028    Event times are given in a list (sparse representation) in milliseconds. 
    2129 
    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 
    3346    """ 
    34     # TODO in the definition, should a spike train be ordered? 
    35  
    36     # TODO : should we handle different population shapes differently? 
    3747 
    3848    ####################################################################### 
     
    4151    def __init__(self, spike_times, dt=None, t_start=None, t_stop=None): 
    4252        """ 
    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 
    5457 
    5558        """ 
    5659 
    5760        if dt is not None: 
    58             if dt<=0: 
     61            if dt <= 0: 
    5962                raise ValueError("dt must be greater than zero") 
    6063            #self.spike_times *= dt 
    6164 
    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 
    6668        self.spike_times = numpy.array(spike_times, 'float') 
    6769 
     
    6971        # the spikes with t >= t_start 
    7072        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) 
    7574 
    7675        # If t_stop is not None, we resize the spike_train keeping only 
    7776        # the spikes with t <= t_stop 
    7877        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) 
    8483        # Here we deal with the t_start and t_stop values if the SpikeTrain 
    8584        # is empty, with only one element or several elements, if we 
     
    9190        size = len(spike_times) 
    9291        if size == 0: 
    93             if self.t_start is None: 
     92            if self.t_start is None:  
    9493                self.t_start = 0 
    9594            if self.t_stop is None: 
     
    111110 
    112111        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)) 
    114113        if self.t_start < 0: 
    115114            raise ValueError("t_start must not be negative") 
     
    122121    def __len__(self): 
    123122        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) 
    124167 
    125168    def duration(self): 
     169        """ 
     170        Return the duration of the SpikeTrain 
     171        """ 
    126172        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) 
    127196 
    128197    def format(self, relative=False, quantized=False): 
    129198        """ 
    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] 
    133212        """ 
    134213        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: 
    138216            spike_times[1:] = spike_times[1:] - spike_times[:-1] 
    139217 
     
    145223        return spike_times 
    146224 
     225 
     226 
    147227    ####################################################################### 
    148228    ## Analysis methods that can be applied to a SpikeTrain object       ## 
    149229    ####################################################################### 
     230     
    150231    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 
    156245    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 
    168260            idx = numpy.where((self.spike_times >= t_start) & (self.spike_times <= t_stop))[0] 
    169261        return 1000.*len(idx)/(t_stop-t_start) 
    170262 
    171     # Returns the cv of the isi of the SpikeTrain 
    172263    def cv_isi(self): 
    173264        """ 
     265        Return the coefficient of variation of the isis. 
     266         
    174267        cv_isi is the ratio between the standard deviation and the mean of the ISI 
    175  
    176268          The irregularity of individual spike trains is measured by the squared 
    177269        coefficient of variation of the corresponding inter-spike interval (ISI) 
     
    181273        Poisson-type behavior. As a measure for irregularity in the network one 
    182274        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 
    185279        """ 
    186280        isi = self.isi() 
    187         #TODO return an exception if mean.isi= 0 
    188281        if len(isi) > 0: 
    189282            return numpy.std(isi)/numpy.mean(isi) 
     
    192285 
    193286    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        """ 
    195295        isi = self.isi() 
    196296        if len(isi) > 0: 
    197             #firing_rate = self.time_histogram(time_bin,False)       
    198297            fano = numpy.var(isi)/numpy.mean(isi) 
    199298            return fano 
     
    201300            raise Exception("No spikes in the SpikeTrain !") 
    202301 
    203     def time_axis(self, time_bin): 
     302    def time_axis(self, time_bin=10): 
    204303        """ 
    205304        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 
    206317        """ 
    207318        return numpy.arange(self.t_start, self.t_stop, time_bin) 
    208319 
    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={}): 
    210321        """ 
    211322        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) 
    248383        return SpikeTrain(spikes, self.dt, t_start, t_stop) 
    249384 
    250     def time_histogram(self, time_bin , normalized=True): 
     385 
     386    def time_histogram(self, time_bin=10, normalized=True): 
    251387        """ 
    252388        Bin the spikes with the specified bin width. The first and last bins 
    253389        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) 
    263409        if normalized and isinstance(time_bin, int): # what about normalization if time_bin is a sequence? 
    264410            hist *= 1000.0/time_bin 
     
    267413    def relative_times(self): 
    268414        """ 
    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        """ 
    271420        if self.t_start != 0: 
    272421            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    #################################################################### 
    276518    def tuning_curve(self, var_array, normalized=False, method='sum'): 
    277519        """ 
     
    320562        return tuning_curve 
    321563 
     564 
     565    #################################################################### 
     566    ### TOO SPECIFIC METHOD ? 
     567    ### Better documentation 
     568    #################################################################### 
    322569    def frequency_spectrum(self, time_bin): 
    323570        """ 
     
    325572        frequency axis. 
    326573        """ 
    327         hist = self.time_histogram(time_bin, normalized=False) 
     574        hist       = self.time_histogram(time_bin, normalized=False) 
    328575        freq_spect = analysis.simple_frequency_spectrum(hist) 
    329         freq_bin = 1000.0/self.duration() # Hz 
    330         freq_axis = numpy.arange(len(freq_spect)) * freq_bin     
     576        freq_bin   = 1000.0/self.duration() # Hz 
     577        freq_axis  = numpy.arange(len(freq_spect)) * freq_bin     
    331578        return freq_spect, freq_axis     
    332579 
     580 
     581    #################################################################### 
     582    ### TOO SPECIFIC METHOD ? 
     583    ### Better documentation 
     584    #################################################################### 
    333585    def f1f0_ratio(self, time_bin, f_stim): 
    334586        """ 
     
    346598            raise Exception(errmsg) 
    347599        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 
    361602 
    362603class SpikeList(object): 
    363604    """ 
    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_times 
    370     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 
    385626 
    386627    """ 
     
    388629    ## Constructor and key methods to manipulate the SpikeList objects   ## 
    389630    ####################################################################### 
    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         self.dt = dt 
    405         self.label = label 
    406         # transform spikes in a spike array 
     631    def __init__(self, spikes, id_list, dt=None, t_start=None, t_stop=None, dims=None): 
     632        """ 
     633        Constructor of the SpikeList object 
     634 
     635        See also 
     636            SpikeList, loadSpikeList 
     637        """ 
     638        self.t_start     = t_start 
     639        self.t_stop      = t_stop 
     640        self.dt          = dt 
     641        self.dimensions  = dims 
    407642        self.spiketrains = {} 
     643 
    408644        for id in id_list: 
    409645            self.spiketrains[id] = [] 
    410646        for id,time in spikes: 
    411             if id in id_list: #id_list can be a subset of the list of recorded neurons 
     647            if id in self.id_list(): #id_list can be a subset of the list of recorded neurons 
    412648                self.spiketrains[id].append(time) 
    413649 
    414650        # writing as a list of SpikeTrains 
    415651        for id,spikes in self.spiketrains.items(): # 
    416             self.spiketrains[id] = SpikeTrain(spike_times=spikes, dt=self.dt, t_start=self.t_start, t_stop=self.t_stop) 
     652            self.spiketrains[id] = SpikeTrain(spikes, self.dt, self.t_start, self.t_stop) 
     653         
    417654        if len(self) > 0 and (self.t_start is None or self.t_stop is None): 
    418655            self.__calc_startstop() 
    419656 
    420     def N(self): 
    421         return len(self.id_list) 
     657    def id_list(self): 
     658        """  
     659        Return the list of all the cells ids contained in the 
     660        SpikeList object 
     661        """ 
     662        return numpy.array(self.spiketrains.keys()) 
     663 
     664    def copy(self): 
     665        """ 
     666        Return a copy of the SpikeList object 
     667        """ 
     668        # Maybe not optimal, should be optimized 
     669        spklist = SpikeList([], [], self.dt, self.t_start, self.t_stop, self.dimensions) 
     670        for id in self.id_list(): 
     671            spklist.append(id, self.spiketrains[id]) 
     672        return spklist 
    422673 
    423674    def __calc_startstop(self): 
     
    429680        if len(self) > 0: 
    430681            if self.t_start is None: 
    431                 start_times = numpy.array([self.spiketrains[idx].t_start for idx in self.id_list]) 
    432                 self.t_start = start_times.min() 
     682                start_times = numpy.array([self.spiketrains[idx].t_start for idx in self.id_list()]) 
     683                self.t_start = numpy.min(start_times) 
     684                logging.debug("Warning, t_start is infered from the data : %f" %self.t_start) 
    433685                for id in self.spiketrains.keys(): 
    434686                    self.spiketrains[id].t_start = self.t_start 
    435687            if self.t_stop is None: 
    436                 stop_times = numpy.array([self.spiketrains[idx].t_stop for idx in self.id_list]) 
    437                 self.t_stop  = stop_times.max() 
     688                stop_times = numpy.array([self.spiketrains[idx].t_stop for idx in self.id_list()]) 
     689                self.t_stop  = numpy.max(stop_times) 
     690                logging.debug("Warning, t_stop  is infered from the data : %f" %self.t_stop) 
    438691                for id in self.spiketrains.keys(): 
    439692                    self.spiketrains[id].t_stop = self.t_stop 
     
    441694            raise Exception("No SpikeTrains") 
    442695 
    443     def __getitem__(self, i): 
    444         return self.spiketrains[i] 
    445  
    446     def __setitem__(self, i, val): 
    447         assert isinstance(val, SpikeTrain), "A SpikeList object can only contain SpikeTrain objects" 
    448         self.spiketrains[i] = val 
    449         self.id_list.append(i) 
     696    def __getitem__(self, id): 
     697        return self.spiketrains[id] 
     698     
     699    def __getslice__(self, i, j): 
     700        """ 
     701        Return a new SpikeList object with all the ids between i and j 
     702        """ 
     703        ids = numpy.where((self.id_list() > i) and (self.id_list() < j)) 
     704        return self.id_slice(ids) 
     705     
     706    #def __setslice__(self, i, j): 
     707 
     708    def __setitem__(self, id, spktrain): 
     709        assert isinstance(spktrain, SpikeTrain), "A SpikeList object can only contain SpikeTrain objects" 
     710        self.spiketrains[id] = spktrain 
    450711        self.__calc_startstop() 
    451712 
     
    456717        return len(self.spiketrains) 
    457718 
    458     def append(self, id, spiketrain): 
     719    def __sub_id_list(self, sub_list=None): 
     720        if sub_list == None: 
     721            return self.id_list() 
     722        if type(sub_list) == int: 
     723            return numpy.random.permutation(self.id_list())[0:sub_list] 
     724        if type(sub_list) == list: 
     725            return sub_list 
     726     
     727    def __getdisplay__(self,display): 
     728        """ 
     729        Return a pylab object with a plot() function to draw the plots. 
     730         
     731        Inputs: 
     732            display - if True, a new figure is created. Otherwise, if display is a 
     733                      subplot object, this object is returned. 
     734        """ 
     735        if display is False: 
     736            return None 
     737        elif display is True: 
     738            pylab.figure() 
     739            return pylab 
     740        else: 
     741            return display 
     742     
     743    def __labels__(self, subplot, xlabel, ylabel): 
     744        """ 
     745        Function to put some labels on a plot 
     746         
     747        Inputs: 
     748            subplot - the targeted plot 
     749            xlabel  - a string for the x label 
     750            ylabel  - a string for the y label 
     751        """ 
     752        if hasattr(subplot, 'xlabel'): 
     753            subplot.xlabel(xlabel) 
     754            subplot.ylabel(ylabel) 
     755        else: 
     756            subplot.set_xlabel(xlabel) 
     757            subplot.set_ylabel(ylabel) 
     758 
     759    def append(self, id, spktrain): 
    459760        """ 
    460761        Add a SpikeTrain object to the SpikeList 
    461         """ 
    462         assert isinstance(spiketrain, SpikeTrain), "A SpikeList object can only contain SpikeTrain objects" 
    463         if id in self.id_list: 
    464             raise Exception("Id already present in SpikeList.Use setitem instead()") 
    465         else: 
    466             self.spiketrains[id] = spiketrain 
    467             self.id_list.append(id) 
    468         self.t_start = min(self.t_start, spiketrain.t_start) or spiketrain.t_start # in case self.t_start is None 
    469         self.t_stop = max(self.t_stop, spiketrain.t_stop) 
    470  
     762         
     763        Inputs: 
     764            id       - the id of the new cell 
     765            spktrain - the SpikeTrain object representing the new cell 
     766         
     767        The SpikeTrain object is sliced according to the t_start and t_stop times 
     768        of the SpikeLlist object 
     769         
     770        Examples 
     771            >>> st=SpikeTrain(range(0,100,5),0.1,0,100) 
     772            >>> spklist.append(999, st) 
     773            >>> spklist[999] 
     774         
     775        See also 
     776            concatenate, __setitem__ 
     777        """ 
     778        assert isinstance(spktrain, SpikeTrain), "A SpikeList object can only contain SpikeTrain objects" 
     779        if id in self.id_list(): 
     780            raise Exception("id %d already present in SpikeList. Use __setitem__ (spk[id]=...) instead()" %id) 
     781        else: 
     782            self.spiketrains[id] = spktrain.time_slice(self.t_start, self.t_stop) 
     783             
    471784    def get_time_parameters(self): 
    472785        """ 
    473         Returns the time parameters of the SpikeList (t_start, t_stop, dt) 
     786        Return the time parameters of the SpikeList (t_start, t_stop, dt) 
    474787        """ 
    475788        return (self.t_start, self.t_stop, self.dt) 
    476789 
    477     # Same as for the SpikeTrain object 
    478790    def time_axis(self, time_bin): 
     791        """ 
     792        Return a time axis between t_start and t_stop according to a time_bin 
     793         
     794        Inputs: 
     795            time_bin - the bin width 
     796         
     797        See also 
     798            spike_histogram 
     799        """ 
    479800        return numpy.arange(self.t_start, self.t_stop, time_bin) 
    480801 
    481     def concatenate(self, SpikeList_list): 
    482         """ 
    483         Concatenation of a list of SpikeLists to the current SpikeList 
    484         """ 
     802    def concatenate(self, spklists): 
     803        """ 
     804        Concatenation of SpikeLists to the current SpikeList. 
     805         
     806        Inputs: 
     807            spklists - could be a single SpikeList or a list of SpikeLists 
     808         
     809        The concatenated SpikeLists must have similar (t_start, t_stop, dt), and 
     810        they can't shared similar cells. All their ids have to be different. 
     811         
     812        See also 
     813            append, merge, __setitem__ 
     814        """ 
     815        if isinstance(spklists, SpikeList): 
     816            spklists = [spklists] 
    485817        # We check that Spike Lists have similar time_axis 
    486         sl_= SpikeList_list[0] 
    487         for sl in SpikeList_list: 
     818        for sl in spklists: 
    488819            if not sl.get_time_parameters() == self.get_time_parameters(): 
    489820                raise Exception("Spike Lists should have similar time_axis") 
    490         for sl in SpikeList_list: 
    491             for id in sl.id_list: 
     821        for sl in spklists: 
     822            for id in sl.id_list(): 
    492823                self.append(id, sl.spiketrains[id]) 
    493824 
     
    500831        """ 
    501832        for id, spiketrain in spikelist.spiketrains.items(): 
    502             if id in self.id_list: 
     833            if id in self.id_list(): 
    503834                self.spiketrains[id].merge(spiketrain, relative_times) 
    504835            else: 
     
    508839                 
    509840     
    510     def idsubSpikeList(self, id_list): 
    511         """ 
    512         Generate a new SpikeList truncated from a particular sublist of cells 
    513         """ 
    514         # We check what are the elements that are in self.id_list and not in 
    515         # id_list. We remove such elements from the SpikeList 
    516         new_SpkList = SpikeList([], [], self.dt, self.t_start, self.t_stop) 
    517         if isinstance(id_list,int): 
    518             id_list = numpy.random.permutation(self.id_list)[0:id_list] 
     841    def id_slice(self, id_list): 
     842        """ 
     843        Return a new SpikeList obtained by selecting particular ids 
     844         
     845        Inputs: 
     846            id_list - Can be an integer (and then N random cells will be selected) 
     847                      or a sublist of the current ids 
     848         
     849        The new SpikeList inherits the time parameters (t_start, t_stop, dt) 
     850         
     851        Examples: 
     852            >>> spklist.id_list 
     853            >>> [830, 1959, 1005, 416, 1011, 1240, 729, 59, 1138, 259] 
     854            >>> new_spklist = spklist.id_slice(5) 
     855            >>> new_spklist.id_list 
     856            >>> [1011, 729, 1138, 416, 59] 
     857 
     858        See also 
     859            time_slice 
     860        """ 
     861        new_SpkList = SpikeList([], [], self.dt, self.t_start, self.t_stop, self.dimensions) 
     862        id_list = self.__sub_id_list(id_list) 
    519863        for id in id_list: 
    520864            try: 
    521865                new_SpkList.append(id, self.spiketrains[id]) 
    522866            except Exception: 
    523                 print "Item %s is not in the source SpikeList" %id 
     867                print "id %d is not in the source SpikeList" %id 
    524868        return new_SpkList 
    525869 
    526     def timesubSpikeList(self, t_start, t_stop): 
    527         """ 
    528         Generate a new SpikeList truncated from particular time boundaries 
    529         returns a new SpikeList 
    530  
    531         """ 
    532         new_SpkList = SpikeList([], [], self.dt, t_start, t_stop) 
    533         for id in self.id_list: 
    534             new_SpkList.append(id, self.spiketrains[id].subSpikeTrain(t_start, t_stop)) 
     870    def time_slice(self, t_start, t_stop): 
     871        """ 
     872        Return a new SpikeList obtained by slicing between t_start and t_stop 
     873         
     874        Inputs: 
     875            t_start - begining of the new SpikeTrain, in ms. 
     876            t_stop  - end of the new SpikeTrain, in ms. 
     877         
     878        See also 
     879            id_slice 
     880        """ 
     881        new_SpkList = SpikeList([], [], self.dt, t_start, t_stop, self.dimensions) 
     882        for id in self.id_list(): 
     883            new_SpkList.append(id, self.spiketrains[id].time_slice(t_start, t_stop)) 
    535884        new_SpkList.__calc_startstop() 
    536885        return new_SpkList 
     886     
     887    def add_offset(self, offset): 
     888        """ 
     889        Add an offset to the whole SpikeList object. t_start and t_stop are 
     890        shifted from offset, so does all the SpikeTrain. 
     891          
     892        Inputs: 
     893            offset - the time offset, in ms 
     894         
     895        Examples: 
     896            >>>spklist.t_start 
     897            >>> 1000 
     898            >>>spklist.add_offset(50) 
     899            >>>spklist.t_start 
     900            >>> 1050 
     901        """ 
     902        self.t_start += offset 
     903        self.t_stop  += offset 
     904        for id in self.id_list(): 
     905            self.spiketrains[id].add_offset(offset) 
     906     
     907    def first_spike_time(self): 
     908        """ 
     909        Get the time of the first real spike in the SpikeList 
     910        """ 
     911        first_spike = self.t_stop 
     912        is_empty    = True 
     913        for id in self.id_list(): 
     914            if len(self.spiketrains[id]) > 0: 
     915                is_empty = False 
     916                if self.spiketrains[id].spike_times[0] < first_spike: 
     917                    first_spike = self.spiketrains[id].spike_times[0] 
     918        if is_empty: 
     919            raise Exception("No spikes can be found in the SpikeList object !") 
     920        else: 
     921            return first_spike 
     922     
     923    def last_spike_time(self): 
     924        """ 
     925        Get the time of the last real spike in the SpikeList 
     926        """ 
     927        last_spike = self.t_start 
     928        is_empty    = True 
     929        for id in self.id_list(): 
     930            if len(self.spiketrains[id]) > 0: 
     931                is_empty = False 
     932                if self.spiketrains[id].spike_times[-1] > last_spike: 
     933                    last_spike = self.spiketrains[id].spike_times[-1] 
     934        if is_empty: 
     935            raise Exception("No spikes can be found in the SpikeList object !") 
     936        else: 
     937            return last_spike 
     938     
     939     
     940    def select_ids(self, criteria=None): 
     941        """ 
     942        Return the list of all the cells in the SpikeList that will match the criteria 
     943        expressed with the following syntax.  
     944         
     945        Inputs :  
     946            criteria - a string that can be evaluated on a SpikeTrain object, where the  
     947                       SpikeTrain should be named ``cell''. 
     948         
     949        Exemples: 
     950            >>> spklist.select_ids("cell.mean_rate() > 0") (all the active cells) 
     951            >>> spklist.select_ids("cell.mean_rate() == 0") (all the silent cells) 
     952            >>> spklist.select_ids("len(cell.spiketimes) > 10") 
     953            >>> spklist.select_ids("mean(cell.isi()) < 1") 
     954        """ 
     955        selected_ids = [] 
     956        for id in self.id_list(): 
     957            cell = self.spiketrains[id] 
     958            if eval(criteria): 
     959                selected_ids.append(id) 
     960        return selected_ids 
     961 
     962     
     963    def save(self, filename, method="text"): 
     964        """ 
     965        Save the SpikeList in a text or binary file 
     966         
     967        Inputs: 
     968            filename - name of the output file 
     969            method   - "text"   -> a classical human readible text file 
     970                       "pickle" -> binary backup, much more faster to load/save,  
     971                                   but no longer human readible 
     972                       "hdf5"   -> a compress an optimized structure, not 
     973                                   implemented yet 
     974        """ 
     975        spike_loader = io.SpikeListIO(filename) 
     976        if method == "pickle": 
     977            spike_loader.save_spikelist_pickle(self, filename) 
     978        if method == "text": 
     979            spike_loader.save_spikelist_txt(self, filename) 
    537980 
    538981 
     
    542985 
    543986     
    544     def isi(self, nbins=100, display=False): 
     987    def isi(self): 
    545988        """ 
    546989        Return the list of all the isi vectors for all the SpikeTrains objects 
    547         within the SpikeList. If display is True, then it plots the distribution 
    548         of the ISI 
     990        within the SpikeList. 
     991         
     992        See also: 
     993            isi_hist 
    549994        """ 
    550995        isis = [] 
    551         for idx,id in enumerate(self.id_list): 
     996        for id in self.id_list(): 
    552997            isis.append(self.spiketrains[id].isi()) 
    553         if not display: 
    554             return isis 
    555         else: 
    556             ISI = numpy.array([]) 
    557             for idx in xrange(self.N()): 
    558                 ISI = numpy.concatenate((ISI,isis[idx])) 
    559             values, xaxis = numpy.histogram(ISI, nbins, normed=1) 
    560             pylab.figure() 
    561             pylab.plot(xaxis, values) 
    562             pylab.xlabel("Inter Spike Interval (ms)", size="x-large") 
    563             pylab.ylabel("% of Neurons", size="x-large") 
    564  
    565     def isi_hist(self, bins): 
    566         """Return the histogram of the ISI. 
    567          
    568         bins may either be an integer, giving the number of bins (between the 
    569         min and max of the data) or a list/array containing the lower edges of 
    570         the bins. 
    571          
    572         Returns a tuple, (histogram values, bin edges) 
    573         """ 
    574         isis = numpy.concatenate(self.isi()) 
    575         return numpy.histogram(isis, bins=bins) 
    576  
    577      
    578     def cv_isi(self, nbins=100, display=False): 
     998        return isis 
     999 
     1000 
     1001    def isi_hist(self, bins=50, display=False, kwargs={}): 
     1002        """ 
     1003        Return the histogram of the ISI. 
     1004         
     1005        Inputs: 
     1006            bins    - the number of bins (between the min and max of the data)  
     1007                      or a list/array containing the lower edges of the bins. 
     1008            display - if True, a new figure is created. Could also be a subplot 
     1009            kwargs  - dictionary contening extra parameters that will be sent to the plot  
     1010                      function 
     1011         
     1012        Examples: 
     1013            >>> z = subplot(221) 
     1014            >>> spklist.isi_hist(10, display=z, kwargs={'color':'r'}) 
     1015 
     1016        See also: 
     1017            isi 
     1018        """ 
     1019        isis          = numpy.concatenate(self.isi()) 
     1020        values, xaxis = numpy.histogram(isis, bins=bins, normed=True) 
     1021        subplot       = self.__getdisplay__(display) 
     1022        if not subplot or not ENABLE_PLOTS: 
     1023            return values, xaxis 
     1024        else: 
     1025            xlabel = "Inter Spike Interval (ms)" 
     1026            ylabel = "% of Neurons" 
     1027            self.__labels__(subplot, xlabel, ylabel) 
     1028            subplot.plot(xaxis, values, **kwargs) 
     1029            pylab.draw() 
     1030 
     1031     
     1032    def cv_isi(self): 
    5791033        """ 
    5801034        Return the list of all the cv coefficients for all the SpikeTrains objects 
    581         within the SpikeList. If display is True, then it plots the distribution 
    582         of the CVs 
     1035        within the SpikeList. 
     1036         
     1037        See also: 
     1038            cv_isi_hist 
    5831039        """ 
    5841040        cvs_isi = [] 
    585         for idx,id in enumerate(self.id_list): 
     1041        for id in self.id_list(): 
    5861042            isi = self.spiketrains[id].isi() 
    5871043            if len(isi) > 1: 
    5881044                cvs_isi.append(numpy.std(isi)/numpy.mean(isi)) 
    589         if not display: 
     1045        if len(cvs_isi) > 0: 
    5901046            return cvs_isi 
    5911047        else: 
    592             CV = numpy.array([]) 
    593             for idx in xrange(len(cvs_isi)): 
    594                 CV = numpy.concatenate((CV,[cvs_isi[idx]])) 
    595             values, xaxis = numpy.histogram(CV, nbins, normed=1) 
    596             pylab.figure() 
    597             pylab.plot(xaxis, values) 
    598             pylab.xlabel("Inter Spike Interval CV", size="x-large") 
    599             pylab.ylabel("% of Neurons", size="x-large") 
    600  
    601     def cv_isi_hist(self, bins): 
    602         cvs = numpy.array(self.cv_isi()) 
    603         return numpy.histogram(cvs, bins=bins) 
    604  
    605     def time_axis(self, time_bin): 
    606         return numpy.arange(self.t_start, self.t_stop, time_bin) 
     1048            raise Exception("No isi can be computed in the SpikeList !") 
     1049 
     1050 
     1051    def cv_isi_hist(self, bins=50, display=False, kwargs={}): 
     1052        """ 
     1053        Return the histogram of the cv coefficients. 
     1054         
     1055        Inputs: 
     1056            bins    - the number of bins (between the min and max of the data)  
     1057                      or a list/array containing the lower edges of the bins. 
     1058            display - if True, a new figure is created. Could also be a subplot 
     1059            kwargs  - dictionary contening extra parameters that will be sent to the plot  
     1060                      function 
     1061         
     1062        Examples: 
     1063            >>> z = subplot(221) 
     1064            >>> spklist.cv_isi_hist(10, display=z, kwargs={'color':'r'}) 
     1065         
     1066        See also: 
     1067            cv_isi 
     1068        """ 
     1069        cvs           = numpy.array(self.cv_isi()) 
     1070        values, xaxis = numpy.histogram(cvs, bins=bins, normed=True) 
     1071        subplot       = self.__getdisplay__(display) 
     1072        if not subplot or not ENABLE_PLOTS: 
     1073            return values, xaxis 
     1074        else: 
     1075            xlabel = "Inter Spike Interval (ms)" 
     1076            ylabel = "% of Neurons" 
     1077            self.__labels__(subplot, xlabel, ylabel) 
     1078            subplot.plot(xaxis, values, **kwargs) 
     1079            pylab.draw() 
     1080 
    6071081 
    6081082    def mean_rate(self, t_start=None, t_stop=None): 
    6091083        """ 
    610         Return the mean firing rate averaged accross all SpikeTrains 
    611  
    612         see mean_rates 
     1084        Return the mean firing rate averaged accross all SpikeTrains between t_start and t_stop. 
     1085         
     1086        Inputs: 
     1087            t_start - begining of the selected area to compute mean_rate, in ms 
     1088            t_stop  - end of the selected area to compute mean_rate, in ms 
     1089         
     1090        If t_start or t_stop are not defined, those of the SpikeList are used 
     1091         
     1092        Examples: 
     1093            >>> spklist.mean_rate() 
     1094            >>> 12.63 
     1095         
     1096        See also 
     1097            mean_rates, mean_rate_std 
    6131098        """ 
    6141099        return numpy.mean(self.mean_rates(t_start, t_stop)) 
    615      
     1100 
     1101 
    6161102    def mean_rate_std(self, t_start=None, t_stop=None): 
    6171103        """ 
    618         Std deviation of the Mean firing rate averaged accross all SpikeTrains 
    619  
    620         see mean_rate 
     1104        Standard deviation of the firing rates accross all SpikeTrains  
     1105        between t_start and t_stop 
     1106 
     1107        Inputs: 
     1108            t_start - begining of the selected area to compute std(mean_rate), in ms 
     1109            t_stop  - end of the selected area to compute std(mean_rate), in ms 
     1110         
     1111        If t_start or t_stop are not defined, those of the SpikeList are used 
     1112         
     1113        Examples: 
     1114            >>> spklist.mean_rate_std() 
     1115            >>> 13.25 
     1116 
     1117        See also 
     1118            mean_rate, mean_rates 
    6211119        """ 
    6221120        return numpy.std(self.mean_rates(t_start, t_stop)) 
    623      
     1121 
     1122 
    6241123    def mean_rates(self, t_start=None, t_stop=None): 
    625         """ returns a vector of the size of id_list giving the mean rate for each neuron 
    626  
    627         see SpikeTrain.mean_rate 
     1124        """  
     1125        Returns a vector of the size of id_list giving the mean firing rate for each neuron 
     1126 
     1127        Inputs: 
     1128            t_start - begining of the selected area to compute std(mean_rate), in ms 
     1129            t_stop  - end of the selected area to compute std(mean_rate), in ms 
     1130         
     1131        If t_start or t_stop are not defined, those of the SpikeList are used 
     1132         
     1133        See also 
     1134            mean_rate, mean_rate_std 
    6281135        """ 
    6291136        rates = [] 
    630         for id in self.id_list: 
     1137        for id in self.id_list(): 
    6311138            rates.append(self.spiketrains[id].mean_rate(t_start, t_stop)) 
    632  
    6331139        return rates 
    6341140     
    635     def rate_distribution(self, nbins=25, normalize=True, display=False): 
     1141     
     1142    def rate_distribution(self, nbins=25, normalize=True, display=False, kwargs={}): 
    6361143        """ 
    6371144        Return a vector with all the mean firing rates for all SpikeTrains. 
    638         If display is True, then it plots the distribution of the rates 
    639         """ 
    640         #rates = numpy.zeros(self.N(), float) 
    641         #for idx,id in enumerate(self.id_list): 
    642         #    rates[idx] = self.spiketrains[id].mean_firing_rate() 
    643         rates = self.mean_rates() 
    644         if not display: 
     1145         
     1146        Inputs: 
     1147            bins    - the number of bins (between the min and max of the data)  
     1148                      or a list/array containing the lower edges of the bins. 
     1149            display - if True, a new figure is created. Could also be a subplot 
     1150            kwargs  - dictionary contening extra parameters that will be sent to the plot  
     1151                      function 
     1152         
     1153        See also 
     1154            mean_rate, mean_rates 
     1155        """ 
     1156        rates   = self.mean_rates() 
     1157        subplot = self.__getdisplay__(display) 
     1158        if not subplot or not ENABLE_PLOTS: 
    6451159            return rates 
    6461160        else: 
    647             values, xaxis = numpy.histogram(rates, nbins, normed=1) 
    648             pylab.plot(xaxis,values) 
    649             pylab.ylabel("% of Neurons", size="x-large") 
    650             pylab.xlabel("Average Firing Rate (Hz)", size="x-large") 
    651  
    652     def spike_histogram(self, time_bin, normalized=False, display=False): 
     1161            values, xaxis = numpy.histogram(rates, nbins, normed=True) 
     1162            xlabel = "Average Firing Rate (Hz)" 
     1163            ylabel = "% of Neurons" 
     1164            self.__labels__(subplot, xlabel, ylabel) 
     1165            subplot.plot(xaxis, values, **kwargs) 
     1166            pylab.draw() 
     1167             
     1168 
     1169 
     1170    def spike_histogram(self, time_bin, normalized=False, display=False, kwargs={}): 
    6531171        """ 
    6541172        Generate an array with all the spike_histograms of all the SpikeTrains 
    655         objects within the SpikeList. If display is True, then it plots the 
    656         mean firing rate of the all population along time 
    657         """ 
    658         if hasattr(time_bin, '__len__'): 
    659             nbins = len(time_bin) 
    660         else: 
    661             nbins = numpy.ceil((self.t_stop-self.t_start)/float(time_bin)) 
    662         spike_hist = numpy.zeros((self.N(), nbins), float) 
    663         logging.debug("nbins = %d" % nbins) 
    664         for idx,id in enumerate(self.id_list): 
    665             try: 
    666                 spike_hist[idx,:] = self.spiketrains[id].time_histogram(time_bin,normalized) 
    667             except ValueError: 
    668                 print spike_hist[idx,:].shape, self.spiketrains[id].time_histogram(time_bin,normalized).shape 
    669                 print nbins, self.t_start, self.t_stop 
    670                 print self.spiketrains[id].t_start, self.spiketrains[id].t_stop 
    671                 raise 
    672         if display: 
    673             pylab.figure() 
    674             pylab.plot(self.time_axis(time_bin),sum(spike_hist)/self.N()) 
    675             pylab.ylabel("Mean Number of Spikes per bin", size="x-large") 
    676             pylab.xlabel("Time (ms)", size="x-large") 
    677         return spike_hist 
    678  
    679     def firing_rate(self, time_bin, display=False): 
    680         """ 
    681         Calculate firing rate traces (in Hz) from arrays of spike times. 
    682  
    683         Spike times and binwidth should are in milliseconds. 
    684         Returns a tuple (list_of_firing_rate_traces,bins) 
    685  
    686         >>> pylab.plot(output[0].time_axis(dt),sum(output.firing_rate(dt))) 
    687         """ 
    688         return self.spike_histogram(time_bin, normalized=True, display=display) 
    689  
    690     # Compute the Fano Factor of the population. Need to be checked 
     1173        objects within the SpikeList. 
     1174         
     1175        Inputs: 
     1176            time_bin   - the time bin used to gather the data 
     1177            normalized - if True, the histogram are in Hz (spikes/second), otherwise they are 
     1178                         in spikes/bin 
     1179            display    - if True, a new figure is created. Could also be a subplot. The averaged 
     1180                         spike_histogram over the whole population is then plotted 
     1181            kwargs     - dictionary contening extra parameters that will be sent to the plot  
     1182                         function 
     1183         
     1184        See also 
     1185            firing_rate, time_axis 
     1186        """ 
     1187        nbins      = self.time_axis(time_bin) 
     1188        N          = len(self) 
     1189        spike_hist = numpy.zeros((N, len(nbins)), float) 
     1190        subplot    = self.__getdisplay__(display) 
     1191        for idx,id in enumerate(self.id_list()): 
     1192            spike_hist[idx,:] = self.spiketrains[id].time_histogram(time_bin, normalized) 
     1193        if not subplot or not ENABLE_PLOTS: 
     1194            return spike_hist 
     1195        else: 
     1196            if normalized: 
     1197                ylabel = "Firing rate (Hz)" 
     1198            else: 
     1199                ylabel = "Spikes per bin" 
     1200            xlabel = "Time (ms)" 
     1201            self.__labels__(subplot, xlabel, ylabel) 
     1202            subplot.plot(self.time_axis(time_bin),numpy.sum(spike_hist, axis=0)/N,**kwargs) 
     1203            pylab.draw() 
     1204             
     1205 
     1206    def firing_rate(self, time_bin, display=False, kwargs={}): 
     1207        """ 
     1208        Generate an array with all the instantaneous firing rates along time (in Hz)  
     1209        of all the SpikeTrains objects within the SpikeList. 
     1210         
     1211        Inputs: 
     1212            time_bin   - the number of bins (between the min and max of the data)  
     1213                         or a list/array containing the lower edges of the bins. 
     1214            display    - if True, a new figure is created. Could also be a subplot. The averaged 
     1215                         spike_histogram over the whole population is then plotted 
     1216            kwargs     - dictionary contening extra parameters that will be sent to the plot  
     1217                         function 
     1218         
     1219        See also 
     1220            spike_histogram, time_axis 
     1221        """ 
     1222        return self.spike_histogram(time_bin, normalized=True, display=display, kwargs=kwargs) 
     1223 
     1224 
    6911225    def fano_factor(self, time_bin): 
     1226        """ 
     1227        Compute the Fano Factor of the population activity. 
     1228         
     1229        Inputs: 
     1230            time_bin   - the number of bins (between the min and max of the data)  
     1231                         or a list/array containing the lower edges of the bins. 
     1232         
     1233        The Fano Factor is computed as the variance of the averaged activity divided by its 
     1234        mean 
     1235         
     1236        See also 
     1237            spike_histogram, firing_rate 
     1238        """ 
    6921239        firing_rate = self.spike_histogram(time_bin) 
    693         firing_rate = sum(firing_rate) 
    694         fano = numpy.var(firing_rate)/numpy.mean(firing_rate) 
     1240        firing_rate = numpy.sum(firing_rate,axis=0) 
     1241        fano        = numpy.var(firing_rate)/numpy.mean(firing_rate) 
    6951242        return fano 
    696      
     1243 
     1244 
    6971245    def fano_factors_isi(self): 
    698         """ returns a list containing the fano factors for each neuron""" 
     1246        """  
     1247        Return a list containing the fano factors for each neuron 
     1248         
     1249        See also 
     1250            isi, isi_cv 
     1251        """ 
    6991252        fano_factors = [] 
    700         for id in self.id_list: 
     1253        for id in self.id_list(): 
    7011254            try: 
    7021255                fano_factors.append(self.spiketrains[id].fano_factor_isi()) 
     
    7071260 
    7081261     
    709     def id2position(self, id, dims): 
    710         """ 
    711         Allow to translate a gid (ranging from 0 to N*M) into 
    712         a position on a N*M grid. dims should be given as a tuple 
    713         (N,M) 
    714         """ 
    715         # Then we translate it in 2D 
    716         if len(dims) == 1: 
     1262    def id2position(self, id): 
     1263        """ 
     1264        Return a position (x,y) from an id if the cells are aranged on a 
     1265        grid of size dims, as defined in the dims attribute of the SpikeList object 
     1266         
     1267        Inputs: 
     1268            id - the id of the cell 
     1269         
     1270        The 'dimensions' attribute of the SpikeList must be defined 
     1271         
     1272        See also 
     1273            activity_map, activity_movie 
     1274        """ 
     1275        if self.dimensions is None: 
     1276            raise Exception("Dimensions of the population are not defined ! Set spikelist.dims") 
     1277        if len(self.dimensions) == 1: 
    7171278            return id 
    718         if len(dims) == 2: 
    719             x = numpy.floor(id/dims[0]) 
    720             y = id % dims[1] 
     1279        if len(self.dimensions) == 2: 
     1280            x = numpy.floor(id/self.dimensions[0]) 
     1281            y = id % self.dimensions[1] 
    7211282            return (x,y) 
    7221283 
    7231284     
    724     def activity_map(self, dims, bounds=None, display=False): 
    725         """ 
    726         Generate a map of the activity during t_start and t_stop. 
    727         If dims is a tuple, then cells are placed on a grid of size 
    728         (N,M), else if dims is an array of size (2,nb_cells) with the 
    729         x (first line) and y (second line) flotting positions of the cells, 
    730         we generate a scatter plot. bounds is a parameters allowing to specify 
    731         the range of the colorbar 
    732         """ 
    733         if isinstance(dims, tuple) or isinstance(dims, list): 
    734             activity_map = numpy.zeros(dims,float) 
    735             rates = self.mean_rates() 
    736             for id in self.id_list: 
    737                 position = self.id2position(id, dims) 
     1285    def activity_map(self, t_start=None, t_stop=None, float_positions=None, display=False, kwargs={}): 
     1286        """ 
     1287        Generate a 2D map of the activity averaged between t_start and t_stop. 
     1288        If t_start and t_stop are not defined, we used those of the SpikeList object 
     1289         
     1290        Inputs: 
     1291            t_start         - if not defined, the one of the SpikeList is used 
     1292            t_stop          - if not defined, the one of the SpikeList is used 
     1293            float_positions - None by default, meaning that the dimensions attribute  
     1294                              of the SpikeList is used to arange the ids on a 2D grid.  
     1295                              Otherwise, if the cells have flotting positions,  
     1296                              float_positions should be an array of size 
     1297                              (2, nb_cells) with the x (first line) and y (second line)  
     1298                              coordinates of the cells 
     1299            display         - if True, a new figure is created. Could also be a subplot.  
     1300                              The averaged spike_histogram over the whole population is  
     1301                              then plotted 
     1302            kwargs          - dictionary contening extra parameters that will be sent  
     1303                              to the plot function 
     1304 
     1305        The 'dimensions' attribute of the SpikeList is used to turn ids into 2d positions. It should 
     1306        therefore be not empty. 
     1307         
     1308        Examples: 
     1309            >> spklist.activity_map(0,1000,display=True) 
     1310         
     1311        See also 
     1312            activity_movie 
     1313        """ 
     1314        subplot = self.__getdisplay__(display) 
     1315         
     1316        if t_start == None:  
     1317            t_start = self.t_start 
     1318        if t_stop  == None:  
     1319            t_stop  = self.t_stop 
     1320        if t_start != self.t_start or t_stop != self.t_stop: 
     1321            spklist = self.time_slice(t_start, t_stop) 
     1322        else: 
     1323            spklist = self 
     1324         
     1325        if float_positions is None: 
     1326            if self.dimensions is None: 
     1327                raise Exception("Dimensions of the population are not defined ! Set spikelist.dims") 
     1328            activity_map = numpy.zeros(self.dimensions, float) 
     1329            rates        = spklist.mean_rates() 
     1330            for id in spklist.id_list(): 
     1331                position = spklist.id2position(id) 
    7381332                activity_map[position] = rates[id] 
    739             if not display: 
     1333            if not subplot or not ENABLE_PLOTS: 
    7401334                return activity_map 
    7411335            else: 
    742                 pylab.figure() 
    743                 pylab.imshow(activity_map,interpolation='bicubic') 
    744                 pylab.colorbar() 
    745                 pylab.show() 
    746                 if bounds is not None: 
    747                     pylab.clim(bounds) 
    748         elif isinstance(dims, numpy.ndarray): 
    749             if not len(self.id_list) == len(dims[0]): 
    750                 raise Exception("Error, the number of positions does not match the number of cells in the SpikeList") 
    751             rates = self.mean_rates() 
    752             #for id in self.id_list: 
    753             #    rates.append(self.spiketrains[id].mean_firing_rate()) 
    754             if not display: 
     1336                subplot.imshow(activity_map, **kwargs) 
     1337                subplot.colorbar() 
     1338                pylab.draw() 
     1339        elif isinstance(float_positions, numpy.ndarray): 
     1340            if not len(spklist.id_list) == len(float_positions[0]): 
     1341                raise Exception("Error, the number of flotting positions does not match the number of cells in the SpikeList") 
     1342            rates = spklist.mean_rates() 
     1343            if not subplot or not ENABLE_PLOTS: 
    7551344                return rates 
    7561345            else: 
    757                 x = dims[0,:] 
    758                 y = dims[1,:] 
    759                 pylab.scatter(x,y,c=rates) 
    760                 pylab.colorbar() 
    761                 if bounds is not None: 
    762                     pylab.clim(bounds) 
    763  
    764     def pairwise_correlations(self, pairs, time_bin=1., display=False): 
    765         """ 
    766         Function to generate an array of cross correlation between computed 
    767         between pairs of cells within the SpikeTrains. pairs should be therefore 
    768         a list of (cell_id_1, cell_id_2). If display is True, then if plots the 
    769         averaged cross correlation over all those pairs 
    770         """ 
    771         if len(pairs[0]) != len(pairs[1]): 
    772             raise Exception("Pairs should have the same number of elements") 
    773         nb_pairs = len(pairs[0]) 
    774         spk1 = self.idsubSpikeList(pairs[0]) 
    775         spk2 = self.idsubSpikeList(pairs[1]) 
     1346                x = float_positions[0,:] 
     1347                y = float_positions[1,:] 
     1348                subplot.scatter(x,y,c=rates, **kwargs) 
     1349                subplot.colorbar() 
     1350                pylab.draw() 
     1351 
     1352 
     1353    def pairwise_cc(self, pairs, spklist=None, time_bin=1., averaged=False, display=False, kwargs={}): 
     1354        """ 
     1355        Function to generate an array of cross correlations computed 
     1356        between pairs of cells within the SpikeTrains. 
     1357         
     1358        Inputs: 
     1359            pairs    - Could be an int, and then N random pairs of cells will be selected,  
     1360                       or it could be a list of tuple (id cell_1, id cell_2) 
     1361            time_bin - The time bin used to gather the spikes 
     1362            spklist  - The other SpikeList object where cells should be taken. By default,  
     1363                       if None, this is the one calling the function 
     1364            averaged - If true, only the averaged CC among all the pairs is returned (less memory needed) 
     1365            display  - if True, a new figure is created. Could also be a subplot. The averaged 
     1366                       spike_histogram over the whole population is then plotted 
     1367            kwargs   - dictionary contening extra parameters that will be sent to the plot  
     1368                       function 
     1369        """ 
     1370        subplot = self.__getdisplay__(display) 
     1371         
     1372        if spklist == None: 
     1373            spklist = self 
     1374         
     1375        if type(pairs) == int: 
     1376            spk1 = self.id_slice(pairs) 
     1377            spk2 = spklist.id_slice(pairs) 
     1378            N    = pairs 
     1379        else: 
     1380            pairs  = numpy.array(pairs) 
     1381            N      = len(pairs[:,0]) 
     1382            spk1   = self.id_slice(pairs[:,0]) 
     1383            spk2   = spklist.id_slice(pairs[:,1]) 
    7761384        hist_1 = spk1.spike_histogram(time_bin) 
    7771385        hist_2 = spk2.spike_histogram(time_bin) 
    778         print spk1, spk2 
    7791386        length = 2*len(hist_1[0]) 
    780         results = numpy.zeros((nb_pairs,length), float) 
    781         for idx in xrange(nb_pairs): 
     1387        if not averaged: 
     1388            results = numpy.zeros((nb_pairs,length), float) 
     1389        else: 
     1390            results = numpy.zeros(length, float) 
     1391        for idx in xrange(N): 
    7821392            # We need to avoid empty spike histogram, otherwise the ccf function 
    7831393            # will give a nan vector 
    784             if sum(hist_1[idx]) > 0 and sum(hist_2[idx] > 0): 
    785                 results[idx,:] = ccf(hist_1[idx],hist_2[idx]) 
    786         if (display): 
    787             results = sum(results)/nb_pairs 
    788             pylab.figure() 
    789             xaxis  = time_bin*numpy.arange(-len(results)/2, len(results)/2) 
    790             pylab.plot(xaxis, results) 
    791             pylab.xlabel("Time (ms)", size="x-large") 
    792             pylab.ylabel("Cross Correlation", size="x-large") 
    793         else: 
    794             return results 
     1394            if numpy.sum(hist_1[idx]) > 0 and numpy.sum(hist_2[idx] > 0): 
     1395                if not averaged: 
     1396                    results[idx,:] = analysis.ccf(hist_1[idx],hist_2[idx]) 
     1397                else: 
     1398                    results += analysis.ccf(hist_1[idx],hist_2[idx]) 
     1399        if not subplot or not ENABLE_PLOTS: 
     1400            if not averaged: 
     1401                return results 
     1402            else: 
     1403                return results/N 
     1404        else: 
     1405            if averaged: 
     1406                results = results/N 
     1407            else: 
     1408                results = numpy.sum(results, axis=0)/N 
     1409            xaxis   = time_bin*numpy.arange(-len(results)/2, len(results)/2) 
     1410            xlabel  = "Time (ms)" 
     1411            ylabel  = "Cross Correlation" 
     1412            subplot.plot(xaxis, results) 
     1413            self.__labels__(subplot, xlabel, ylabel) 
     1414            pylab.draw() 
     1415 
     1416 
     1417    def CrossCorrZero(self, pairs, spklist=None, time_bin=1., mode="auto"): 
     1418        #Just the Aertsen Value at 0 delay 
     1419        t_start = float(time_parameters[0]) 
     1420        t_stop  = float(time_parameters[1]) 
     1421         
     1422        spk1 = CutSpikeList(f1, time_parameters) 
     1423        spk2 = CutSpikeList(f2, time_parameters) 
     1424     
     1425        if ((size(spk1)==0) or (size(spk2)==0)): 
     1426            return 0 
     1427         
     1428        if mode == "auto": 
     1429            if (selected_set==None): 
     1430                selected_set = GetCells(spk1) 
     1431            if isinstance(selected_set,int): 
     1432                all_positions = GetCells(spk1) 
     1433                selected_set  = numpy.random.permutation(all_positions)[0:selected_set] 
     1434            spk1 = CutSpikeList2(spk1,selected_set) 
     1435            spk2 = CutSpikeList2(spk2,selected_set) 
     1436            cells_id = sort(selected_set) 
     1437            for idx in xrange(len(spk1[0])): 
     1438                spk1[1][idx] = numpy.where(cells_id == spk1[1][idx])[0] 
     1439            for idx in xrange(len(spk2[0])): 
     1440                spk2[1][idx] = numpy.where(cells_id == spk2[1][idx])[0] 
     1441            nb_neur   = len(selected_set) 
     1442         
     1443        if mode == "cross": 
     1444            # If nothing is entered, we perform the cross correlation between the two 
     1445            # whole spike trains 
     1446            if (selected_set==None): 
     1447                cell_1 = GetCells(spk1) 
     1448                cell_2 = GetCells(spk2) 
     1449                N      = min(len(cell_1),len(cell_2)) 
     1450                cell_1 = cell_1[0:N] 
     1451                cell_2 = cell_2[0:N] 
     1452             
     1453            # If we want to select only X pairs of cells to performs the auto 
     1454            # correlation, we select those random pairs. 
     1455            if isinstance(selected_set,int): 
     1456                N = selected_set 
     1457                all_positions = GetCells(spk1) 
     1458                shuffle       = numpy.random.permutation(all_positions) 
     1459                cell_1        = shuffle[0:N] 
     1460                # If we perform a cross correlation within the same spike file, 
     1461                # we prevent the same neuron to be in the two signals, to have a real 
     1462                # non overlapping cross correlation 
     1463                if not(any(equal(spk1,spk2) == False)): 
     1464                    shuffle = numpy.random.permutation(all_positions) 
     1465                    cell_2  = shuffle[0:N] 
     1466                else: 
     1467                    # Otherwise we don't care... 
     1468                    all_positions = GetCells(spk2) 
     1469                    shuffle = numpy.random.permutation(all_positions) 
     1470                    cell_2  = shuffle[0:N] 
     1471            spk1 = CutSpikeList2(spk1,cell_1) 
     1472            spk2 = CutSpikeList2(spk2,cell_2) 
     1473            cells_id_1 = sort(cell_1) 
     1474            cells_id_2 = sort(cell_2) 
     1475            for count, cell in enumerate(cells_id_1): 
     1476                spk1[1][numpy.where(cell == spk1[1])] = count 
     1477            for count, cell in enumerate(cells_id_2): 
     1478                spk2[1][numpy.where(cell == spk2[1])] = count 
     1479            nb_neur = len(cells_id_1) 
     1480         
     1481         
     1482        num_bins  = int((t_stop-t_start)/time_bin)+1 
     1483        mat_neur1 = numpy.zeros((num_bins,nb_neur)) 
     1484        mat_neur2 = numpy.zeros((num_bins,nb_neur)) 
     1485         
     1486        timespk1 = numpy.array(((spk1[0] - t_start)/time_bin),'int') 
     1487        timespk2 = numpy.array(((spk2[0] - t_start)/time_bin),'int') 
     1488         
     1489        mat_neur1[timespk1,spk1[1]] = 1 
     1490        mat_neur2[timespk2,spk2[1]] = 1 
     1491        Z = float(sum(sum(mat_neur1*mat_neur2))) 
     1492         
     1493        N = float(num_bins*nb_neur) 
     1494        X = float(len(spk1[0])) 
     1495        Y = float(len(spk2[0])) 
     1496         
     1497        X=X/N 
     1498        Y=Y/N 
     1499        Z=Z/N 
     1500         
     1501        return (Z-X*Y)/sqrt((X*(1-X))*(Y*(1-Y))) 
     1502     
     1503    def VictorPurpuraDistance(self, id_list, spklist=None, cost=0.5): 
     1504        """ 
     1505        Function to calculate the Victor-Purpura distance averaged over N pairs in the SpikeList 
     1506        See J. D. Victor and K. P. Purpura, 
     1507            Nature and precision of temporal coding in visual cortex: a metric-space 
     1508            analysis., 
     1509            J Neurophysiol,76(2):1310-1326, 1996 
     1510         
     1511        Inputs: 
     1512            id_list - Could be an int, and then N random pairs will be selected,  
     1513                      or it could be a list cells ids 
     1514            spklist - The other SpikeList object where cells should be taken. By default,  
     1515                      if None, this is the one calling the function 
     1516            cost    - The cost parameter. See the paper for more informations. BY default, set to 0.5 
     1517 
     1518        """ 
     1519        if spklist == None: 
     1520            spklist = self 
     1521         
     1522        if type(id_list) == int: 
     1523            spk1 = self.id_slice(id_list) 
     1524            spk2 = spklist.id_slice(spk1.id_list) 
     1525            N    = id_list 
     1526        else: 
     1527            N    = len(id_list) 
     1528            spk1 = self.id_slice(id_list) 
     1529            spk2 = spklist.id_slice(id_list) 
     1530         
     1531        distance   = 0. 
     1532         
     1533        for idx in xrange(len(spk1)): 
     1534            distance += spk1[spk1.id_list[idx]].VictorPurpuraDistance(spk2[spk2.id_list[idx]], cost) 
     1535        return distance/N 
     1536     
     1537     
     1538    def KreuzDistance(self, id_list, spklist=None): 
     1539        """ 
     1540        Function to calculate the Kreuz/Politi distance between two spike trains 
     1541        See Kreuz, T.; Haas, J.S.; Morelli, A.; Abarbanel, H.D.I. & Politi,  
     1542        A. Measuring spike train synchrony.  
     1543        J Neurosci Methods, 2007, 165, 151-161 
     1544 
     1545        Inputs: 
     1546            id_list - Could be an int, and then N random pairs will be selected,  
     1547                      or it could be a list cells ids 
     1548            spklist  - The other SpikeList object where cells should be taken. By default,  
     1549                       if None, this is the one calling the function 
     1550        """ 
     1551        if spklist == None: 
     1552            spklist = self 
     1553         
     1554        if type(id_list) == int: 
     1555            spk1 = self.id_slice(id_list) 
     1556            spk2 = spklist.id_slice(spk1.id_list) 
     1557            N    = id_list 
     1558        else: 
     1559            N    = len(id_list) 
     1560            spk1 = self.id_slice(id_list) 
     1561            spk2 = spklist.id_slice(id_list) 
     1562         
     1563        distance   = 0. 
     1564         
     1565        for idx in xrange(len(spk1)): 
     1566            distance += spk1[spk1.id_list[idx]].KreuzDistance(spk2[spk2.id_list[idx]]) 
     1567        return distance/N 
    7951568 
    7961569    def mean_rate_variance(self, time_bin): 
    7971570        """ 
    798         Function to extract the variance of the firing rate along time, 
     1571        Return the standard deviation of the firing rate along time, 
    7991572        if events are binned with a time bin. 
     1573         
     1574        Inputs: 
     1575            time_bin - time bin to bin events 
     1576         
     1577        See also 
     1578            mean_rate, mean_rates, mean_rate_covariance, firing_rate 
    8001579        """ 
    8011580        firing_rate = self.firing_rate(time_bin) 
    802         return numpy.var(sum(firing_rate)/self.N()) 
    803  
    804     def mean_rate_covariance(self, SpkList, time_bin): 
    805         """ 
    806         Function to extract the covariance of the firing rate along time, 
    807         if events are binned with a time bin. We need a second SpikeList 
    808         object with same time parameters to calculate the covariance 
    809         """ 
    810         if not isinstance(SpkList, SpikeList): 
     1581        return numpy.var(numpy.sum(firing_rate, axis=0)/len(self)) 
     1582 
     1583    def mean_rate_covariance(self, spikelist, time_bin): 
     1584        """ 
     1585        Return the covariance of the firing rate along time, 
     1586        if events are binned with a time bin. 
     1587         
     1588        Inputs: 
     1589            spikelist - the other spikelist to compute covariance  
     1590            time_bin  - time bin to bin events 
     1591         
     1592        See also 
     1593            mean_rate, mean_rates, mean_rate_variance, firing_rate 
     1594        """ 
     1595        if not isinstance(spikelist, SpikeList): 
    8111596            raise Exception("Error, argument should be a SpikeList object") 
    812         if not SpkList.get_time_parameters() == self.get_time_parameters(): 
     1597        if not spikelist.get_time_parameters() == self.get_time_parameters(): 
    8131598            raise Exception("Error, both SpikeLists should share common t_start, t_stop and dt") 
    8141599        frate_1 = self.firing_rate(time_bin) 
    815         frate_1 = sum(frate_1)/self.N() 
    816         frate_2 = SpkList.firing_rate(time_bin) 
    817         frate_2 = sum(frate_2)/SpkList.N() 
     1600        frate_1 = numpy.sum(frate_1, axis=0)/len(self) 
     1601        frate_2 = spikelist.firing_rate(time_bin) 
     1602        frate_2 = numpy.sum(frate_2, axis=0)/len(spikelist) 
    8181603        N = len(frate_1) 
    819         cov = sum(frate_1*frate_2)/N-sum(frate_1)*sum(frate_2)/(N*N) 
     1604        cov = numpy.sum(frate_1*frate_2)/N-numpy.sum(frate_1)*numpy.sum(frate_2)/(N*N) 
    8201605        return cov 
    821      
    822     def raster_plot(self, id_list=None, t_start=None, t_stop=None, colors='b', subplot=None, size=1): 
    823         """ 
    824         Generate a raster plot of a certain number of cells in the 
    825         SpikeList object. If id_list is an integer, then N ids will be randomly choosen 
    826         in id_list. If this is a list, those id will be selected. 
    827         Raster is made between t_start and t_stop (region of interest, not the global ones) 
    828         and colors can be a list of color (each for one cells) or a single string 
    829         to apply the same color to all the raster plots. 
    830         """ 
     1606 
     1607 
     1608    def raster_plot(self, id_list=None, t_start=None, t_stop=None, display=True, kwargs={}): 
     1609        """ 
     1610        Generate a raster plot for the SpikeList in a subwindow of interest, 
     1611        defined by id_list, t_start and t_stop.  
     1612         
     1613        Inputs: 
     1614            id_list - can be a integer (and then N cells are randomly selected) or a list of ids. If None,  
     1615                      we use all the ids of the SpikeList 
     1616            t_start - in ms. If not defined, the one of the SpikeList object is used 
     1617            t_stop  - in ms. If not defined, the one of the SpikeList object is used 
     1618            display - if True, a new figure is created. Could also be a subplot 
     1619            kwargs  - dictionary contening extra parameters that will be sent to the plot  
     1620                      function 
     1621         
     1622        Examples: 
     1623            >>> z = subplot(221) 
     1624            >>> spikelist.raster_plot(display=z, kwargs={'color':'r'}) 
     1625         
     1626        See also 
     1627            SpikeTrain.raster_plot 
     1628        """ 
     1629        subplot = self.__getdisplay__(display) 
    8311630        if id_list == None:  
    832             id_list = self.id_list 
    833             spk = self.idsubSpikeList(id_list) 
    834         elif id_list != self.id_list: 
    835             spk = self.idsubSpikeList(id_list) 
    836             id_list = spk.id_list 
    837         else: 
    838             spk = self.idsubSpikeList(id_list) 
    839  
     1631            id_list = self.id_list() 
     1632            spk = self 
     1633        else: 
     1634            spk = self.id_slice(id_list) 
     1635 
     1636        if t_start is None: t_start = spk.t_start 
     1637        if t_stop is None:  t_stop  = spk.t_stop 
     1638        if t_start != spk.t_start or t_stop != spk.t_stop: 
     1639            spk = spk.time_slice(t_start, t_stop) 
     1640 
     1641        if not subplot or not ENABLE_PLOTS: 
     1642            print MATPLOTLIB_ERROR 
     1643        else: 
     1644            ids, spike_times = spk.convert(format="[ids, times]") 
     1645            idx = numpy.where((spike_times >= t_start) & (spike_times <= t_stop))[0] 
     1646            if len(spike_times) > 0: 
     1647                subplot.scatter(spike_times, ids, **kwargs) 
     1648            xlabel = "Time (ms)" 
     1649            ylabel = "Neuron #" 
     1650            self.__labels__(subplot, xlabel, ylabel) 
     1651            min_id = numpy.min(spk.id_list) 
     1652            max_id = numpy.max(spk.id_list) 
     1653            length = t_stop - t_start 
     1654            subplot.axis([t_start-0.05*length, t_stop+0.05*length, min_id-2, max_id+2]) 
     1655            pylab.draw() 
     1656 
     1657 
     1658 
     1659    def activity_movie(self, time_bin=10, t_start=None, t_stop=None, float_positions=None, output="animation.mpg", bounds=(0,5), fps=10, display = True, kwargs={}): 
     1660        """ 
     1661        Generate a movie of the activity between t_start and t_stop. 
     1662        If t_start and t_stop are not defined, we used those of the SpikeList object 
     1663         
     1664        Inputs: 
     1665            time_bin        - time step to bin activity during the movie.  
     1666                              One frame is the mean rate during time_bin 
     1667            t_start         - if not defined, the one of the SpikeList is used, in ms 
     1668            t_stop          - if not defined, the one of the SpikeList is used, in ms 
     1669            float_positions - None by default, meaning that the dimensions attribute of the SpikeList 
     1670                              is used to arange the ids on a 2D grid. Otherwise, if the cells have 
     1671                              flotting positions, float_positions should be an array of size 
     1672                              (2, nb_cells) with the x (first line) and y (second line) coordinates of 
     1673                              the cells 
     1674            output          - The filename to store the movie 
     1675            bounds          - The common color bounds used during all the movies frame.  
     1676                              This is a tuple 
     1677                              of values (min, max), in spikes per frame. 
     1678            fps             - The number of frame per second in the final movie 
     1679            display         - if True, a new figure is created. Could also be a subplot. 
     1680            kwargs          - dictionary contening extra parameters that will be sent to the plot  
     1681                              function 
     1682 
     1683        The 'dimensions' attribute of the SpikeList is used to turn ids into 2d positions. It should 
     1684        therefore be not empty. 
     1685         
     1686        Examples: 
     1687            >> spklist.activity_movie(10,0,1000,bounds=(0,5),display=subplot(221),output="test.mpg") 
     1688         
     1689        See also 
     1690            activity_map 
     1691        """ 
     1692        subplot = self.__getdisplay__(display) 
    8401693        if t_start is None: t_start = self.t_start 
    841         if t_stop is None:  t_stop = self.t_stop 
    842  
    843         if subplot is None: 
    844             pylab.figure() 
    845             subplot = pylab 
    846         if isinstance(colors, str): # this is much, much faster than a different colour per row 
    847             ids, spike_times = self.as_ids_times() 
    848             idx = numpy.where((spike_times >= t_start) & (spike_times <= t_stop))[0] 
    849             spike_times = spike_times[idx] 
    850             ids = ids[idx] 
    851             if len(spike_times) > 0: 
    852                 print "Plotting %d points for %s" % (len(spike_times), self.label) 
    853                 subplot.scatter(spike_times, ids, s=size, c=colors) 
    854         elif len(colors) != len(id_list): 
    855             raise Exception("The numbers of colors does not match the number of cells!") 
    856         else: # this is very slow in interactive mode 
    857             for count,id in enumerate(spk.id_list): 
    858                 st = spk.spiketrains[id] 
    859                 idx = numpy.where((st.spike_times >= t_start) & (st.spike_times <= t_stop))[0] 
    860                 spikes = st.spike_times[idx] 
    861                 if len(spikes) > 0: 
    862                     subplot.scatter(spikes,count*numpy.ones(len(spikes)), s=size, c=colors[count]) 
    863         xlabel = "Time (ms)" 
    864         ylabel = "Neuron #" 
    865         if hasattr(subplot, 'xlabel'): 
    866             subplot.xlabel(xlabel, size="x-large") 
    867             subplot.ylabel(ylabel, size="x-large") 
    868         else: 
    869             subplot.set_xlabel(xlabel, size="x-large") 
    870             subplot.set_ylabel(ylabel, size="x-large") 
    871         subplot.axis([t_start-10, t_stop+10, -1, len(self)+1]) 
    872  
    873     # Clearly not optimal, but at least this is working... The best way to 
    874     # do that function would be to go through the sorted list of all the spike times 
    875     def activity_movie(self, dims, time_bin=10, bounds = (0,20), output="animation.mpg", fps=10): 
    876         time  = self.t_start 
    877         files = [] 
    878         while (time < self.t_stop): 
    879             subSpkList = self.timesubSpikeList(time, time + time_bin) 
    880             activity_map = subSpkList.activity_map(dims, bounds, display=True) 
    881             caption = time+time_bin/2 
    882             pylab.title("Time = %g ms" %caption) 
    883             fname = "_tmp_%g.jpg" %caption 
    884             print " Saving Frame", fname 
    885             pylab.savefig(fname) 
    886             pylab.close() 
    887             files.append(fname) 
    888             time += time_bin 
    889         print 'Making movie %s - this make take a while' %output 
    890         command = "mencoder 'mf://_tmp_*.jpg' -mf type=jpg:fps=%d -ovc lavc -lavcopts vcodec=wmv2 -oac copy -o %s" %(fps,output) 
    891         print command 
    892         os.system(command) 
    893         ## cleanup 
    894         print "Clean up...." 
    895         for fname in files: os.remove(fname) 
    896  
    897     def pw_corr_pearson(self,edge,bins,number_of_neuron_pairs):  
    898         """ 
    899         TODO: document/test this function 
    900  
    901         """ 
    902         #bins = edge[1]-edge[0] 
    903         cor = numpy.zeros((number_of_neuron_pairs,)) 
    904         [neuron_ids_array, spike_times_array] = self.as_list_id_list_time() 
    905          
    906         # Pairwise correlation 
    907         neuron_ids_unique = numpy.unique(neuron_ids_array) 
    908          
    909         if len(neuron_ids_unique)==0: 
    910             return (0,0) 
    911          
    912         for count in range(number_of_neuron_pairs): 
    913             # draw two neuron radomly out of the neuron_id_unique pool 
    914             neuron_1_tmp = neuron_ids_unique[numpy.floor(numpy.random.uniform()*len(neuron_ids_unique))] 
    915             neuron_2_tmp = neuron_ids_unique[numpy.floor(numpy.random.uniform()*len(neuron_ids_unique))] 
    916             # get the spike_times of the neurons 
    917             spike_times_1_tmp = self.spiketrains[neuron_1_tmp].spike_times 
    918             spike_times_2_tmp = self.spiketrains[neuron_2_tmp].spike_times 
    919  
    920             # hist of the spiketrains 
    921             n1_hist = numpy.histogram(spike_times_1_tmp,bins=bins,range=edge) 
    922             n2_hist = numpy.histogram(spike_times_2_tmp,bins=bins,range=edge) 
     1694        if t_stop is None:  t_stop  = self.t_stop 
     1695        if not subplot or not ENABLE_PLOTS: 
     1696            print MATPLOTLIB_ERROR 
     1697        else: 
     1698            files        = [] 
     1699            activity_map = numpy.zeros(self.dimensions) 
     1700            im           = subplot.imshow(activity_map, **kwargs) 
     1701            im.set_clim(bounds[0],bounds[1]) 
     1702            im.colorbar() 
     1703            count     = 0 
     1704            idx       = 0 
     1705            manager   = pylab.get_current_fig_manager() 
     1706            if t_start != self.t_start or t_stop != self.t_stop: 
     1707                spk   = spk.time_slice(t_start, t_stop) 
     1708            else: 
     1709                spk   = self 
     1710            time, pos = spk.convert("times, ids") 
     1711            # We sort the spikes to allow faster process later 
     1712            sort_idx  = time.ravel().argsort() 
     1713            time      = time[sort_idx] 
     1714            pos       = pos[sort_idx] 
     1715 
     1716            if float_positions is None: 
     1717                if self.dimensions is None: 
     1718                    raise Exception("Dimensions of the population are not defined ! Set spikelist.dims") 
     1719            while (t_start < t_stop): 
     1720                activity_map = numpy.zeros(spk.dimensions) 
     1721                while (time[idx] < t_start + time_bin): 
     1722                    addr = spk.id2position(pos[idx]) 
     1723                    activity_map[addr] += 1 
     1724                    idx += 1 
     1725                im.set_array(activity_map) 
     1726                subplot.title("time = %d ms" %t_start) 
     1727                manager.canvas.draw() 
     1728                im.set_clim(bounds[0],bounds[1]) 
     1729                fname = "_tmp_spikes_%05d.png" %count 
     1730                print " Saving Frame", fname 
     1731                pylab.savefig(fname) 
     1732                files.append(fname) 
     1733                t_start += time_bin 
     1734                count += 1 
     1735            print 'Making movie %s - this make take a while' %output 
     1736            command = "mencoder 'mf://_tmp_*.jpg' -mf type=jpg:fps=%d -ovc lavc -lavcopts vcodec=wmv2 -oac copy -o %s" %(fps,output) 
     1737            print command 
     1738            os.system(command) 
     1739            ## cleanup 
     1740            print "Clean up...." 
     1741            for fname in files: os.remove(fname) 
     1742 
     1743 
     1744    def pairwise_pearson_corrcoeff(self, pairs, spklist=None, time_bin=1.):  
     1745        """ 
     1746        Function to return the mean and the variance of the pearson correlation coefficient.  
     1747        For more details, see Kumar et al, .... 
     1748         
     1749        Inputs: 
     1750            pairs    - an int to specify the number of pairs used to estimate the correlation coefficient 
     1751            time_bin - The time bin used to gather the spikes 
     1752        """ 
     1753        if spklist == None: 
     1754            spklist = self 
     1755         
     1756        if type(pairs) == int: 
     1757            spk1 = self.id_slice(pairs) 
     1758            spk2 = spklist.id_slice(pairs) 
     1759            N    = pairs 
     1760        else: 
     1761            pairs  = numpy.array(pairs) 
     1762            N      = len(pairs[:,0]) 
     1763            spk1   = self.id_slice(pairs[:,0]) 
     1764            spk2   = spklist.id_slice(pairs[:,1]) 
     1765         
     1766        cor          = numpy.zeros(N, float) 
     1767         
     1768        ## We have to extract only the non silent cells, to avoied problems 
     1769        non_silent = spk1.select_ids("cell.mean_rate() > 0") 
     1770        spk1 = spk1.id_slice(non_silent) 
     1771        non_silent = spk2.select_ids("cell.mean_rate() > 0") 
     1772        spk2 = spk2.id_slice(non_silent) 
     1773         
     1774        for count in range(N): 
     1775            # draw two neuron randomly out of the neuron_id_unique pool 
     1776            neuron_1 = self.id_list()[numpy.floor(numpy.random.uniform()*len(self))] 
     1777            neuron_2 = self.id_list()[numpy.floor(numpy.random.uniform()*len(self))] 
     1778 
     1779            # get the spike_times of the selected neurons 
     1780            spk_1 = self.spiketrains[neuron_1] 
     1781            spk_2 = self.spiketrains[neuron_2] 
     1782 
     1783            # get the histogram of the spiketrains 
     1784            n1_hist = spk_1.time_histogram(time_bin) 
     1785            n2_hist = spk_2.time_histogram(time_bin) 
    9231786 
    9241787            # correlation 
    9251788            # TODO: normalize the cor, look in 1.6 in Kumar et al. 
    9261789            # bruederle: the function corrcoeff actually implements the definition in Kumar 1.6 
    927             cov = numpy.corrcoef(n1_hist[0],n2_hist[0])[1][0] 
    928             #print n1_hist[0] 
    929             #print n2_hist[0] 
     1790            cov = numpy.corrcoef(n1_hist,n2_hist)[1][0] 
    9301791 
    9311792            # bruederle: the expression 'cov' is already, per definition, the pearson correlation coefficient  
     
    9371798 
    9381799        cor_coef_mean = cor.mean() 
    939         cor_coef_std = cor.std() 
    940         return cor_coef_mean, cor_coef_std 
    941  
     1800        cor_coef_std  = cor.std() 
     1801        return (cor_coef_mean, cor_coef_std) 
     1802 
     1803 
     1804    #################################################################### 
     1805    ### TOO SPECIFIC METHOD ? 
     1806    ### Better documentation 
     1807    #################################################################### 
    9421808    def f1f0_ratios(self, time_bin, f_stim): 
    9431809        """ 
     
    9501816        return f1f0_dict 
    9511817 
    952         # methods for different output formats 
    953     def as_ids_times(self, relative=False, quantized=False): 
    954         """Returns (array of ids, array of times).""" 
    955         spikes = numpy.concatenate([st.spike_times for st in self.spiketrains.itervalues()]) 
    956         ids = numpy.concatenate([id*numpy.ones((len(st.spike_times),)) for id,st in self.spiketrains.iteritems()]) 
    957         assert len(ids) == len(spikes) 
    958         return ids, spikes 
    959  
    960     def as_list_id_time(self, relative=False, quantized=False): 
    961         """ 
    962         Returns a list/tuple of (id,t) tuples (id in range(0,N)). 
    963  
    964         """ 
    965         spikes =[] 
    966         for id in self.id_list: 
    967             for time in self.spiketrains[id].spike_times : 
    968                 spikes.append((id, time)) 
    969         return spikes 
    970  
    971     def as_list_id_list_time(self, relative=False, quantized=False): 
    972         """ 
    973         Returns (list of ids, list of times). 
    974  
    975         """ 
    976         spikes = self.as_list_id_time() 
    977         ids, times = [], [] 
    978         for spike in spikes: 
    979             ids.append(spike[0]) 
    980             times.append(spike[1]) 
    981  
    982         return [ids, times] 
    983  
    984     def as_id_list_times(self, relative=False, quantized=False): 
    985         pass 
    986  
    987     def as_time_list_ids(self, relative=False, quantized=False): 
    988         pass 
    989  
    990     def as_2byN_array(self, relative=False, quantized=False): 
    991         pass 
    992  
    993     def as_spikematrix(self): 
    994         """ Returns a list giving for each neuron how many spikes per 
    995         time bin, usually zero everywhere, one if a spike. 
    996         Useful for plots etc. 
    997  
    998         """ 
    999         return self.firing_rate(self.dt) 
    1000  
    1001     def as_pyNN_SpikeArray(self): 
    1002         """ 
    1003         to use in conjunction with SpikeSourceArray neurons 
    1004  
    1005         >>> pop = Population((10,),SpikeSourceArray, {'spike_times': sl.as_pyNN_SpikeArray() }) 
    1006  
    1007         """ 
    1008         spike_array = list([ [] for i in range(self.N())]) 
    1009         for spike in spikes: 
    1010             spike_array[spike[0]].append(spike[1]) 
    1011  
    1012         return spike_array 
    1013  
    1014 """ 
    1015 SpikeLists functions 
    1016  
    1017 """ 
    1018  
    1019 def population2spikelist(output, N, dt , t_start, t_stop): 
     1818 
     1819 
     1820    ####################################################################### 
     1821    ## Method to convert the SpikeList into several others format        ## 
     1822    ####################################################################### 
     1823 
     1824    def convert(self, format="[times, ids]", relative=False, quantized=False): 
     1825        """ 
     1826        Return a new representation of the SpikeList object, in a user designed format. 
     1827            format is an expression containing either the keywords times and ids,  
     1828            time and id. 
     1829        
     1830        Inputs: 
     1831            relative -  a boolean to say if a relative representation of the spikes  
     1832                        times compared to t_start is needed 
     1833            quantized - a boolean to round the spikes_times. 
     1834         
     1835        Examples:  
     1836            >>>spk.convert("[times, ids]") will return a list of two elements, the  
     1837                first one being the array of all the spikes, the second the array of all the 
     1838                corresponding ids 
     1839            >>>spk.convert("[(time,id)]") will return a list of tuples (time, id) 
     1840         
     1841        See also 
     1842            SpikeTrain.format 
     1843        """ 
     1844        is_times = re.compile("times") 
     1845        is_ids   = re.compile("ids") 
     1846        times  = numpy.concatenate([st.format(relative, quantized) for st in self.spiketrains.itervalues()]) 
     1847        ids    = numpy.concatenate([id*numpy.ones(len(st.spike_times), int) for id,st in self.spiketrains.iteritems()]) 
     1848        if is_times.search(format): 
     1849            if is_ids.search(format): 
     1850                return eval(format) 
     1851            else: 
     1852                raise Exception("You must have a format with [times, ids] or [time, id]") 
     1853        is_times = re.compile("time") 
     1854        is_ids   = re.compile("id") 
     1855        if is_times.search(format): 
     1856            if is_ids.search(format): 
     1857                result = [] 
     1858                for id, time in zip(ids, times): 
     1859                    result.append(eval(format)) 
     1860            else: 
     1861                raise Exception("You must have a format with [times, ids] or [time, id]") 
     1862            return result 
     1863 
     1864 
     1865 
     1866 
     1867class AnalogSignal(object): 
    10201868    """ 
    1021     TODO sl2pynn 
     1869    AnalogSignal(signal, dt, t_start=None, t_stop=None) 
     1870     
     1871    Return a AnalogSignal object which will be a analog signal trace 
     1872 
     1873    Inputs: 
     1874        signal  - the vector with the data of the AnalogSignal 
     1875        dt      - the time step between two data points of the sampled analog signal 
     1876        t_start - begining of the signal, in ms. If None, will be set to 0 
     1877        t_stop  - end of the SpikeList, in ms. If None, will be infered from the data 
     1878     
     1879    Examples: 
     1880        >>> as = AnalogSignal(range(100), dt=0.1, t_start=0, t_stop=10) 
     1881 
     1882    See also 
     1883        AnalogSignalList, load_currenttraces, load_membranetrace, load_conductancetraces 
     1884 
    10221885    """ 
    1023     import os, tempfile 
    1024  
    1025     tmpdir = tempfile.mkdtemp() 
    1026     output_filename=os.path.join(tmpdir,'output.gdf') 
    1027     output.printSpikes(output_filename)# 
    1028     output_DATA = loadSpikeList(output_filename, N= N, dt = dt, t_start=t_start, t_stop=t_stop) 
    1029     os.remove(output_filename) 
    1030     os.rmdir(tmpdir) 
    1031     return output_DATA 
    1032  
    1033 def readFile(filename, sepchar = "\t", skipchar = '#'): 
    1034     """ 
    1035     Function to read data. Should be optimize to deal with errors in the file 
    1036     that may append sometimes, when nest1 does not save the entire last line. 
    1037     It assumes that the data have been produced by pyNN under the format 
    1038     time (ms) gids (for raster) 
    1039     value (unit) gids (for continuous recordings like Vm, current, conductances) 
    1040     """ 
    1041     myfile = open(filename, "r", 10000) 
    1042     contents = myfile.readlines() 
    1043     myfile.close() 
    1044     data = [] 
    1045     for line in contents: 
    1046         stripped_line = line.lstrip() 
    1047         if (len(stripped_line) != 0): 
    1048             if (stripped_line[0] != skipchar): 
    1049                 items = stripped_line.split(sepchar) 
    1050                 data.append([int(float(items[1])), float(items[0])]) 
    1051     return(data) 
    1052  
    1053 def get_header(filename): 
    1054     cmd = '' 
    1055     f = open(filename, 'r') 
    1056     for line in f.readlines(): 
    1057         if line[0] == '#': 
    1058             cmd += line[1:].strip() + ';' 
    1059     f.close() 
    1060     header = {} 
    1061     exec cmd in None, header 
    1062     return header 
    1063  
    1064 def loadSpikeList(filename, id_list=None, dt = None, t_start=None, t_stop=None): 
    1065     """ 
    1066     Returns a SpikeList object from the tmp file saved by PyNN. 
    1067  
    1068     The input is the filename where pyNN stored the spike list and the discretization step dt. 
    1069     it returns the spike list represented as a list of events. Events are tuples (relative time 
    1070     since last event, neuron_id); neuron_id and time are integers 
    1071  
    1072     All times in milliseconds. 
    1073  
    1074     The PyNN format (with compatible_output=True) is: 
    1075     * comment lines containing header information, 
    1076     * then one line per event:  absolute time in ms, GID 
    1077     (see function printSpikes in nest1.py) 
    1078  
    1079     """ 
    1080     if id_list is None: # try to obtain id_list from file header 
    1081         header = get_header(filename) 
    1082         if 'first_id' in header: 
    1083             n_cells = int(header['last_id']) - int(header['first_id']) + 1 
    1084             id_list = n_cells 
    1085         else: 
    1086             raise Exception("id_list not provided and cannot be inferred from file header.") 
    1087     if isinstance(id_list,int): # allows to just specify the number of neurons 
    1088         id_list = range(id_list) 
    1089     spikes = readFile(filename) 
    1090     print "Read %d spikes from %s" % (len(spikes), filename) 
    1091     return SpikeList(spikes, id_list, dt, t_start, t_stop, label=filename) 
    1092  
    1093  
    1094 def loadConductanceTraceList(filename, id_list, dt = None, t_start=None, t_stop=None): 
    1095     if isinstance(id_list,int): # allows to just specify the number of neurons 
    1096         id_list = range(id_list) 
    1097     analog_signals = readFile(filename) 
    1098     return ConductanceTraceList(analog_signals, id_list, dt, t_start, t_stop) 
    1099  
    1100  
    1101 def loadMembraneTraceList(filename, id_list, dt = None, t_start=None, t_stop=None): 
    1102     if isinstance(id_list,int): # allows to just specify the number of neurons 
    1103         id_list = range(id_list) 
    1104     analog_signals = readFile(filename) 
    1105     return MembraneTraceList(analog_signals, id_list, dt, t_start, t_stop) 
    1106  
    1107  
    1108 def loadCurrentTraceList(filename, id_list, dt = None, t_start=None, t_stop=None): 
    1109     if isinstance(id_list,int): # allows to just specify the number of neurons 
    1110         id_list = range(id_list) 
    1111     analog_signals = readFile(filename) 
    1112     return CurrentTraceList(analog_signals, id_list, dt, t_start, t_stop) 
    1113  
    1114  
    1115 class AnalogSignal(object): 
    1116  
    11171886    def __init__(self, signal, dt, t_start=None, t_stop=None): 
    11181887 
     
    11301899        # elements with t <= t_stop 
    11311900        if self.t_stop is not None: 
    1132             self.signal = self.signal[:(self.t_stop-self.t_start/self.dt)] 
    1133  
    1134         if len(signal) > 0: # spike list may be empty 
     1901            self.signal = self.signal[:(self.t_stop-self.t_start)/self.dt] 
     1902 
     1903        if len(self.signal) > 0: # spike list may be empty 
    11351904            if self.t_start is None: 
    11361905                self.t_start = 0. 
     
    11411910        #TODO return an exception if self.t_stop < self.t_start (when not empty) 
    11421911        if self.t_start >= self.t_stop : 
    1143             raise("Incompatible time interval for the creation of the AnalogSignal") 
     1912            raise Exception("Incompatible time interval for the creation of the AnalogSignal") 
     1913 
     1914    def __getslice__(self, i, j): 
     1915        """ 
     1916        Return a sublist of the signal vector of the AnalogSignal 
     1917        """ 
     1918        return self.signal[i:j] 
     1919 
     1920    def duration(self): 
     1921        """ 
     1922        Return the duration of the SpikeTrain 
     1923        """ 
     1924        return self.t_stop - self.t_start 
    11441925 
    11451926    def __str__(self): 
     
    11491930        return len(self.signal) 
    11501931 
     1932    def copy(self): 
     1933        """ 
     1934        Return a copy of the AnalogSignal object 
     1935        """ 
     1936        return AnalogSignal(self.signal, self.dt, self.t_start, self.t_stop) 
     1937 
    11511938    def time_axis(self): 
     1939        """ 
     1940        Return the time axis of the AnalogSignal 
     1941        """ 
    11521942        return numpy.arange(self.t_start, self.t_stop, self.dt) 
    11531943 
     1944    def time_slice(self, t_start, t_stop): 
     1945        """  
     1946        Return a new AnalogSignal obtained by slicing between t_start and t_stop 
     1947         
     1948        Inputs: 
     1949            t_start - begining of the new SpikeTrain, in ms. 
     1950            t_stop  - end of the new SpikeTrain, in ms. 
     1951 
     1952        """ 
     1953        signal = self.signal[t_start/self.dt:t_stop/self.dt] 
     1954        return AnalogSignal(signal, self.dt, t_start, t_stop) 
     1955         
     1956 
    11541957 
    11551958class AnalogSignalList(object): 
    1156  
    1157     def __init__(self, signals, id_list, dt=None, t_start=None, t_stop=None): 
    1158         self.id_list = id_list 
    1159         self.N = len(id_list) 
     1959    """ 
     1960    AnalogSignalList(signals, id_list, dt=None, t_start=None, t_stop=None, dims=None) 
     1961     
     1962    Return a AnalogSignalList object which will be a list of AnalogSignal objects. 
     1963 
     1964    Inputs: 
     1965        signals - a list of the AnalogSignals objects 
     1966        id_list - the list of the ids of all recorded cells (needed for silent cells) 
     1967        dt      - if dt is specified, time values should be floats 
     1968        t_start - begining of the SpikeList, in ms. If None, will be infered from the data 
     1969        t_stop  - end of the SpikeList, in ms. If None, will be infered from the data 
     1970        dims    - dimensions of the recorded population, if not 1D population 
     1971     
     1972    dt, t_start and t_stop are shared for all SpikeTrains object within the SpikeList 
     1973     
     1974    See also 
     1975        load_currentlist load_vmlist, load_conductancelist 
     1976 
     1977    """ 
     1978    def __init__(self, signals, id_list, dt=None, t_start=None, t_stop=None, dims=None): 
    11601979        self.t_start = t_start 
    11611980        self.t_stop  = t_stop 
    1162         self.dt = dt 
     1981        self.dt      = dt 
     1982        self.dimensions     = dims 
    11631983        self.analog_signals = {} 
    11641984        for id in id_list: 
     
    11671987            self.analog_signals[id].append(value) 
    11681988 
     1989        if t_start is None: 
     1990            self.t_start = 0 
     1991 
    11691992        # writing as a list of SpikeTrains 
    11701993        for id,signal in self.analog_signals.items(): #TODO: handle missing fields 
     
    11721995        if t_start is None or t_stop is None: 
    11731996            self.__calc_startstop() 
    1174             #self.spiketrains.append( SpikeTrain(spike_array[i_neuron], dt=dt )) 
     1997 
     1998    def id_list(self): 
     1999        """  
     2000        Return the list of all the cells ids contained in the 
     2001        SpikeList object 
     2002        """ 
     2003        return numpy.array(self.analog_signals.keys()) 
     2004 
     2005    def copy(self): 
     2006        """ 
     2007        Return a copy of the AnalogSignalList object 
     2008        """ 
     2009        # Maybe not optimal, should be optimized 
     2010        aslist = AnalogSignalList([], [], self.dt, self.t_start, self.t_stop, self.dimensions) 
     2011        for id in self.id_list(): 
     2012            aslist.append(id, self.analog_signals[id]) 
     2013        return aslist 
    11752014 
    11762015    def __calc_startstop(self): 
     
    11822021        if len(self) > 0: 
    11832022            if self.t_start is None: 
    1184                 self.t_start = 0. 
    1185             #if self.t_stop is None: 
    1186             # 
     2023                start_times  = numpy.array([self.analog_signals[idx].t_start for idx in self.id_list()]) 
     2024                self.t_start = numpy.min(start_times) 
     2025                logging.debug("Warning, t_start is infered from the data : %f" %self.t_start) 
     2026                for id in self.analog_signals.keys(): 
     2027                    self.analog_signals[id].t_start = self.t_start 
     2028            if self.t_stop is None: 
     2029                stop_times  = numpy.array([self.analog_signals[idx].t_stop for idx in self.id_list()]) 
     2030                self.t_stop = numpy.max(stop_times) 
     2031                logging.debug("Warning, t_stop  is infered from the data : %f" %self.t_stop) 
     2032                for id in self.analog_signals.keys(): 
     2033                    self.analog_signals[id].t_stop = self.t_stop 
    11872034        else: 
    11882035            raise Exception("No Analog Signals !") 
     2036     
     2037    def __getdisplay__(self,display): 
     2038        """ 
     2039        Return a pylab object with a plot() function to draw the plots. 
     2040         
     2041        Inputs: 
     2042            display - if True, a new figure is created. Otherwise, if display is a 
     2043                      subplot object, this object is returned. 
     2044        """ 
     2045        if display is False: 
     2046            return None 
     2047        elif display is True: 
     2048            pylab.figure() 
     2049            return pylab 
     2050        else: 
     2051            return display 
     2052     
     2053    def __labels__(self, subplot, xlabel, ylabel): 
     2054        """ 
     2055        Function to put some labels on a plot 
     2056         
     2057        Inputs: 
     2058            subplot - the targeted plot 
     2059            xlabel  - a string for the x label 
     2060            ylabel  - a string for the y label 
     2061        """ 
     2062        if hasattr(subplot, 'xlabel'): 
     2063            subplot.xlabel(xlabel) 
     2064            subplot.ylabel(ylabel) 
     2065        else: 
     2066            subplot.set_xlabel(xlabel) 
     2067            subplot.set_ylabel(ylabel) 
    11892068 
    11902069    def __getitem__(self, i): 
     
    11992078        return len(self.analog_signals) 
    12002079 
     2080    def __sub_id_list(self, sub_list=None): 
     2081        if sub_list == None: 
     2082            return self.id_list() 
     2083        if type(sub_list) == int: 
     2084            return numpy.random.permutation(self.id_list())[0:sub_list] 
     2085        if type(sub_list) == list: 
     2086            return sub_list 
     2087 
    12012088    def append(self, id, signal): 
     2089        """ 
     2090        Add an AnalogSignal object to the AnalogSignalList 
     2091         
     2092        Inputs: 
     2093            id     - the id of the new cell 
     2094            signal - the AnalogSignal object representing the new cell 
     2095         
     2096        The AnalogSignal object is sliced according to the t_start and t_stop times 
     2097        of the AnalogSignallist object 
     2098         
     2099        See also 
     2100            __setitem__ 
     2101        """ 
    12022102        assert isinstance(signal, AnalogSignal), "An AnalogSignalList object can only contain AnalogSignal objects" 
    1203         if id in self.id_list: 
    1204             raise Exception("Id already present in AnalogSignalList.Use setitem instead()") 
     2103        if id in self.id_list(): 
     2104            raise Exception("Id already present in AnalogSignalList. Use setitem instead()") 
    12052105        else: 
    12062106            self.analog_signals[id] = signal 
    1207             self.id_list.append(id) 
    1208             self.N += 1 
    12092107        self.__calc_startstop() 
    12102108 
    12112109    def time_axis(self): 
     2110        """ 
     2111        Return the time axis of the AnalogSignalList object 
     2112        """ 
    12122113        return numpy.arange(self.t_start,self.t_stop,self.dt) 
    12132114 
    1214  
    1215  
    1216  
    1217 class MembraneTraceList(AnalogSignalList): 
    1218  
    1219     def plot(self, id_list, v_thresh=None): 
    1220         pylab.figure() 
    1221         pylab.hold(1) 
    1222         pylab.ylabel("Analog values [unit]", size="x-large") 
    1223         pylab.xlabel("Time (ms)", size="x-large") 
     2115    def id_slice(self, id_list): 
     2116        """ 
     2117        Return a new AnalogSignalList obtained by selecting particular ids 
     2118         
     2119        Inputs: 
     2120            id_list - Can be an integer (and then N random cells will be selected) 
     2121                      or a sublist of the current ids 
     2122         
     2123        The new AnalogSignalList inherits the time parameters (t_start, t_stop, dt) 
     2124         
     2125        See also 
     2126            time_slice 
     2127        """ 
     2128        new_AnalogSignalList = AnalogSignalList([], [], self.dt, self.t_start, self.t_stop, self.dimensions) 
     2129        id_list = self.__sub_id_list(id_list) 
    12242130        for id in id_list: 
    1225             to_be_plot = self.analog_signals[id].signal 
    1226             if v_thresh is not None: 
    1227                 to_be_plot = pylab.where(to_be_plot>=v_thresh-0.05,0.0,to_be_plot) 
    1228             pylab.plot(to_be_plot) 
    1229         [x,y] = pylab.xticks() 
    1230         pylab.xticks(x,numpy.array(self.t_start+x*self.dt,'string').tolist()) 
    1231  
    1232  
    1233 class CurrentTraceList(AnalogSignalList): 
    1234  
    1235     def plot(self, id_list): 
    1236         pylab.figure() 
    1237         pylab.hold(1) 
    1238         pylab.ylabel("Current (nA)", size="x-large") 
    1239         pylab.xlabel("Time (ms)", size="x-large") 
    1240         for id in id_list: 
    1241             pylab.plot(self.analog_signals[id].signal) 
    1242         [x,y] = pylab.xticks() 
    1243         pylab.xticks(x,numpy.array(self.t_start+x*self.dt,'string').tolist()) 
    1244  
    1245  
    1246 class ConductanceTraceList(AnalogSignalList): 
    1247  
    1248     def plot(self, id_list): 
    1249         pylab.figure() 
    1250         pylab.hold(1) 
    1251         pylab.ylabel("Conductance (nS)", size="x-large") 
    1252         pylab.xlabel("Time (ms)", size="x-large") 
    1253         for id in id_list: 
    1254             pylab.plot(self.analog_signals[id].signal) 
    1255         [x,y] = pylab.xticks() 
    1256         pylab.xticks(x,numpy.array(self.t_start+x*self.dt,'string').tolist()) 
    1257  
    1258  
    1259  
    1260  
    1261  
    1262 def ccf(x, y, axis=None): 
    1263     """Computes the cross-correlation function of two series `x` and `y`. 
    1264 Note that the computations are performed on anomalies (deviations from 
    1265 average). 
    1266 Returns the values of the cross-correlation at different lags. 
    1267 Lags are given as [0,1,2,...,n,n-1,n-2,...,-2,-1] (not any more) 
    1268  
    1269 :Parameters: 
    1270     `x` : 1D MaskedArray 
    1271         Time series. 
    1272     `y` : 1D MaskedArray 
    1273         Time series. 
    1274     `axis` : integer *[None]* 
    1275         Axis along which to compute (0 for rows, 1 for cols). 
    1276         If `None`, the array is flattened first. 
     2131            try: 
     2132                AnalogSignalList.append(id, self.analog_signals[id]) 
     2133            except Exception: 
     2134                print "id %d is not in the source AnalogSignalList" %id 
     2135        return new_AnalogSignalList 
     2136 
     2137    def time_slice(self, t_start, t_stop): 
     2138        """ 
     2139        Return a new AnalogSignalList obtained by slicing between t_start and t_stop 
     2140         
     2141        Inputs: 
     2142            t_start - begining of the new AnalogSignalList, in ms. 
     2143            t_stop  - end of the new AnalogSignalList, in ms. 
     2144         
     2145        See also 
     2146            id_slice 
     2147        """ 
     2148        new_AnalogSignalList = AnalogSignalList([], [], self.dt, t_start, t_stop, self.dimensions) 
     2149        for id in self.id_list(): 
     2150            new_AnalogSignalList.append(id, self.analog_signals[id].time_slice(t_start, t_stop)) 
     2151        new_AnalogSignalList.__calc_startstop() 
     2152        return new_AnalogSignalList 
     2153 
     2154    def save(self, filename, method="text"): 
     2155        """ 
     2156        Save the AnalogSignal in a text or binary file 
     2157         
     2158        Inputs: 
     2159            filename - name of the output file 
     2160            method   - "text"   -> a classical human readible text file 
     2161                       "pickle" -> binary backup, much more faster to load/save,  
     2162                                   but no longer human readible 
     2163                       "hdf5"   -> a compress an optimized structure, not 
     2164                                   implemented yet 
     2165        """ 
     2166        as_loader = io.AnalogSignalIO(filename) 
     2167        if method == "pickle": 
     2168            as_loader.save_analogsignal_pickle(self, filename) 
     2169        if method == "text": 
     2170            as_loader.save_analogsignal_txt(self, filename) 
     2171         
     2172     
     2173 
     2174class VmList(AnalogSignalList): 
     2175 
     2176    def plot(self, id_list=None, v_thresh=None, display=True, kwargs={}): 
     2177        """ 
     2178        Plot all cells in the AnalogSignalList defined by id_list 
     2179         
     2180        Inputs: 
     2181            id_list - can be a integer (and then N cells are randomly selected) or a  
     2182                      list of ids. If None, we use all the ids of the SpikeList 
     2183            v_thresh- For graphical purpose, plot a spike when Vm > V_thresh. If None,  
     2184                      just plot the raw Vm 
     2185            display - if True, a new figure is created. Could also be a subplot 
     2186            kwargs  - dictionary contening extra parameters that will be sent to the plot  
     2187                      function 
     2188         
     2189        Examples: 
     2190            >>> z = subplot(221) 
     2191            >>> aslist.plot(5, v_thresh = -50, display=z, kwargs={'color':'r'}) 
     2192        """ 
     2193        subplot   = self.__getdisplay__(display) 
     2194        id_list   = self._AnalogSignalList__sub_id_list(id_list) 
     2195        time_axis = self.time_axis()   
     2196        if not subplot or not ENABLE_PLOTS: 
     2197            print MATPLOTLIB_ERROR 
     2198        else: 
     2199            xlabel = "Time (ms)" 
     2200            ylabel = "Membrane Potential (mV)" 
     2201            self.__labels__(subplot, xlabel, ylabel) 
     2202            for id in id_list: 
     2203                to_be_plot = self.analog_signals[id].signal 
     2204                if v_thresh is not None: 
     2205                    to_be_plot = pylab.where(to_be_plot>=v_thresh-0.05,0.0,to_be_plot) 
     2206                subplot.plot(time_axis, to_be_plot, **kwargs) 
     2207                subplot.hold(1) 
     2208            pylab.draw() 
     2209 
     2210 
     2211class CurrentList(AnalogSignalList): 
     2212 
     2213    def plot(self, id_list=None, v_thresh=None, display=True, kwargs={}): 
     2214        """ 
     2215        Plot all cells in the AnalogSignalList defined by id_list 
     2216         
     2217        Inputs: 
     2218            id_list - can be a integer (and then N cells are randomly selected) or a  
     2219                      list of ids. If None, we use all the ids of the SpikeList 
     2220            display - if True, a new figure is created. Could also be a subplot 
     2221            kwargs  - dictionary contening extra parameters that will be sent to the plot  
     2222                      function 
     2223         
     2224        Examples: 
     2225            >>> z = subplot(221) 
     2226            >>> aslist.plot(5, display=z, kwargs={'color':'r'}) 
     2227        """ 
     2228        subplot   = self.__getdisplay__(display) 
     2229        id_list   = self._AnalogSignalList__sub_id_list(id_list) 
     2230        time_axis = self.time_axis()   
     2231        if not subplot or not ENABLE_PLOTS: 
     2232            print MATPLOTLIB_ERROR 
     2233        else: 
     2234            xlabel = "Time (ms)" 
     2235            ylabel = "Current (nA)" 
     2236            self.__labels__(subplot, xlabel, ylabel) 
     2237            for id in id_list: 
     2238                subplot.plot(time_axis, self.analog_signals[id].signal, **kwargs) 
     2239                subplot.hold(1) 
     2240            pylab.draw() 
     2241 
     2242class ConductanceList(AnalogSignalList): 
     2243 
     2244    def plot(self, id_list=None, v_thresh=None, display=True, kwargs={}): 
     2245        """ 
     2246        Plot all cells in the AnalogSignalList defined by id_list 
     2247         
     2248        Inputs: 
     2249            id_list - can be a integer (and then N cells are randomly selected) or a  
     2250                      list of ids. If None, we use all the ids of the SpikeList 
     2251            display - if True, a new figure is created. Could also be a subplot 
     2252            kwargs  - dictionary contening extra parameters that will be sent to the plot  
     2253                      function 
     2254         
     2255        Examples: 
     2256            >>> z = subplot(221) 
     2257            >>> aslist.plot(5, display=z, kwargs={'color':'r'}) 
     2258        """ 
     2259        subplot   = self.__getdisplay__(display) 
     2260        id_list   = self._AnalogSignalList__sub_id_list(id_list) 
     2261        time_axis = self.time_axis()   
     2262        if not subplot or not ENABLE_PLOTS: 
     2263            print MATPLOTLIB_ERROR 
     2264        else: 
     2265            xlabel = "Time (ms)" 
     2266            ylabel = "Conductance (nS)" 
     2267            self.__labels__(subplot, xlabel, ylabel) 
     2268            for id in id_list: 
     2269                subplot.plot(time_axis, self.analog_signals[id].signal, **kwargs) 
     2270                subplot.hold(1) 
     2271            pylab.draw() 
     2272 
     2273 
     2274 
     2275############################################################# 
     2276## Object Loaders. Functions used to create NeuroTools 
     2277## objects from data generated by pyNN (the most simple form 
     2278## supported right now) 
     2279############################################################# 
     2280 
     2281def load_spikelist(filename, id_list=None, dt = None, t_start=None, t_stop=None, dims=None): 
    12772282    """ 
    1278     assert(x.ndim == y.ndim, "Inconsistent shape !") 
    1279 #    assert(x.shape == y.shape, "Inconsistent shape !") 
    1280     if axis is None: 
    1281         if x.ndim > 1: 
    1282             x = x.ravel() 
    1283             y = y.ravel() 
    1284         npad = x.size + y.size 
    1285         xanom = (x - x.mean(axis=None)) 
    1286         yanom = (y - y.mean(axis=None)) 
    1287         Fx = numpy.fft.fft(xanom, npad, ) 
    1288         Fy = numpy.fft.fft(yanom, npad, ) 
    1289         iFxy = numpy.fft.ifft(Fx.conj()*Fy).real 
    1290         varxy = numpy.sqrt(numpy.inner(xanom,xanom) * numpy.inner(yanom,yanom)) 
    1291     else: 
    1292         npad = x.shape[axis] + y.shape[axis] 
    1293         if axis == 1: 
    1294             if x.shape[0] != y.shape[0]: 
    1295                 raise ValueError, "Arrays should have the same length!" 
    1296             xanom = (x - x.mean(axis=1)[:,None]) 
    1297             yanom = (y - y.mean(axis=1)[:,None]) 
    1298             varxy = numpy.sqrt((xanom*xanom).sum(1) * (yanom*yanom).sum(1))[:,None] 
    1299         else: 
    1300             if x.shape[1] != y.shape[1]: 
    1301                 raise ValueError, "Arrays should have the same width!" 
    1302             xanom = (x - x.mean(axis=0)) 
    1303             yanom = (y - y.mean(axis=0)) 
    1304             varxy = numpy.sqrt((xanom*xanom).sum(0) * (yanom*yanom).sum(0)) 
    1305         Fx = numpy.fft.fft(xanom, npad, axis=axis) 
    1306         Fy = numpy.fft.fft(yanom, npad, axis=axis) 
    1307         iFxy = numpy.fft.ifft(Fx.conj()*Fy,n=npad,axis=axis).real 
    1308     # We juste turn the lags into correct positions: 
    1309     iFxy = numpy.concatenate((iFxy[len(iFxy)/2:len(iFxy)],iFxy[0:len(iFxy)/2])) 
    1310     return iFxy/varxy 
    1311  
    1312  
     2283    Returns a SpikeList object from a file. If the file has been generated by PyNN,  
     2284    a header should be found with following parameters: 
     2285     ---> dims, dt, id of the first cell, id of the last cell.  
     2286    They must be specified otherwise.  Then the classical PyNN format for text file is: 
     2287     ---> one line per event:  absolute time in ms, GID 
     2288     
     2289    Inputs: 
     2290        filename - the name of the spike file 
     2291        id_list  - the list of the recorded ids. Can be an int (meaning cells in  
     2292                   the range (0,..,N)), or a list.  
     2293        dims     - if the cells were aranged on a 2/3D grid, a tuple with the dimensions 
     2294        dt       - the discretization step, in ms 
     2295        t_start  - begining of the simulation, in ms. 
     2296        t_stop   - end of the simulation, in ms 
     2297 
     2298    If dims, dt, t_start, t_stop or id_list are None, they will be infered from either  
     2299    the data or from the header. 
     2300    All times are in milliseconds.  
     2301    The format of the file (text, pickle or hdf5) will be inferred automatically 
     2302    """ 
     2303    spike_loader = io.SpikeListIO(filename) 
     2304    return spike_loader.get_spikelist(id_list, dt, t_start, t_stop, dims) 
     2305 
     2306 
     2307 
     2308def load_conductancelist(filename, id_list=None, dt = None, t_start=None, t_stop=None, dims=None): 
     2309    """ 
     2310    Returns a ConductanceList object from a file. If the file has been generated by PyNN,  
     2311    a header should be found with following parameters: 
     2312     ---> dims, dt, id of the first cell, id of the last cell.  
     2313    They must be specified otherwise.  Then the classical PyNN format for text file is: 
     2314     ---> one line per event:  data value, GID 
     2315     
     2316    Inputs: 
     2317        filename - the name of the spike file 
     2318        id_list  - the list of the recorded ids. Can be an int (meaning cells in  
     2319                   the range (0,..,N)), or a list.  
     2320        dims     - if the cells were aranged on a 2/3D grid, a tuple with the dimensions 
     2321        dt       - the discretization step, in ms 
     2322        t_start  - begining of the simulation, in ms. 
     2323        t_stop   - end of the simulation, in ms 
     2324 
     2325    If dims, dt, t_start, t_stop or id_list are None, they will be infered from either  
     2326    the data or from the header. 
     2327    All times are in milliseconds.  
     2328    The format of the file (text, pickle or hdf5) will be inferred automatically 
     2329    """ 
     2330    analogsignal_loader = io.AnalogSignalIO(filename) 
     2331    return analogsignal_loader.get_conductancelist(id_list, dt, t_start, t_stop, dims) 
     2332 
     2333 
     2334def load_vmlist(filename, id_list=None, dt=None, t_start=None, t_stop=None, dims=None): 
     2335    """ 
     2336    Returns a VmList object from a file. If the file has been generated by PyNN,  
     2337    a header should be found with following parameters: 
     2338     ---> dims, dt, id of the first cell, id of the last cell.  
     2339    They must be specified otherwise.  Then the classical PyNN format for text file is: 
     2340     ---> one line per event:  data value, GID 
     2341     
     2342    Inputs: 
     2343        filename - the name of the spike file 
     2344        id_list  - the list of the recorded ids. Can be an int (meaning cells in  
     2345                   the range (0,..,N)), or a list.  
     2346        dims     - if the cells were aranged on a 2/3D grid, a tuple with the dimensions 
     2347        dt       - the discretization step, in ms 
     2348        t_start  - begining of the simulation, in ms. 
     2349        t_stop   - end of the simulation, in ms 
     2350 
     2351    If dims, dt, t_start, t_stop or id_list are None, they will be infered from either  
     2352    the data or from the header. 
     2353    All times are in milliseconds.  
     2354    The format of the file (text, pickle or hdf5) will be inferred automatically 
     2355    """ 
     2356    analogsignal_loader = io.AnalogSignalIO(filename) 
     2357    return analogsignal_loader.get_vmlist(id_list, dt, t_start, t_stop, dims) 
     2358 
     2359 
     2360 
     2361def load_currentlist(filename, id_list=None, dt = None, t_start=None, t_stop=None, dims=None): 
     2362    """ 
     2363    Returns a CurrentList object from a file. If the file has been generated by PyNN,  
     2364    a header should be found with following parameters: 
     2365     ---> dims, dt, id of the first cell, id of the last cell.  
     2366    They must be specified otherwise.  Then the classical PyNN format for text file is: 
     2367     ---> one line per event:  data value, GID 
     2368     
     2369    Inputs: 
     2370        filename - the name of the spike file 
     2371        id_list  - the list of the recorded ids. Can be an int (meaning cells in  
     2372                   the range (0,..,N)), or a list.  
     2373        dims     - if the cells were aranged on a 2/3D grid, a tuple with the dimensions 
     2374        dt       - the discretization step, in ms 
     2375        t_start  - begining of the simulation, in ms. 
     2376        t_stop   - end of the simulation, in ms 
     2377 
     2378    If dims, dt, t_start, t_stop or id_list are None, they will be infered from either  
     2379    the data or from the header. 
     2380    All times are in milliseconds.  
     2381    The format of the file (text, pickle or hdf5) will be inferred automatically 
     2382    """ 
     2383    analogsignal_loader = io.AnalogSignalIO(filename) 
     2384    return analogsignal_loader.get_currentlist(id_list, dt, t_start, t_stop, dims) 
    13132385 
    13142386