def show_isi_stats(self, mesg='', run_len=[], tr=0, rest_file=''): """display ISI timing statistics mesg : display the user message first run_len : can be empty, length 1 or length nrows tr : if > 0: show mean/stdev for stimuli within TRs (so 0 <= mean < tr) rest_file : if set, save all rest durations display these statistics: - total time, total stim time, total rest time - total time per run - total stim time per run - total rest time per run - pre-stim rest per run - post-stim response rest per run (if run_len is given) - total ISI rest per run - min/mean/max (stdev) of stim duration - min/mean/max (stdev) of ISI rest """ if not self.ready: print '** M Timing: nothing to compute ISI stats from' return 1 if not (self.mtype & LD.MTYPE_DUR): print '** warning: computing stats without duration' if self.nrows != len(self.data): print '** bad MTiming, nrows=%d, datalen=%d, failing...' % \ (self.nrows, len(self.data)) return 1 # make a sorted copy scopy = self.copy() scopy.sort() # make a copy of format run x stim x [start,end], i.e. is 3-D tdata = scopy.get_start_end_timing() # make an updated run lengths list if len(run_len) == 0: rlens = [0 for rind in range(self.nrows)] elif len(run_len) == 1: rlens = [run_len[0] for rind in range(self.nrows)] elif len(run_len) == self.nrows: rlens = run_len else: # failure print '** invalid len(run_len)=%d, must be one of 0,1,%d' % \ (len(run_len), self.nrows) return 1 if self.verb > 1: print '-- show_isi_stats, run_len = %s, tr = %s, rest_file = %s' \ % (run_len, tr, rest_file) if self.verb > 3: print scopy.make_data_string(nplaces=1, flag_empty=0, check_simple=0, mesg='scopy data') all_stim = [] # all stimulus durations (one row per run) all_isi = [] # all isi times (one row per run) pre_time = [] # pre-stim, per run post_time = [] # pose-stim, per run run_time = [] # total run time, per run errs = 0 # allow a few errors before failing max_errs = 10 for rind in range(self.nrows): run = tdata[rind] rlen = rlens[rind] if len(run) == 0: # empty run all_stim.append([]) all_isi.append([]) pre_time.append(rlen) post_time.append(0.0) run_time.append(rlen) continue # if no run len specified, use end of last stimulus if rlen == 0.0: rlen = run[-1][1] elif rlen < run[-1][1]: print '** run %d: given length = %s, last stim ends at %s' % \ (rind+1, rlen, run[-1][1]) errs += 1 if errs > max_errs: print '** bailing...' return 1 # pre- and post-stim times are set pre = run[0][0] post = rlen - run[-1][1] if pre < 0: print '** ISI error: first stimulus of run %d at negative time %s'%\ (rind+1, run[0][0]) errs += 1 if errs > max_errs: print '** bailing...' return 1 # init accumulation vars stimes = [run[0][1] - run[0][0]] itimes = [] # for each following index, update stim and isi times # (check for bad overlap) for sind in range(1, len(run)): if run[sind][0] < run[sind-1][1]: print '** ISI error: stimuli overlap at run %d, time %s' % \ (rind+1, run[sind][0]) errs += 1 if errs > max_errs: print '** bailing...' return 1 stimes.append(run[sind][1]-run[sind][0]) itimes.append(run[sind][0]-run[sind-1][1]) # store results all_stim.append(stimes) all_isi.append(itimes) pre_time.append(pre) post_time.append(post) run_time.append(rlen) if errs > 0: return 1 # tally the results rtot_stim = [] ; rtot_isi = [] ; rtot_rest = [] stim_list = [] ; isi_list = [] ; nstim_list = [] for rind in range(self.nrows): rtot_stim.append(UTIL.loc_sum(all_stim[rind])) rtot_rest.append(pre_time[rind] + UTIL.loc_sum(all_isi[rind]) + post_time[rind]) rtot_isi.append(UTIL.loc_sum(all_isi[rind])) stim_list.extend(all_stim[rind]) isi_list.extend(all_isi[rind]) nstim_list.append(len(all_stim[rind])) if mesg: mstr = '(%s) ' % mesg else: mstr = '' print '\nISI statistics %s:\n' % mstr print ' total per run' print ' ------ ------------------------------' print ' total time %6.1f %s' % \ (UTIL.loc_sum(run_time), float_list_string(run_time, ndec=1)) print ' total time: stim %6.1f %s' % \ (UTIL.loc_sum(rtot_stim),float_list_string(rtot_stim,7,ndec=1)) print ' total time: rest %6.1f %s' % \ (UTIL.loc_sum(rtot_rest),float_list_string(rtot_rest,7,ndec=1)) print '' print ' rest: total isi %6.1f %s' % \ (UTIL.loc_sum(rtot_isi), float_list_string(rtot_isi,7,ndec=1)) print ' rest: pre stim %6.1f %s' % \ (UTIL.loc_sum(pre_time), float_list_string(pre_time,7,ndec=1)) print ' rest: post stim %6.1f %s' % \ (UTIL.loc_sum(post_time),float_list_string(post_time,7,ndec=1)) print '' print ' num stimuli %6d %s' % \ (UTIL.loc_sum(nstim_list), float_list_string(nstim_list,7,ndec=0)) print '\n' print ' min mean max stdev' print ' ------- ------- ------- -------' print ' rest: pre-stim %7.3f %7.3f %7.3f %7.3f' % \ (UTIL.min_mean_max_stdev(pre_time)) print ' rest: post-stim %7.3f %7.3f %7.3f %7.3f' % \ (UTIL.min_mean_max_stdev(post_time)) print '' for ind in range(self.nrows): m0, m1, m2, s = UTIL.min_mean_max_stdev(all_isi[ind]) print ' rest: run #%d ISI %7.3f %7.3f %7.3f %7.3f' % \ (ind, m0, m1, m2, s) print '' print ' all runs: ISI %7.3f %7.3f %7.3f %7.3f' % \ (UTIL.min_mean_max_stdev(isi_list)) print ' all runs: stimuli %7.3f %7.3f %7.3f %7.3f' % \ (UTIL.min_mean_max_stdev(stim_list)) print '' # and possibly print out offset info if tr > 0: self.show_TR_offset_stats(tr, '') # maybe write all rest durations if rest_file: all_rest = copy.deepcopy(all_isi) for run, rest in enumerate(all_rest): rest[:0] = [pre_time[run]] rest.append(post_time[run]) UTIL.write_to_timing_file(all_rest, rest_file) # clean up, just to be kind del(all_stim); del(all_isi); del(pre_time); del(post_time); del(run_time) del(rtot_stim); del(rtot_isi); del(rtot_rest); del(stim_list) del(isi_list); del(nstim_list) del(scopy) del(tdata)
def show_isi_stats(self, mesg='', run_len=[], tr=0, rest_file=''): """display ISI timing statistics mesg : display the user message first run_len : can be empty, length 1 or length nrows tr : if > 0: show mean/stdev for stimuli within TRs (so 0 <= mean < tr) rest_file : if set, save all rest durations display these statistics: - total time, total stim time, total rest time - total time per run - total stim time per run - total rest time per run - pre-stim rest per run - post-stim response rest per run (if run_len is given) - total ISI rest per run - min/mean/max (stdev) of stim duration - min/mean/max (stdev) of ISI rest """ if not self.ready: print '** M Timing: nothing to compute ISI stats from' return 1 if not (self.mtype & LD.MTYPE_DUR): print '** warning: computing stats without duration' if self.nrows != len(self.data): print '** bad MTiming, nrows=%d, datalen=%d, failing...' % \ (self.nrows, len(self.data)) return 1 # make a sorted copy scopy = self.copy() scopy.sort() # make a copy of format run x stim x [start,end], i.e. is 3-D tdata = scopy.get_start_end_timing() # make an updated run lengths list if len(run_len) == 0: rlens = [0 for rind in range(self.nrows)] elif len(run_len) == 1: rlens = [run_len[0] for rind in range(self.nrows)] elif len(run_len) == self.nrows: rlens = run_len else: # failure print '** invalid len(run_len)=%d, must be one of 0,1,%d' % \ (len(run_len), self.nrows) return 1 if self.verb > 1: print '-- show_isi_stats, run_len = %s, tr = %s, rest_file = %s' \ % (run_len, tr, rest_file) if self.verb > 3: print scopy.make_data_string(nplaces=1, flag_empty=0, check_simple=0, mesg='scopy data') all_stim = [] # all stimulus durations (one row per run) all_isi = [] # all isi times (one row per run) pre_time = [] # pre-stim, per run post_time = [] # pose-stim, per run run_time = [] # total run time, per run errs = 0 # allow a few errors before failing max_errs = 10 for rind in range(self.nrows): run = tdata[rind] rlen = rlens[rind] if len(run) == 0: # empty run all_stim.append([]) all_isi.append([]) pre_time.append(rlen) post_time.append(0.0) run_time.append(rlen) continue # if no run len specified, use end of last stimulus if rlen == 0.0: rlen = run[-1][1] elif rlen < run[-1][1]: print '** run %d: given length = %s, last stim ends at %s' % \ (rind+1, rlen, run[-1][1]) errs += 1 if errs > max_errs: print '** bailing...' return 1 # pre- and post-stim times are set pre = run[0][0] post = rlen - run[-1][1] if pre < 0: print '** ISI error: first stimulus of run %d at negative time %s'%\ (rind+1, run[0][0]) errs += 1 if errs > max_errs: print '** bailing...' return 1 # init accumulation vars stimes = [run[0][1] - run[0][0]] itimes = [] # for each following index, update stim and isi times # (check for bad overlap) for sind in range(1, len(run)): if run[sind][0] < run[sind - 1][1]: print '** ISI error: stimuli overlap at run %d, time %s' % \ (rind+1, run[sind][0]) errs += 1 if errs > max_errs: print '** bailing...' return 1 stimes.append(run[sind][1] - run[sind][0]) itimes.append(run[sind][0] - run[sind - 1][1]) # store results all_stim.append(stimes) all_isi.append(itimes) pre_time.append(pre) post_time.append(post) run_time.append(rlen) if errs > 0: return 1 # tally the results rtot_stim = [] rtot_isi = [] rtot_rest = [] stim_list = [] isi_list = [] nstim_list = [] for rind in range(self.nrows): rtot_stim.append(UTIL.loc_sum(all_stim[rind])) rtot_rest.append(pre_time[rind] + UTIL.loc_sum(all_isi[rind]) + post_time[rind]) rtot_isi.append(UTIL.loc_sum(all_isi[rind])) stim_list.extend(all_stim[rind]) isi_list.extend(all_isi[rind]) nstim_list.append(len(all_stim[rind])) if mesg: mstr = '(%s) ' % mesg else: mstr = '' print '\nISI statistics %s:\n' % mstr print ' total per run' print ' ------ ------------------------------' print ' total time %6.1f %s' % \ (UTIL.loc_sum(run_time), float_list_string(run_time, ndec=1)) print ' total time: stim %6.1f %s' % \ (UTIL.loc_sum(rtot_stim),float_list_string(rtot_stim,7,ndec=1)) print ' total time: rest %6.1f %s' % \ (UTIL.loc_sum(rtot_rest),float_list_string(rtot_rest,7,ndec=1)) print '' print ' rest: total isi %6.1f %s' % \ (UTIL.loc_sum(rtot_isi), float_list_string(rtot_isi,7,ndec=1)) print ' rest: pre stim %6.1f %s' % \ (UTIL.loc_sum(pre_time), float_list_string(pre_time,7,ndec=1)) print ' rest: post stim %6.1f %s' % \ (UTIL.loc_sum(post_time),float_list_string(post_time,7,ndec=1)) print '' print ' num stimuli %6d %s' % \ (UTIL.loc_sum(nstim_list), float_list_string(nstim_list,7,ndec=0)) print '\n' print ' min mean max stdev' print ' ------- ------- ------- -------' print ' rest: pre-stim %7.3f %7.3f %7.3f %7.3f' % \ (UTIL.min_mean_max_stdev(pre_time)) print ' rest: post-stim %7.3f %7.3f %7.3f %7.3f' % \ (UTIL.min_mean_max_stdev(post_time)) print '' for ind in range(self.nrows): m0, m1, m2, s = UTIL.min_mean_max_stdev(all_isi[ind]) print ' rest: run #%d ISI %7.3f %7.3f %7.3f %7.3f' % \ (ind, m0, m1, m2, s) print '' print ' all runs: ISI %7.3f %7.3f %7.3f %7.3f' % \ (UTIL.min_mean_max_stdev(isi_list)) print ' all runs: stimuli %7.3f %7.3f %7.3f %7.3f' % \ (UTIL.min_mean_max_stdev(stim_list)) print '' # and possibly print out offset info if tr > 0: self.show_TR_offset_stats(tr, '') # maybe write all rest durations if rest_file: all_rest = copy.deepcopy(all_isi) for run, rest in enumerate(all_rest): rest[:0] = [pre_time[run]] rest.append(post_time[run]) UTIL.write_to_timing_file(all_rest, rest_file) # clean up, just to be kind del (all_stim) del (all_isi) del (pre_time) del (post_time) del (run_time) del (rtot_stim) del (rtot_isi) del (rtot_rest) del (stim_list) del (isi_list) del (nstim_list) del (scopy) del (tdata)