def _create_mock_atlas(): """ Instantiates a mock atlas.BrainAtlas for testing purposes mimicking Allen Atlas using the IBL Bregma and coordinate system """ ba = AllenAtlas(res_um=25, mock=True) X, Y = np.meshgrid(ba.bc.xscale, ba.bc.yscale) top = X**2 + Y**2 ba.top = (top - np.min(top)) / (np.max(top) - np.min(top)) * .001 return ba
def __init__(self, qmain: TopView, res=25): super(Controller, self).__init__(qmain) self.atlas = AllenAtlas(res) self.fig_top = self.qwidget = qmain # Setup Coronal slice: width: ml, height: dv, depth: ap self.fig_coronal = SliceView(qmain, waxis=0, haxis=2, daxis=1) self.fig_coronal.setWindowTitle('Coronal Slice') self.set_slice(self.fig_coronal) self.fig_coronal.show() # Setup Sagittal slice: width: ap, height: dv, depth: ml self.fig_sagittal = SliceView(qmain, waxis=1, haxis=2, daxis=0) self.fig_sagittal.setWindowTitle('Sagittal Slice') self.set_slice(self.fig_sagittal) self.fig_sagittal.show()
def __init__(self, probe_id, one=None, brain_atlas=None, channels=True, collection=None): super().__init__(probe_id, one=one, log=_log, endpoint='insertions') # Data self.alignments = None self.xyz_picks = None self.depths = None self.cluster_chns = None self.chn_coords = None self.align_keys_sorted = None # Metrics and passed trials self.sim_matrix = None self.criteria = CRITERIA # Get the brain atlas self.brain_atlas = brain_atlas or AllenAtlas(25) # Flag for uploading channels to alyx. For testing purposes self.channels_flag = channels self.insertion = self.one.alyx.get(f'/insertions/{self.eid}', clobber=True) self.resolved = (self.insertion.get('json', {'temp': 0}).get('extended_qc'). get('alignment_resolved', False)) self.probe_collection = collection
def get_aligned_channels(ins, chn_coords, one, ba=None, save_dir=None): ba = ba or AllenAtlas(25) depths = chn_coords[:, 1] xyz = np.array(ins['json']['xyz_picks']) / 1e6 traj = one.alyx.rest('trajectories', 'list', probe_insertion=ins['id'], provenance='Ephys aligned histology track')[0] align_key = ins['json']['extended_qc']['alignment_stored'] feature = traj['json'][align_key][0] track = traj['json'][align_key][1] ephysalign = EphysAlignment(xyz, depths, track_prev=track, feature_prev=feature, brain_atlas=ba, speedy=True) channels_mlapdv = np.int32(ephysalign.get_channel_locations(feature, track) * 1e6) channels_atlas_ids = ephysalign.get_brain_locations(channels_mlapdv / 1e6)['id'] out_files = [] if save_dir is not None: f_name = Path(save_dir).joinpath('channels.mlapdv.npy') np.save(f_name, channels_mlapdv) out_files.append(f_name) f_name = Path(save_dir).joinpath('channels.brainLocationIds_ccf_2017.npy') np.save(f_name, channels_atlas_ids) out_files.append(f_name) return out_files
def get_channels(self, alf_object, collection): electrodes = {} try: electrodes = self.one.load_object(self.eid, alf_object, collection=collection) electrodes['axial_um'] = electrodes['localCoordinates'][:, 1] except ALFObjectNotFound: _logger.warning(f'{alf_object} does not yet exist') if self.hist_lookup[self.histology_status] == 3: try: electrodes['atlas_id'] = electrodes['brainLocationIds_ccf_2017'] electrodes['mlapdv'] = electrodes['mlapdv'] / 1e6 except KeyError: _logger.warning('Insertion resolved but brainLocationIds_ccf_2017 attribute do not exist') if self.hist_lookup[self.histology_status] > 0 and 'atlas_id' not in electrodes.keys(): if not self.brain_atlas: self.brain_atlas = AllenAtlas() self.brain_regions = self.brain_regions or self.brain_atlas.regions if 'localCoordinates' not in electrodes.keys(): geometry = trace_header(version=1) electrodes['localCoordinates'] = np.c_[geometry['x'], geometry['y']] electrodes['axial_um'] = electrodes['localCoordinates'][:, 1] depths = electrodes['localCoordinates'][:, 1] xyz = np.array(self.ins['json']['xyz_picks']) / 1e6 if self.hist_lookup[self.histology_status] >= 2: traj = self.one.alyx.rest('trajectories', 'list', provenance='Ephys aligned histology track', probe_insertion=self.pid)[0] align_key = self.ins['json']['extended_qc']['alignment_stored'] feature = traj['json'][align_key][0] track = traj['json'][align_key][1] ephysalign = EphysAlignment(xyz, depths, track_prev=track, feature_prev=feature, brain_atlas=self.brain_atlas, speedy=True) electrodes['mlapdv'] = ephysalign.get_channel_locations(feature, track) electrodes['atlas_id'] = self.brain_atlas.regions.get(self.brain_atlas.get_labels(electrodes['mlapdv']))['id'] if self.hist_lookup[self.histology_status] == 1: xyz = xyz[np.argsort(xyz[:, 2]), :] electrodes['mlapdv'] = interpolate_along_track(xyz, (depths + TIP_SIZE_UM) / 1e6) electrodes['atlas_id'] = self.brain_atlas.regions.get(self.brain_atlas.get_labels(electrodes['mlapdv']))['id'] return electrodes
def _load_brain_regions(eid, probe_idx=0): one = ONE() ba = AllenAtlas() probe = 'probe0%d' % probe_idx ins = one.alyx.rest('insertions', 'list', session=eid, name=probe)[0] xyz_chans = load_channels_from_insertion(ins, depths=SITES_COORDINATES[:, 1], one=one, ba=ba) region, region_label, region_color, _ = EphysAlignment.get_histology_regions( xyz_chans, SITES_COORDINATES[:, 1], brain_atlas=ba) return region, region_label, region_color
def compute_volume_from_points(xyz, values=None, aggr='sum', fwhm=100, ba=None): """ Creates a 3D volume with xyz points placed in corresponding voxel in volume. Points that fall into the same voxel within the volume are aggregated according to the method specified in aggr. Gaussian smoothing with a 3D kernel with distance specified by fwhm (full width half max) argument is applied. If fwhm = 0, no gaussian smoothing is applied. :param xyz: 3 column array of xyz coordinates of points in metres :param values: 1 column array of values per xyz coordinates, if no values are given the sum of xyz points in each voxel is returned :param aggr: aggregation method. Options are sum, count, mean, std, median, min and max. Can also give in custom function (https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.binned_statistic.html) :param fwhm: full width at half maximum of gaussian kernel in um :param ba: AllenAtlas object :return: """ ba = ba or AllenAtlas() idx = ba._lookup(xyz) ba_shape = ba.image.shape[0] * ba.image.shape[1] * ba.image.shape[2] if values is not None: volume = binned_statistic(idx, values, range=[0, ba_shape], statistic=aggr, bins=ba_shape).statistic volume[np.isnan(volume)] = 0 else: volume = np.bincount(idx, minlength=ba_shape, weights=values) volume = volume.reshape(ba.image.shape[0], ba.image.shape[1], ba.image.shape[2]).astype(np.float32) if fwhm > 0: # Compute sigma used for gaussian kernel fwhm_over_sigma_ratio = np.sqrt(8 * np.log(2)) sigma = fwhm / (fwhm_over_sigma_ratio * ba.res_um) # TODO to speed up only apply gaussian filter on slices within distance of chosen coordinate volume = gaussian_filter(volume, sigma=sigma) # Mask so that outside of the brain is set to nan volume[ba.label == 0] = np.nan return volume
def __init__(self, one=None, ba=None, lazy=False): self.one = one or ONE() self.ba = ba or AllenAtlas(25) self.traj = {'Planned': {}, 'Micro-manipulator': {}, 'Histology track': {}, 'Ephys aligned histology track': {}, 'Resolved': {}, 'Best': {}} self.ins = {} self.cvol = None self.cvol_flat = None self.initialised = False if not lazy: self.initialise()
def save_coverage(): from oneibl.one import ONE from ibllib.pipes.histology import coverage from ibllib.atlas import AllenAtlas ba = AllenAtlas() one = ONE() trajs = one.alyx.rest( 'trajectories', 'list', django= ('provenance,70,' 'probe_insertion__session__project__name__icontains,ibl_neuropixel_brainwide_01,' 'probe_insertion__session__qc__lt,50,' 'probe_insertion__json__extended_qc__alignment_count__gt,0,' 'probe_insertion__session__extended_qc__behavior,1')) vol = coverage(trajs=trajs, ba=ba) vol[np.isnan(vol)] = 0 np.save('coverage.npy', vol)
def test_simple(): self = AllenAtlas(25) # extracts the top surface from the volume and make sure it's all populated ix, iy = np.meshgrid(np.arange(self.bc.nx), np.arange(self.bc.ny)) iz = self.bc.z2i(self.top) inds = self._lookup_inds(np.stack((ix, iy, iz), axis=-1)) assert np.all(self.label.flat[inds][~np.isnan(self.top)] != 0) # one sample above, it's all zeros inds = self._lookup_inds(np.stack((ix, iy, np.maximum(iz - 1, 0)), axis=-1)) assert np.all(self.label.flat[inds][~np.isnan(self.top)] == 0) # plt.imshow(self._label2rgb(self.label.flat[inds])) # show the surface # do the same for the bottom surface izb = self.bc.z2i(self.bottom) inds = self._lookup_inds(np.stack((ix, iy, izb), axis=-1)) assert np.all(self.label.flat[inds][~np.isnan(self.top)] != 0) # one sample below, it's all zeros inds = self._lookup_inds( np.stack((ix, iy, np.maximum(izb + 1, 0)), axis=-1)) assert np.all(self.label.flat[inds][~np.isnan(self.bottom)] == 0)
def __init__(self): self.atlas = AllenAtlas(25) self.xlim = self.atlas.bc.xlim self.ylim = self.atlas.bc.ylim[::-1] self.zlim = self.atlas.bc.zlim[::-1] # Coverage if not Path('coverage.npy').exists(): save_coverage() cov = np.load('coverage.npy') cov = normalize_volume(cov) cov *= 255 cov = cov.astype(np.uint8) self.shape = cov.shape # Atlas if not Path('label.npy').exists(): save_labels() atlas = np.load('label.npy') # Brain region colors n = len(self.atlas.regions.rgb) alpha = 255 * np.ones((n, 1)) alpha[0] = 0 # put empty region transparent? rgb = np.hstack((self.atlas.regions.rgb, alpha)).astype(np.uint8) atlas = rgb[atlas] atlas = np.ascontiguousarray(atlas) np.save('volume_label.npy', atlas) # atlas.astype(np.uint8).tofile('../datoviz/data/volume/atlas_25_label.img') # Merge coverage and atlas assert cov.shape == atlas.shape[:3] _idx = cov != 0 atlas[_idx, :] = cov[_idx][:, np.newaxis] atlas = np.transpose(atlas, (1, 2, 0, 3)) self.vol = atlas
class Controller(PgImageController): """ TopView Controller """ def __init__(self, qmain: TopView, res=25): super(Controller, self).__init__(qmain) self.atlas = AllenAtlas(res) self.fig_top = self.qwidget = qmain # Setup Coronal slice: width: ml, height: dv, depth: ap self.fig_coronal = SliceView(qmain, waxis=0, haxis=2, daxis=1) self.fig_coronal.setWindowTitle('Coronal Slice') self.set_slice(self.fig_coronal) self.fig_coronal.show() # Setup Sagittal slice: width: ap, height: dv, depth: ml self.fig_sagittal = SliceView(qmain, waxis=1, haxis=2, daxis=0) self.fig_sagittal.setWindowTitle('Sagittal Slice') self.set_slice(self.fig_sagittal) self.fig_sagittal.show() def set_slice(self, fig, coord=0): waxis, haxis, daxis = (fig.ctrl.waxis, fig.ctrl.haxis, fig.ctrl.daxis) # construct the transform matrix image 2 ibl coordinates dw = self.atlas.bc.dxyz[waxis] dh = self.atlas.bc.dxyz[haxis] wl = self.atlas.bc.lim(waxis) - dw / 2 hl = self.atlas.bc.lim(haxis) - dh / 2 fig.ctrl.set_image(self.atlas.slice(coord, axis=daxis, mode='clip'), dw, dh, wl[0], hl[0]) fig.ctrl.slice_coord = coord def set_top(self): img = self.atlas.top.transpose() img[np.isnan(img)] = np.nanmin(img) # img has dims ml, ap dw, dh = (self.atlas.bc.dxyz[0], self.atlas.bc.dxyz[1]) wl, hl = (self.atlas.bc.xlim, self.atlas.bc.ylim) self.set_image(img, dw, dh, wl[0], hl[0])
def save_labels(): from ibllib.atlas import AllenAtlas ba = AllenAtlas() vol = np.ascontiguousarray(ba.label) np.save('label.npy', vol)
class ReportSnapshotProbe(ReportSnapshot): signature = { 'input_files': [], # see setUp method for declaration of inputs 'output_files': [] # see setUp method for declaration of inputs } def __init__(self, pid, session_path=None, one=None, brain_regions=None, brain_atlas=None, **kwargs): """ :param pid: probe insertion UUID from Alyx :param one: one instance :param brain_regions: (optional) ibllib.atlas.BrainRegion object :param brain_atlas: (optional) ibllib.atlas.AllenAtlas object :param kwargs: """ assert one self.one = one self.brain_atlas = brain_atlas self.brain_regions = brain_regions if self.brain_atlas and not self.brain_regions: self.brain_regions = self.brain_atlas.regions self.content_type = 'probeinsertion' self.pid = pid self.eid, self.pname = self.one.pid2eid(self.pid) self.session_path = session_path or self.one.eid2path(self.eid) self.output_directory = self.session_path.joinpath('snapshot', self.pname) self.output_directory.mkdir(exist_ok=True, parents=True) self.histology_status = None self.get_probe_signature() super(ReportSnapshotProbe, self).__init__(self.session_path, object_id=pid, content_type=self.content_type, one=self.one, **kwargs) @property def pid_label(self): """returns a probe insertion stub to label titles, for example: 'SWC_054_2020-10-05_001_probe01'""" return '_'.join(list(self.session_path.parts[-3:]) + [self.pname]) @abc.abstractmethod def get_probe_signature(self): # method that gets input and output signatures from the probe name. The format is a dictionary as follows: # return {'input_files': input_signature, 'output_files': output_signature} pass def get_histology_status(self): """ Finds at which point in histology pipeline the probe insertion is :return: """ self.hist_lookup = {'Resolved': 3, 'Aligned': 2, 'Traced': 1, None: 0} # is this bad practice? self.ins = self.one.alyx.rest('insertions', 'list', id=self.pid)[0] traced = self.ins.get('json', {}).get('extended_qc', {}).get('tracing_exists', False) aligned = self.ins.get('json', {}).get('extended_qc', {}).get('alignment_count', 0) resolved = self.ins.get('json', {}).get('extended_qc', {}).get('alignment_resolved', False) if resolved: return 'Resolved' elif aligned > 0: return 'Aligned' elif traced: return 'Traced' else: return None def get_channels(self, alf_object, collection): electrodes = {} try: electrodes = self.one.load_object(self.eid, alf_object, collection=collection) electrodes['axial_um'] = electrodes['localCoordinates'][:, 1] except ALFObjectNotFound: _logger.warning(f'{alf_object} does not yet exist') if self.hist_lookup[self.histology_status] == 3: try: electrodes['atlas_id'] = electrodes['brainLocationIds_ccf_2017'] electrodes['mlapdv'] = electrodes['mlapdv'] / 1e6 except KeyError: _logger.warning('Insertion resolved but brainLocationIds_ccf_2017 attribute do not exist') if self.hist_lookup[self.histology_status] > 0 and 'atlas_id' not in electrodes.keys(): if not self.brain_atlas: self.brain_atlas = AllenAtlas() self.brain_regions = self.brain_regions or self.brain_atlas.regions if 'localCoordinates' not in electrodes.keys(): geometry = trace_header(version=1) electrodes['localCoordinates'] = np.c_[geometry['x'], geometry['y']] electrodes['axial_um'] = electrodes['localCoordinates'][:, 1] depths = electrodes['localCoordinates'][:, 1] xyz = np.array(self.ins['json']['xyz_picks']) / 1e6 if self.hist_lookup[self.histology_status] >= 2: traj = self.one.alyx.rest('trajectories', 'list', provenance='Ephys aligned histology track', probe_insertion=self.pid)[0] align_key = self.ins['json']['extended_qc']['alignment_stored'] feature = traj['json'][align_key][0] track = traj['json'][align_key][1] ephysalign = EphysAlignment(xyz, depths, track_prev=track, feature_prev=feature, brain_atlas=self.brain_atlas, speedy=True) electrodes['mlapdv'] = ephysalign.get_channel_locations(feature, track) electrodes['atlas_id'] = self.brain_atlas.regions.get(self.brain_atlas.get_labels(electrodes['mlapdv']))['id'] if self.hist_lookup[self.histology_status] == 1: xyz = xyz[np.argsort(xyz[:, 2]), :] electrodes['mlapdv'] = interpolate_along_track(xyz, (depths + TIP_SIZE_UM) / 1e6) electrodes['atlas_id'] = self.brain_atlas.regions.get(self.brain_atlas.get_labels(electrodes['mlapdv']))['id'] return electrodes def register_images(self, widths=None, function=None): super(ReportSnapshotProbe, self).register_images(widths=widths, function=function, extra_dict={'channels': self.histology_status})
def _plot_slice(coord, slice, region_values, vol_type, background='boundary', map='Allen', clevels=None, cmap='viridis', show_cbar=False, ba=None, ax=None): ba = ba or AllenAtlas() if clevels is None: clevels = (np.nanmin(region_values), np.nanmax(region_values)) if ax: fig = ax.get_figure() else: fig, ax = plt.subplots() if background == 'boundary': cmap_bound = matplotlib.cm.get_cmap("bone_r").copy() cmap_bound.set_under([1, 1, 1], 0) else: cmap_bound = None if slice == 'coronal': if background == 'image': ba.plot_cslice(coord, volume='image', mapping=map, ax=ax) ba.plot_cslice(coord, volume=vol_type, region_values=region_values, mapping=map, cmap=cmap, vmin=clevels[0], vmax=clevels[1], ax=ax) else: ba.plot_cslice(coord, volume=vol_type, region_values=region_values, mapping=map, cmap=cmap, vmin=clevels[0], vmax=clevels[1], ax=ax) ba.plot_cslice(coord, volume='boundary', mapping=map, ax=ax, cmap=cmap_bound, vmin=0.01, vmax=0.8) elif slice == 'sagittal': if background == 'image': ba.plot_sslice(coord, volume='image', mapping=map, ax=ax) ba.plot_sslice(coord, volume=vol_type, region_values=region_values, mapping=map, cmap=cmap, vmin=clevels[0], vmax=clevels[1], ax=ax) else: ba.plot_sslice(coord, volume=vol_type, region_values=region_values, mapping=map, cmap=cmap, vmin=clevels[0], vmax=clevels[1], ax=ax) ba.plot_sslice(coord, volume='boundary', mapping=map, ax=ax, cmap=cmap_bound, vmin=0.01, vmax=0.8) elif slice == 'horizontal': if background == 'image': ba.plot_hslice(coord, volume='image', mapping=map, ax=ax) ba.plot_hslice(coord, volume=vol_type, region_values=region_values, mapping=map, cmap=cmap, vmin=clevels[0], vmax=clevels[1], ax=ax) else: ba.plot_hslice(coord, volume=vol_type, region_values=region_values, mapping=map, cmap=cmap, vmin=clevels[0], vmax=clevels[1], ax=ax) ba.plot_hslice(coord, volume='boundary', mapping=map, ax=ax, cmap=cmap_bound, vmin=0.01, vmax=0.8) elif slice == 'top': if background == 'image': ba.plot_top(volume='image', mapping=map, ax=ax) ba.plot_top(volume=vol_type, region_values=region_values, mapping=map, cmap=cmap, vmin=clevels[0], vmax=clevels[1], ax=ax) else: ba.plot_top(volume=vol_type, region_values=region_values, mapping=map, cmap=cmap, vmin=clevels[0], vmax=clevels[1], ax=ax) ba.plot_top(volume='boundary', mapping=map, ax=ax, cmap=cmap_bound, vmin=0.01, vmax=0.8) if show_cbar: norm = matplotlib.colors.Normalize(vmin=clevels[0], vmax=clevels[1], clip=False) cbar = fig.colorbar(matplotlib.cm.ScalarMappable(norm=norm, cmap=cmap), ax=ax) return fig, ax, cbar else: return fig, ax
def save_atlas(): from ibllib.atlas import AllenAtlas ba = AllenAtlas() vol = np.ascontiguousarray(ba.image) np.save('atlas.npy', vol)
from ibllib.atlas import AllenAtlas ba = AllenAtlas() # Primary somatosensory area nose region_id = 353 ba.regions.descendants(353) ba.regions.ancestors(353)
class MainWindow(QtWidgets.QMainWindow): @staticmethod def _instances(): app = QtWidgets.QApplication.instance() return [w for w in app.topLevelWidgets() if isinstance(w, MainWindow)] @staticmethod def _get_or_create(title=None, **kwargs): av = next(filter(lambda e: e.isVisible() and e.windowTitle() == title, MainWindow._instances()), None) if av is None: av = MainWindow(**kwargs) av.setWindowTitle(title) return av def __init__(self, lazy=False): super(MainWindow, self).__init__() uic.loadUi(Path(__file__).parent.joinpath('mainUI.ui'), self) self.atlas = AllenAtlas(25) # Configure the Menu bar menu_bar = QtWidgets.QMenuBar(self) menu_bar.setNativeMenuBar(False) self.setMenuBar(menu_bar) # Add menu bar for mappings self.map_menu = menu_bar.addMenu('Mappings') self.map_group = QtGui.QActionGroup(self.map_menu) # Only allow one to plot to be selected at any one time self.map_group.setExclusive(True) self.add_menu_bar(self.map_menu, self.map_group, list(self.atlas.regions.mappings.keys()), callback=self.change_mapping, default='Allen') # Add menu bar for base image self.img_menu = menu_bar.addMenu('Images') self.img_group = QtGui.QActionGroup(self.img_menu) self.img_group.setExclusive(True) images = ['Image', 'Annotation'] self.add_menu_bar(self.img_menu, self.img_group, images, callback=self.change_image, default='Image') # Add menu bar for coverage self.coverage_menu = menu_bar.addMenu('Coverage') self.coverage_group = QtGui.QActionGroup(self.coverage_menu) self.coverage_group.setExclusive(True) coverages = ['Coverage cosine', 'Coverage grid 500', 'Coverage grid 250', 'Coverage grid 100'] self.add_menu_bar(self.coverage_menu, self.coverage_group, coverages, callback=self.add_coverage) # Add menubar for insertions self.insertion_menu = menu_bar.addMenu('Insertions') self.insertion_group = QtGui.QActionGroup(self.insertion_menu) self.insertion_group.setExclusive(True) insertions = ['Resolved', 'Ephys aligned histology track', 'Histology track', 'Histology track (best)', 'Micro-manipulator', 'Micro-manipulator (best)', 'Planned', 'Planned (best)'] self.add_menu_bar(self.insertion_menu, self.insertion_group, insertions, callback=self.add_insertions) self.coronal = SliceView(self, self.fig_coronal, self.atlas, slice='coronal', waxis=0, haxis=2, daxis=1) self.sagittal = SliceView(self, self.fig_sagittal, self.atlas, slice='sagittal', waxis=1, haxis=2, daxis=0) self.horizontal = SliceView(self, self.fig_horizontal, self.atlas, slice='horizontal', waxis=1, haxis=0, daxis=2) self.horizontal.fig_slice.getViewBox().invertY(True) self.top = TopView(self, self.fig_top, self.atlas) self.probe = ProbeView(self, self.fig_probe) self.coverage = CoverageView(self) self.probe_model = ProbeModel(one=one, ba=self.atlas, lazy=lazy) self.region = RegionView(self, self.atlas) self.change_mapping() layout = QtWidgets.QGridLayout() layout.addWidget(self.coverage) self.coverage_placeholder.setLayout(layout) layout = QtWidgets.QGridLayout() layout.addWidget(self.region) self.region_placeholder.setLayout(layout) self.target = None def change_mapping(self): data = np.unique(self.atlas.regions.name[self.atlas._get_mapping( mapping=self.get_mapping())]) self.region.populate_combobox(data) self._refresh() def get_mapping(self): return self.map_group.checkedAction().text() def change_image(self): self.coronal.ctrl.change_base_layer(self.img_group.checkedAction().text()) self.sagittal.ctrl.change_base_layer(self.img_group.checkedAction().text()) self.horizontal.ctrl.change_base_layer(self.img_group.checkedAction().text()) self._refresh() def add_coverage(self): provenance = self.insertion_group.checkedAction().text() coverage_choice = self.coverage_group.checkedAction().text() if not self.probe_model.initialised: self.probe_model.initialise() if '(best)' in provenance: provenance = provenance[:-7] self.probe_model.compute_best_for_provenance(provenance) self.provenance = 'Best' all_channels = self.probe_model.get_all_channels(self.provenance) else: self.provenance = provenance all_channels = self.probe_model.get_all_channels(self.provenance) if 'cosine' in coverage_choice: cov = self.probe_model.compute_coverage(all_channels) bc = None else: bin_size = int(coverage_choice[-3:]) cov, bc = self.probe_model.grid_coverage(all_channels, bin_size) self.coronal.ctrl.add_volume_layer(cov, bc=bc) self.sagittal.ctrl.add_volume_layer(cov, bc=bc) self.horizontal.ctrl.add_volume_layer(cov, bc=bc) self._refresh() def add_extra_coverage(self, traj, ins=None): cov, xyz_cnt, per = self.probe_model.add_coverage(traj) self.coronal.ctrl.add_volume_layer(cov, name='coverage_extra', cmap='inferno') self.sagittal.ctrl.add_volume_layer(cov, name='coverage_extra', cmap='inferno') self.horizontal.ctrl.add_volume_layer(cov, name='coverage_extra', cmap='inferno') self.refresh_slices('horizontal', 'x', xyz_cnt[1]) self.refresh_slices('horizontal', 'y', xyz_cnt[0]) self.refresh_slices('sagittal', 'y', xyz_cnt[2]) self.top.cov_scatter.setData(x=[traj['x'] / 1e6], y=[traj['y'] / 1e6], pen='b', brush='b') (region, region_lab, region_col) = self.probe_model.get_brain_regions( traj, ins=ins, mapping=self.get_mapping()) self.probe.plot_region_along_probe(region, region_lab, region_col) self.per_label.setText(f"{per} %") self._refresh() def add_trajectory(self, x, y): self.coverage.ctrl.model.initialise_data() self.coverage.ctrl.set_value(x, 'x') self.coverage.ctrl.set_value(y, 'y') self.coverage.update_view() def add_insertion_by_id(self, ins_id): traj, ins = self.probe_model.insertion_by_id(ins_id) self.add_extra_coverage(traj, ins) def add_insertions(self): provenance = self.insertion_group.checkedAction().text() if not self.probe_model.initialised: self.probe_model.initialise() if '(best)' in provenance: provenance = provenance[:-7] self.probe_model.compute_best_for_provenance(provenance) self.provenance = 'Best' else: if not 'traj' in self.probe_model.traj[provenance].keys(): self.probe_model.get_traj_for_provenance(provenance) self.provenance = provenance self.top.ins_scatter.setData(x=self.probe_model.traj[self.provenance]['x']/1e6, y=self.probe_model.traj[self.provenance]['y']/1e6, pen='r', brush='r') def on_insertion_clicked(self, scatter, point): idx = np.argwhere(self.probe_model.traj[self.provenance]['x']/1e6 == point[0].pos().x())[0][0] self.top.highlight_selected_point(point[0]) (region, region_lab, region_col) = self.probe_model.get_brain_regions( self.probe_model.traj[self.provenance]['traj'][idx], mapping=self.get_mapping()) self.probe.plot_region_along_probe(region, region_lab, region_col) def add_menu_bar(self, menu, group, items, callback=None, default=None): for item in items: if item == default: _item = QtGui.QAction(item, self, checkable=True, checked=True) else: _item = QtGui.QAction(item, self, checkable=True, checked=False) if callback: _item.triggered.connect(callback) menu.addAction(_item) group.addAction(_item) return menu, group def _refresh(self): self._refresh_sagittal() self._refresh_coronal() self._refresh_horizontal() def _refresh_coronal(self): self.coronal.ctrl.set_slice() #offset = self.atlas.bc.lim(1)[1] #self.la.update_slicer(self.la.ny_slicer, (self.top.line_coronal.value()*1e6 + offset*16)) def _refresh_sagittal(self): self.sagittal.ctrl.set_slice() #offset = self.atlas.bc.lim(0)[0] #self.la.update_slicer(self.la.nx_slicer, self.top.line_sagittal.value()*1e6 + offset*1e6) def _refresh_horizontal(self): self.horizontal.ctrl.set_slice() #self.set_slice(self.horizontal, self.horizontal.slice_coord) def refresh_highlighted_region(self, region, mlapdv): if (region is None) or (region['acronym'][0] == 'void'): self._reset_region('non_locked') self.region.update_labels(mlapdv[0], mlapdv[1], mlapdv[2], None) else: self._refresh_non_locked_region(region['id'][0]) self.region.update_labels(mlapdv[0], mlapdv[1], mlapdv[2], region) def refresh_locked_region(self, region): region_values = np.zeros_like(self.atlas.regions.id) self._change_region_value('non_locked', region_values) region_idx = np.where(self.atlas.regions.id == region)[0] region_values[region_idx] = 100 self._change_region_value('locked', region_values) self._refresh() self.region.update_selected_region(region) # need to set the drop down to the selected region #self.la2.reveal_regions(region_idx) def _reset_region(self, name): region_values = np.zeros_like(self.atlas.regions.id) self._change_region_value(name, region_values) self._refresh() def _refresh_non_locked_region(self, region): region_values = np.zeros_like(self.atlas.regions.id) region_idx = np.where(self.atlas.regions.id == region)[0] region_values[region_idx] = 100 self._change_region_value('non_locked', region_values) self._refresh() def _change_region_value(self, name, values): image = self.coronal.ctrl.get_image_layer(name=name) image.slice_kwargs['region_values'] = values image = self.sagittal.ctrl.get_image_layer(name=name) image.slice_kwargs['region_values'] = values image = self.horizontal.ctrl.get_image_layer(name=name) image.slice_kwargs['region_values'] = values def refresh_slices(self, slice, orientation, value, move_top=True): if slice == 'coronal' and orientation == 'x': self.sagittal.slice_coord = value self.horizontal.line_y.setValue(value) self.coronal.line_x.setValue(value) if move_top: self.top.line_x.setValue(value) self._refresh_sagittal() if slice == 'coronal' and orientation == 'y': self.horizontal.slice_coord = value self.sagittal.line_y.setValue(value) self.coronal.line_y.setValue(value) self._refresh_horizontal() if slice == 'sagittal' and orientation == 'x': self.coronal.slice_coord = value self.horizontal.line_x.setValue(value) self.sagittal.line_x.setValue(value) if move_top: self.top.line_y.setValue(value) self._refresh_coronal() if slice == 'sagittal' and orientation == 'y': self.horizontal.slice_coord = value self.coronal.line_y.setValue(value) self.sagittal.line_y.setValue(value) self._refresh_horizontal() if slice == 'horizontal' and orientation == 'x': self.coronal.slice_coord = value self.sagittal.line_x.setValue(value) self.horizontal.line_x.setValue(value) self.top.line_y.setValue(value) self._refresh_coronal() if slice == 'horizontal' and orientation == 'y': self.sagittal.slice_coord = value self.coronal.line_x.setValue(value) self.horizontal.line_y.setValue(value) self.top.line_x.setValue(value) self._refresh_sagittal()
import unittest from oneibl.one import ONE from ibllib.atlas import AllenAtlas from ibllib.pipes.misc import create_alyx_probe_insertions from ibllib.qc.alignment_qc import AlignmentQC from ibllib.pipes.histology import register_track from pathlib import Path import numpy as np import copy EPHYS_SESSION = 'b1c968ad-4874-468d-b2e4-5ffa9b9964e9' one = ONE(username='******', password='******', base_url='https://test.alyx.internationalbrainlab.org') brain_atlas = AllenAtlas(25) class TestProbeInsertion(unittest.TestCase): def test_creation(self): probe = ['probe00', 'probe01'] create_alyx_probe_insertions(session_path=EPHYS_SESSION, model='3B2', labels=probe, one=one, force=True) insertion = one.alyx.rest('insertions', 'list', session=EPHYS_SESSION) assert (len(insertion) == 2) assert (insertion[0]['json']['qc'] == 'NOT_SET') assert (len(insertion[0]['json']['extended_qc']) == 0) one.alyx.rest('insertions', 'delete', id=insertion[0]['id'])
def plot_points_on_slice(xyz, values=None, coord=-1000, slice='coronal', mapping='Allen', background='boundary', cmap='Reds', clevels=None, show_cbar=False, aggr='mean', fwhm=100, brain_atlas=None, ax=None): """ Plot xyz points on slice. Points that lie in the same voxel within slice are aggregated according to method specified. A 3D Gaussian smoothing kernel with distance specified by fwhm is applied to images. :param xyz: 3 column array of xyz coordinates of points in metres :param values: array of values per xyz coordinates, if no values are given the sum of xyz points in each voxel is returned :param coord: coordinate of slice in um (not needed when slice='top') :param slice: orientation of slice, options are 'coronal', 'sagittal', 'horizontal', 'top' (top view of brain) :param mapping: atlas mapping to use, options are 'Allen', 'Beryl' or 'Cosmos' :param background: background slice to overlay onto, options are 'image' or 'boundary' :param cmap: colormap to use :param clevels: min max color levels [cmin, cmax] :param show_cbar: whether or not to add colorbar to axis :param aggr: aggregation method. Options are sum, count, mean, std, median, min and max. Can also give in custom function (https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.binned_statistic.html) :param fwhm: fwhm distance of gaussian kernel in um :param brain_atlas: AllenAtlas object :param ax: optional axis object to plot on :return: """ ba = brain_atlas or AllenAtlas() # Find the mapping to use if '-lr' in mapping: map = mapping else: map = mapping + '-lr' region_values = compute_volume_from_points(xyz, values, aggr=aggr, fwhm=fwhm, ba=ba) if show_cbar: fig, ax, cbar = _plot_slice(coord / 1e6, slice, region_values, 'volume', background=background, map=map, clevels=clevels, cmap=cmap, ba=ba, ax=ax, show_cbar=show_cbar) return fig, ax, cbar else: fig, ax = _plot_slice(coord / 1e6, slice, region_values, 'volume', background=background, map=map, clevels=clevels, cmap=cmap, ba=ba, ax=ax, show_cbar=show_cbar) return fig, ax
def plot_scalar_on_slice(regions, values, coord=-1000, slice='coronal', mapping='Allen', hemisphere='left', background='image', cmap='viridis', clevels=None, show_cbar=False, brain_atlas=None, ax=None): """ Function to plot scalar value per allen region on histology slice :param regions: array of acronyms of Allen regions :param values: array of scalar value per acronym. If hemisphere is 'both' and different values want to be shown on each hemispheres, values should contain 2 columns, 1st column for LH values, 2nd column for RH values :param coord: coordinate of slice in um (not needed when slice='top') :param slice: orientation of slice, options are 'coronal', 'sagittal', 'horizontal', 'top' (top view of brain) :param mapping: atlas mapping to use, options are 'Allen', 'Beryl' or 'Cosmos' :param hemisphere: hemisphere to display, options are 'left', 'right', 'both' :param background: background slice to overlay onto, options are 'image' or 'boundary' :param cmap: colormap to use :param clevels: min max color levels [cmin, cmax] :param show_cbar: whether or not to add colorbar to axis :param brain_atlas: AllenAtlas object :param ax: optional axis object to plot on :return: """ ba = brain_atlas or AllenAtlas() br = ba.regions if clevels is None: clevels = (np.nanmin(values), np.nanmax(values)) print(clevels) # Find the mapping to use if '-lr' in mapping: map = mapping else: map = mapping + '-lr' region_values = np.zeros_like(br.id) * np.nan if len(values.shape) == 2: for r, vL, vR in zip(regions, values[:, 0], values[:, 1]): idx = np.where(br.acronym[br.mappings[map]] == r)[0] idx_lh = idx[idx > br.n_lr] idx_rh = idx[idx <= br.n_lr] region_values[idx_rh] = vR region_values[idx_lh] = vL else: for r, v in zip(regions, values): region_values[np.where(br.acronym[br.mappings[map]] == r)[0]] = v if hemisphere == 'left': region_values[0:(br.n_lr + 1)] = np.nan elif hemisphere == 'right': region_values[br.n_lr:] = np.nan region_values[0] = np.nan if show_cbar: fig, ax, cbar = _plot_slice(coord / 1e6, slice, region_values, 'value', background=background, map=map, clevels=clevels, cmap=cmap, ba=ba, ax=ax, show_cbar=show_cbar) return fig, ax, cbar else: fig, ax = _plot_slice(coord / 1e6, slice, region_values, 'value', background=background, map=map, clevels=clevels, cmap=cmap, ba=ba, ax=ax, show_cbar=show_cbar) return fig, ax
def __init__(self, lazy=False): super(MainWindow, self).__init__() uic.loadUi(Path(__file__).parent.joinpath('mainUI.ui'), self) self.atlas = AllenAtlas(25) # Configure the Menu bar menu_bar = QtWidgets.QMenuBar(self) menu_bar.setNativeMenuBar(False) self.setMenuBar(menu_bar) # Add menu bar for mappings self.map_menu = menu_bar.addMenu('Mappings') self.map_group = QtGui.QActionGroup(self.map_menu) # Only allow one to plot to be selected at any one time self.map_group.setExclusive(True) self.add_menu_bar(self.map_menu, self.map_group, list(self.atlas.regions.mappings.keys()), callback=self.change_mapping, default='Allen') # Add menu bar for base image self.img_menu = menu_bar.addMenu('Images') self.img_group = QtGui.QActionGroup(self.img_menu) self.img_group.setExclusive(True) images = ['Image', 'Annotation'] self.add_menu_bar(self.img_menu, self.img_group, images, callback=self.change_image, default='Image') # Add menu bar for coverage self.coverage_menu = menu_bar.addMenu('Coverage') self.coverage_group = QtGui.QActionGroup(self.coverage_menu) self.coverage_group.setExclusive(True) coverages = ['Coverage cosine', 'Coverage grid 500', 'Coverage grid 250', 'Coverage grid 100'] self.add_menu_bar(self.coverage_menu, self.coverage_group, coverages, callback=self.add_coverage) # Add menubar for insertions self.insertion_menu = menu_bar.addMenu('Insertions') self.insertion_group = QtGui.QActionGroup(self.insertion_menu) self.insertion_group.setExclusive(True) insertions = ['Resolved', 'Ephys aligned histology track', 'Histology track', 'Histology track (best)', 'Micro-manipulator', 'Micro-manipulator (best)', 'Planned', 'Planned (best)'] self.add_menu_bar(self.insertion_menu, self.insertion_group, insertions, callback=self.add_insertions) self.coronal = SliceView(self, self.fig_coronal, self.atlas, slice='coronal', waxis=0, haxis=2, daxis=1) self.sagittal = SliceView(self, self.fig_sagittal, self.atlas, slice='sagittal', waxis=1, haxis=2, daxis=0) self.horizontal = SliceView(self, self.fig_horizontal, self.atlas, slice='horizontal', waxis=1, haxis=0, daxis=2) self.horizontal.fig_slice.getViewBox().invertY(True) self.top = TopView(self, self.fig_top, self.atlas) self.probe = ProbeView(self, self.fig_probe) self.coverage = CoverageView(self) self.probe_model = ProbeModel(one=one, ba=self.atlas, lazy=lazy) self.region = RegionView(self, self.atlas) self.change_mapping() layout = QtWidgets.QGridLayout() layout.addWidget(self.coverage) self.coverage_placeholder.setLayout(layout) layout = QtWidgets.QGridLayout() layout.addWidget(self.region) self.region_placeholder.setLayout(layout) self.target = None
class ControllerTopView(PgImageController): """ TopView ControllerTopView """ def __init__(self, qmain: TopView, res: int = 25, volume='image', brainmap='Allen'): super(ControllerTopView, self).__init__(qmain) self.volume = volume self.atlas = AllenAtlas(res, brainmap=brainmap) self.fig_top = self.qwidget = qmain # Setup Coronal slice: width: ml, height: dv, depth: ap self.fig_coronal = SliceView(qmain, waxis=0, haxis=2, daxis=1) self.fig_coronal.setWindowTitle('Coronal Slice') self.set_slice(self.fig_coronal) self.fig_coronal.show() # Setup Sagittal slice: width: ap, height: dv, depth: ml self.fig_sagittal = SliceView(qmain, waxis=1, haxis=2, daxis=0) self.fig_sagittal.setWindowTitle('Sagittal Slice') self.set_slice(self.fig_sagittal) self.fig_sagittal.show() def set_slice(self, fig, coord=0, mapping="Allen"): waxis, haxis, daxis = (fig.ctrl.waxis, fig.ctrl.haxis, fig.ctrl.daxis) # construct the transform matrix image 2 ibl coordinates dw = self.atlas.bc.dxyz[waxis] dh = self.atlas.bc.dxyz[haxis] wl = self.atlas.bc.lim(waxis) - dw / 2 hl = self.atlas.bc.lim(haxis) - dh / 2 # the ImageLayer object carries slice kwargs and pyqtgraph ImageSet kwargs # reversed order so the self.im is set with the base layer for layer in reversed(fig.ctrl.image_layers): _slice = self.atlas.slice(coord, axis=daxis, mapping=mapping, **layer.slice_kwargs) fig.ctrl.set_image(layer.image_item, _slice, dw, dh, wl[0], hl[0], **layer.pg_kwargs) fig.ctrl.slice_coord = coord def set_top(self): img = self.atlas.top.transpose() img[np.isnan(img)] = np.nanmin(img) # img has dims ml, ap dw, dh = (self.atlas.bc.dxyz[0], self.atlas.bc.dxyz[1]) wl, hl = (self.atlas.bc.xlim, self.atlas.bc.ylim) self.set_image(self.image_layers[0].image_item, img, dw, dh, wl[0], hl[0]) def set_scatter(self, fig, coord=0): waxis = fig.ctrl.waxis # dealing with coronal slice if waxis == 0: idx = np.where( self.scatter_data_ind[:, 1] == self.atlas.bc.y2i(coord))[0] x = self.scatter_data[idx, 0] y = self.scatter_data[idx, 2] else: idx = np.where( self.scatter_data_ind[:, 0] == self.atlas.bc.x2i(coord))[0] x = self.scatter_data[idx, 1] y = self.scatter_data[idx, 2] fig.ctrl.set_points(x, y) def set_volume(self, volume): self.volume = volume
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on Fri Sep 25 10:22:22 2020 @author: guido """ import pandas as pd from ephys_functions import combine_layers_cortex from ibllib.atlas import AllenAtlas from oneibl.one import ONE one = ONE() # Get all brain region acronyms ba = AllenAtlas(25) all_regions = ba.regions.acronym # Exclude root incl_regions = [i for i, j in enumerate(all_regions) if not j.islower()] all_regions = all_regions[incl_regions] # Combine cortex layers all_regions = combine_layers_cortex(all_regions, delete_duplicates=True) # Get number of recordings per region num_rec_regions = pd.DataFrame(index=all_regions, columns=['num_recordings']) for i, region in enumerate(all_regions): print('Querying %d of %d' % (i + 1, len(all_regions))) ses = one.alyx.rest('sessions', 'list',
def plot_volume_on_slice(volume, coord=-1000, slice='coronal', mapping='Allen', background='boundary', cmap='Reds', clevels=None, show_cbar=False, brain_atlas=None, ax=None): """ Plot slice at through volume :param volume: 3D array of volume (must be same shape as brain_atlas object) :param coord: coordinate of slice in um :param slice: orientation of slice, options are 'coronal', 'sagittal', 'horizontal' :param mapping: atlas mapping to use, options are 'Allen', 'Beryl' or 'Cosmos' :param background: background slice to overlay onto, options are 'image' or 'boundary' :param cmap: colormap to use :param clevels: min max color levels [cmin, cmax] :param show_cbar: whether or not to add colorbar to axis :param brain_atlas: AllenAtlas object :param ax: optional axis object to plot on :return: """ ba = brain_atlas or AllenAtlas() assert volume.shape == ba.image.shape, 'Volume must have same shape as ba' # Find the mapping to use if '-lr' in mapping: map = mapping else: map = mapping + '-lr' if show_cbar: fig, ax, cbar = _plot_slice(coord / 1e6, slice, volume, 'volume', background=background, map=map, clevels=clevels, cmap=cmap, ba=ba, ax=ax, show_cbar=show_cbar) return fig, ax, cbar else: fig, ax = _plot_slice(coord / 1e6, slice, volume, 'volume', background=background, map=map, clevels=clevels, cmap=cmap, ba=ba, ax=ax, show_cbar=show_cbar) return fig, ax