| 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) |
| 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 | #################################################################### |
| 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 |
| | 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) |
| 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): |
| 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 | |
| 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 | |
| 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) |
| 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]) |
| 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 |
| 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) |
| 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) |
| 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 | |
| | 1867 | class AnalogSignal(object): |
| 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 | | |
| 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 | |
| | 2174 | class 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 | |
| | 2211 | class 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 | |
| | 2242 | class 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 | |
| | 2281 | def load_spikelist(filename, id_list=None, dt = None, t_start=None, t_stop=None, dims=None): |
| 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 | |
| | 2308 | def 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 | |
| | 2334 | def 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 | |
| | 2361 | def 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) |