def StimulusTiming(filename='.', ind=None, channels=0, trigger='StimulusCode > 0', msec=300, offset_msec=0, rectify=False, threshold=0.1, use_eo=False, save=None, **kwargs): """ In <filename> and <ind>, give it - a directory and ind=None: for all .dat files in the directory, in session/run order - a directory and ind=an index or list of indices: for selected .dat files in the directory - a dat-file name and ind=anything: for that particular file - a list of filenames and ind=anything: for certain explicitly-specified files <channels> may be a 0-based index, list of indices, list of channel names, or space- or comma- delimited string of channel names <rectify> subtracts the median and takes the abs before doing anything else <threshold> is on the normalized scale of min=0, max=1 within the resulting image <use_eo> uses the EventOffset state to correct timings """### if hasattr(filename, 'filename'): filename = filename.filename if ind == None: ind = -1 if os.path.isdir(filename): filename = ListDatFiles(filename) if not isinstance(filename, (tuple, list)): filename = [filename] if not isinstance(ind, (tuple, list)): ind = [ind] n = max(len(filename), len(ind)) if len(filename) == 1: filename = list(filename) * n if len(ind) == 1: ind = list(ind) * n if isinstance(channels, str): channels = channels.replace(',', ' ').split() if not isinstance(channels, (tuple, list)): channels = [channels] out = [ SigTools.sstruct( files=[], events=[], t=None, channel=ch, img=[], edges=[], threshold=None, EventOffsets=[], UseEventOffsets=False, ) for ch in channels ] if len(filename) == 0: raise ValueError("no data files specified") for f, i in zip(filename, ind): b = bcistream(filename=f, ind=i) nsamp = b.msec2samples(msec) nsamp_offset = b.msec2samples(offset_msec) sig, st = b.decode('all') statenames = list(zip(*sorted([(-len(x), x) for x in st])))[1] criterion = trigger for x in statenames: criterion = criterion.replace(x, "st['%s']" % x) criterion = numpy.asarray(eval(criterion)).flatten() startind = SigTools.edges(criterion) print("%d events found in %s" % (len(startind), b.filename)) for s in out: s.files.append(b.filename) s.events.append(len(startind)) ch = s.channel if isinstance(ch, str): chn = [x.lower() for x in b.params['ChannelNames']] if ch.lower() in chn: ch = chn.index(ch.lower()) else: raise ValueError("could not find channel %s in %s" % (ch, b.filename)) if len(b.params['ChannelNames']) == len(sig): s.channel = b.params['ChannelNames'][ch] xx = numpy.asarray(sig)[ch] if rectify: xx = numpy.abs(xx - numpy.median(xx)) xx -= xx.min() if xx.max(): xx /= xx.max() s.threshold = threshold for ind in startind: if 'EventOffset' in st: eo = st['EventOffset'].flat[ind] if use_eo: ind += eo - 2**(b.statedefs['EventOffset']['length'] - 1) s.UseEventOffsets = True else: eo = 0 s.EventOffsets.append(eo) x = xx[ind + nsamp_offset:ind + nsamp_offset + nsamp].tolist() x += [0.0] * (nsamp - len(x)) s.img.append(x) for s in out: s.img = numpy.asarray(s.img) s.edges = [ min(list(x.nonzero()[0]) + [numpy.nan]) for x in (s.img > s.threshold) ] s.edges = b.samples2msec(numpy.asarray(s.edges + nsamp_offset)) s.t = b.samples2msec(numpy.arange(nsamp_offset, nsamp_offset + nsamp)) import pylab pylab.clf() ax = None for i, s in enumerate(out): ax = pylab.subplot(1, len(out), i + 1, sharex=ax, sharey=ax) y = y = list(range(1, len(s.img) + 1)) SigTools.imagesc(s.img, x=s.t, y=y, aspect='auto', **kwargs) xl, yl = pylab.xlim(), pylab.ylim() pylab.plot(s.edges, y, 'w*', markersize=10) for j, x in enumerate(s.edges.flat): if not numpy.isnan(x): pylab.text(x, y[j], str(y[j]) + '---', ha='right', va='center', color='#00FF00', clip_on=True) pylab.xlim(xl) pylab.ylim(yl) pylab.grid('on') #pylab.ylim([len(s.img)+0.5,0.5]) # this corrupts the image!! pylab.draw() if save: pylab.gcf().savefig(save, orientation='portrait') return out