class DataStoreLocator(object): def __init__(self, path, glob='*', delta=timedelta(180)): self.path = Path(path).resolve() self.glob = glob self.delta = delta self.now = datetime.now() def item_is_within(self, item): return self.now - datetime.fromtimestamp( item.stat().st_ctime) < self.delta @property def items_within(self): return (item for item in self.path.glob(self.glob) if self.item_is_within(item)) @property def rendered(self): sbxs, dirs = [], [] for item in self.items_within: if item.is_dir() and not item.suffix == '.io': dirs.append(self.render_dir(item)) elif item.is_file() and item.suffix == '.sbx' and item.with_suffix( '.mat').is_file(): sbxs.append(self.render_sbx(item)) return dict(sbxs=sbxs, dirs=dirs) def render_dir(self, item): return dict(name=item.name, ctime=item.stat().st_ctime) def render_sbx(self, item): return dict(name=item.stem, ctime=item.stat().st_ctime, path=item.str, size=item.size.str)
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()