class ScanimageIO(object): session_name = 'main' r_value = 0.7 def __init__(self, path): # wself.path = Path(str(path) + '.imported') if '.imported' in str(path): self.path = Path(path) else: self.path = Path(str(path) + '.imported') @classmethod def get_record(cls, rec_path): return ScanimageRecord(rec_path) @property def exists(self): return self.path.is_dir() @memoized_property def tiff(self): tiffpath = self.path.with_suffix('.tif') print 'Import from {}...Please allow a few minutes.'.format( tiffpath.name) return tifffile.imread(tiffpath.str) def import_raw(self): if self.exists: return False nchan = util.infer_nchannels(self.tiff) if nchan: self.create_package_path() self.convert_channels(nchan) else: print 'Unable to import data.' print 'Import done!' return self.toDict() def create_package_path(self): self.path.mkdir() print 'Path `{}` created.'.format(self.path.str) def remove_package(self): shutil.rmtree(self.path.str) return self.toDict() def convert_channels(self, nchan): for index in range(nchan): self.convert_channel(nchan, index) def convert_channel(self, nchan, chan): tiff = self.tiff[chan::nchan] print 'Converting channel {}...({} frames.)'.format(chan, len(tiff)) return getattr(self, 'ch{}'.format(chan)).import_raw(tiff) def toDict(self): return dict(exists=self.exists, path=self.path.str, sessions=self.sessions) @memoized_property def ch0(self): return ScanimageChannel(self.path.joinpath('ch0')) @memoized_property def ch1(self): return ScanimageChannel(self.path.joinpath('ch1')) @memoized_property def channel(self): chan = self.session.opt.setdefault('channel', 0) return getattr(self, 'ch{}'.format(chan)) @channel.invalidator def set_channel(self, channel): self.session.opt['channel'] = channel return self @property def nchannel(self): return len(list(self.path.glob('ch?.mmap.npy'))) @property def channel_numbers(self): return list(range(self.nchannel)) @property def channel_number(self): return self.session.opt['channel'] colormap_index = 0 colormaps = ['jet', 'gray', 'gist_heat', 'afmhot', 'bone'] @property def has_blank_and_flicker(self): if self.db: rec = self.db.rec return [rec.blankOn, rec.flickerOn] else: return [None, None] @property def sfrequency(self): return self.db.locator.sfrequencies.current if self.db else '' # return self.session.opt.setdefault(# 'sfrequency', ) @property def sfrequency_index(self): return self.sfrequencies.index( self.sfrequency) if self.sfrequency else 0 @property def sfrequencies(self): return self.db.locator.sfrequencies if self.db else [] @property def orientations(self): return self.db.orientations if self.db else [] # @sfrequency.invalidator def set_sfrequency_index(self, sfreq_index): self.sfrequencies.set_cursor(sfreq_index) self.session.opt['sfrequency'] = self.sfrequencies.current self.session.opt.save() return dict(index=sfreq_index, value=self.sfrequency) @memoized_property def db(self): return ScanimageDBAdaptor(self.session.ed) if self.session.ed else None @property def main_response(self): return MainResponse.from_adaptor(self.channel.stat.MEAN, self.db) @property def sessions(self): return map(ScanimageSession, sorted(self.path.ls('*.session'))) @memoized_property def session(self): return ScanimageSession( self.path.joinpath(self.session_name).with_suffix('.session')) @session.invalidator def set_session(self, session_name): self.session_name = session_name return self def upsert_roi(self, roi_kwargs): gp = validate_guess_params(roi_kwargs.pop('guessParams', {})) return self.session.roi.upsert(ROI(guess_params=gp, **roi_kwargs)) def invalidate_rois(self): for roi in self.session.roi.values(): roi.invalidated = True roi.blank = None roi.flicker = None roi.responses = {} def export_sfreqfit_data_as_mat(self, rid): roi = self.session.roi[rid] sio = StringIO() value = roi.sfreqfit.toDict() io.savemat(sio, value) return sio.getvalue() def update_responses(self, id, heavy=False): roi = self.session.roi[id] trace = self.make_trace(roi) if self.session.ed: with self.session.roi.bulk_on: try: if self.db.locator.override_blank(True): roi.blank = Orientation.from_adaptor( 'blank', trace, self.db) if self.db.locator.override_flicker(True): roi.flicker = Orientation.from_adaptor( 'flicker', trace, self.db) finally: self.db.locator.override() for sf in self.db.locator.sfrequencies.loop(): response = ROIResponse.from_adaptor(roi, trace, self.db) roi.responses[self.sfrequency] = response roi.update_with_adaptor(self.db) for sf, resp in roi.sorted_responses: gp = roi.guess_params.get(sf) or resp.sog_initial_guess print 'SoG custom guess for {}: {}'.format(sf, gp) resp.update_fit_and_decay(roi, self.db, gp, heavy) p_value = roi.anova_all.get('p') if heavy: if p_value < 0.01: print('Computing bootstrap for preferred SF') # '{} conditions...').format( # len(self.db.orientations) * len(self.db.sfrequencies)) roi.update_bootstrap_for_sf(self.db) peaksf = roi.sfreqfit.peak_sfreq.x peak_resp = roi.responses[peaksf] print 'Determine peak spatial frequency: {}'.format( peaksf) peak_resp.bootstrap = BootstrapResponse.from_adaptor( peak_resp, self.db) else: print( 'P value is not less than 0.01. ({}) ' 'Skip bootstrap.').format(p_value) roi.invalidated = False print 'Done updating response for ROI ' + str(roi.id) print ' ' print ' ' return self.session.roi.upsert(roi) else: response = ROIResponse.from_scanbox(roi, trace) roi.responses[self.sfrequency] = response roi.update_with_adaptor(self.db) roi.invalidated = False return self.session.roi.upsert(roi) sog_initial_guess = ((0, 1), (0, 1), (15, 60), (0, 0.01)) def make_delta_trace(self, roi, trace, dx=0, dy=0): extras = self.session.roi.values() extras.remove(roi) main_trace, main_mask = roi.trace(trace, dx, dy) neur_trace, neur_mask = roi.neuropil_trace(trace, extras, dx, dy) return main_trace - neur_trace * self.r_value def make_trace(self, roi, old=False): # checked same function if old: # print 'no centroid yet...perform old' extras = self.session.roi.values() extras.remove(roi) main_trace, main_mask = roi.trace(self.channel.mmap) neur_trace, neur_mask = roi.neuropil_trace(self.channel.mmap, extras) # neuropil_mask, roi_mask = roi.trim_bounding_mask(neur_mask, main_mask) # roi.masks = dict( # neuripil = neuropil_mask.tolist(), # roi = roi_mask.tolist()) return main_trace - neur_trace * self.r_value else: # print 'has centroid...perform new' vecs = roi.split_by_vectors(len(self.channel.mmap)) traces = np.split(self.channel.mmap, vecs.index[1:]) return np.concatenate([ self.make_delta_trace(roi, trace, dx, dy) for dx, dy, trace in zip(vecs.x, vecs.y, traces) ]) def export_plots(self, id): roi = self.session.roi[id] return roi.export_plots_as_zip_for_download()
class TrajectoryIO(object): session_name = 'main' def __init__(self, path): self.path = Path(path).merge_or_join_suffix('.imported', on='.tif') @property def exists(self): return self.path.is_dir() @property def as_record(self): return dict(name=self.tiffpath.name, user='******', time=self.datetime.strftime('%H:%M:%S'), host='IOS', desc=self.desc, mouse='Mouse 3', package=self) @property def desc(self): return '{}'.format(tifffile.format_size(self.tiffpath.stat().st_size)) @property def datetime(self): return datetime.fromtimestamp(float(self.tiffpath.stem)) @property def tiffpath(self): return self.path.with_suffix('.tif') def toDict(self): return dict(exists=self.exists, path=self.path.str, sessions=self.sessions) @memoized_property def tiff(self): tiffpath = self.path.with_suffix('.tif') file_size = tiffpath.lstat().st_size print 'Import from {}...'.format(tiffpath) print 'File size {:,} bytes.'.format(file_size) return tifffile.imread(tiffpath.str) def import_raw(self): if self.exists: return False self.create_package_path() print 'Looking for matching VR log file...' log = TrajectoryLog.query(self.datetime) # it can fail but never reports. print 'Converting channel and timestamps...' tss = np.fromfile(self.path.with_suffix('.csv').str, sep='\n', dtype='float64') TrajectoryChannel(self.path.joinpath('channel')).import_raw( self.tiff, tss, log) print 'Import done!' return self.toDict() def create_package_path(self): self.path.mkdir() print 'Path `{}` created.'.format(self.path.str) def remove_package(self): shutil.rmtree(self.path.str) return self.toDict() @memoized_property def channel(self): tfilter = self.session.opt.get('filter') if tfilter: if tfilter._indices is not None: return TrajectoryChannel( self.path.joinpath('channel')).set_indices( tfilter._indices) return TrajectoryChannel(self.path.joinpath('channel')) @property def sessions(self): return map(TrajectorySession, sorted(self.path.ls('*.session'))) @memoized_property def session(self): return TrajectorySession( self.path.joinpath(self.session_name).with_suffix('.session')) @session.invalidator def set_session(self, session_name): self.session_name = session_name return self @memoized_property def alog(self): # aligned log in JSON format return [ dict(e=e, x=x, y=y, v=v) for e, x, y, v in self.channel.alog[['E', 'X', 'Y', 'V']] ] @property def main_response(self): return TrajectoryResponse(self.channel.stat.MEAN) def upsert_roi(self, roi_kwargs): return self.session.roi.upsert(ROI(**roi_kwargs)) def upsert_filter(self, filter_kwargs): tfilter = TrajectoryFilter(**filter_kwargs) tfilter._indices = tfilter.make_indices(self.channel.original_velocity) rv = self.session.opt.upsert(tfilter) for roi in self.session.roi.values(): roi.invalidated = True self.session.roi.save() return rv def make_response(self, id): roi = self.session.roi[id] extras = self.session.roi.values() extras.remove(roi) main_trace, main_mask = roi.trace(self.channel.mmap) neur_trace, neur_mask = roi.neuropil_trace(self.channel.mmap, extras) trace = main_trace - neur_trace * 0.7 roi.invalidated = False roi.response = TrajectoryResponse(trace) return self.session.roi.upsert(roi) @memoized_property def velocity_stat(self): return dict( max=self.channel.alog.V.max(), mean=self.channel.alog.V.mean(), min=self.channel.alog.V.min(), )