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 compute_similarity_matrix(self): """ Computes the similarity matrix between each alignment stored in the ephys aligned trajectory. Similarity matrix based on number of clusters that share brain region and parent brain region """ r = regions_from_allen_csv() clusters = dict() for iK, key in enumerate(self.align_keys_sorted): # Location of reference lines used for alignment feature = np.array(self.alignments[key][0]) track = np.array(self.alignments[key][1]) # Instantiate EphysAlignment object ephysalign = EphysAlignment(self.xyz_picks, self.depths, track_prev=track, feature_prev=feature, brain_atlas=self.brain_atlas) # Find xyz location of all channels xyz_channels = ephysalign.get_channel_locations(feature, track) brain_regions = ephysalign.get_brain_locations(xyz_channels) # Find the location of clusters along the alignment cluster_info = dict() cluster_info['brain_id'] = brain_regions['id'][self.cluster_chns] cluster_info['parent_id'] = r.get( ids=cluster_info['brain_id']).parent.astype(int) clusters.update({key: cluster_info}) sim_matrix = np.zeros( (len(self.align_keys_sorted), len(self.align_keys_sorted))) for ik, key in enumerate(self.align_keys_sorted): for ikk, key2 in enumerate(self.align_keys_sorted): same_id = np.where( clusters[key]['brain_id'] == clusters[key2]['brain_id'])[0] not_same_id = \ np.where(clusters[key]['brain_id'] != clusters[key2]['brain_id'])[0] same_parent = np.where( clusters[key]['parent_id'][not_same_id] == clusters[key2] ['parent_id'][not_same_id])[0] sim_matrix[ik, ikk] = len(same_id) + (len(same_parent) * 0.5) # Normalise sim_matrix_norm = sim_matrix / np.max(sim_matrix) return sim_matrix_norm
class TestsEphysReconstruction(unittest.TestCase): def setUp(self): self.ephysalign = EphysAlignment(xyz_picks, track_prev=track_prev, feature_prev=feature_prev, brain_atlas=brain_atlas) self.feature = self.ephysalign.feature_init self.track = self.ephysalign.track_init def test_channel_locations(self): xyz_channels = self.ephysalign.get_channel_locations(self.feature, self.track, depths=depths) self.assertTrue(np.all(np.isclose(xyz_channels[0, :], xyz_channels_ref[0]))) self.assertTrue(np.all(np.isclose(xyz_channels[-1, :], xyz_channels_ref[-1]))) brain_regions = self.ephysalign.get_brain_locations(xyz_channels) self.assertTrue(np.all(np.equal(np.unique(brain_regions.acronym), brain_regions_ref)))
def upload_channels(self, alignment_key, upload_alyx, upload_flatiron): """ Upload channels to alyx and flatiron based on the alignment specified by the alignment key """ feature = np.array(self.alignments[alignment_key][0]) track = np.array(self.alignments[alignment_key][1]) ephysalign = EphysAlignment(self.xyz_picks, self.depths, track_prev=track, feature_prev=feature, brain_atlas=self.brain_atlas) # Find the channels channels_mlapdv = np.int32( ephysalign.get_channel_locations(feature, track) * 1e6) channels_brainID = ephysalign.get_brain_locations(channels_mlapdv / 1e6)['id'] # Find the clusters r = regions_from_allen_csv() clusters_mlapdv = channels_mlapdv[self.cluster_chns] clusters_brainID = channels_brainID[self.cluster_chns] clusters_brainAcro = r.get(ids=clusters_brainID).acronym # upload datasets to flatiron files_to_register = [] if upload_flatiron: ftp_patcher = FTPPatcher(one=self.one) insertion = self.one.alyx.rest('insertions', 'read', id=self.eid) alf_path = self.one.path_from_eid(insertion['session']).joinpath( 'alf', insertion['name']) alf_path.mkdir(exist_ok=True, parents=True) # Make the channels.mlapdv dataset f_name = alf_path.joinpath('channels.mlapdv.npy') np.save(f_name, channels_mlapdv) files_to_register.append(f_name) # Make the channels.brainLocationIds dataset f_name = alf_path.joinpath( 'channels.brainLocationIds_ccf_2017.npy') np.save(f_name, channels_brainID) files_to_register.append(f_name) # Make the clusters.mlapdv dataset f_name = alf_path.joinpath('clusters.mlapdv.npy') np.save(f_name, clusters_mlapdv) files_to_register.append(f_name) # Make the clusters.brainLocationIds dataset f_name = alf_path.joinpath( 'clusters.brainLocationIds_ccf_2017.npy') np.save(f_name, clusters_brainID) files_to_register.append(f_name) # Make the clusters.brainLocationAcronym dataset f_name = alf_path.joinpath( 'clusters.brainLocationAcronyms_ccf_2017.npy') np.save(f_name, clusters_brainAcro) files_to_register.append(f_name) self.log.info("Writing datasets to FlatIron") ftp_patcher.create_dataset(path=files_to_register, created_by=self.one._par.ALYX_LOGIN) # Need to change channels stored on alyx as well as the stored key is not the same as the # latest key if upload_alyx: if alignment_key != self.align_keys_sorted[0]: histology.register_aligned_track(self.eid, channels_mlapdv / 1e6, chn_coords=SITES_COORDINATES, one=self.one, overwrite=True, channels=self.channels) ephys_traj = self.one.alyx.rest( 'trajectories', 'list', probe_insertion=self.eid, provenance='Ephys aligned histology track') patch_dict = {'json': self.alignments} self.one.alyx.rest('trajectories', 'partial_update', id=ephys_traj[0]['id'], data=patch_dict) return files_to_register
def upload_channels(self, alignment_key, upload_alyx, upload_flatiron): """ Upload channels to alyx and flatiron based on the alignment specified by the alignment key """ feature = np.array(self.alignments[alignment_key][0]) track = np.array(self.alignments[alignment_key][1]) try: meta_dset = self.one.list_datasets(self.insertion['session'], '*ap.meta', collection=f'raw_ephys_data/{self.insertion["name"]}') meta_file = self.one.load_dataset(self.insertion['session'], meta_dset[0].split('/')[-1], collection=f'raw_ephys_data/{self.insertion["name"]}', download_only=True) geometry = spikeglx.read_geometry(meta_file) chns = np.c_[geometry['x'], geometry['y']] except Exception as err: self.log.warning(f"Could not compute channel locations from meta file, errored with message: {err}. " f"Will use default Neuropixel 1 channels") geometry = trace_header(version=1) chns = np.c_[geometry['x'], geometry['y']] ephysalign = EphysAlignment(self.xyz_picks, chns[:, 1], track_prev=track, feature_prev=feature, brain_atlas=self.brain_atlas) channels_mlapdv = np.int32(ephysalign.get_channel_locations(feature, track) * 1e6) channels_atlas_id = ephysalign.get_brain_locations(channels_mlapdv / 1e6)['id'] # Need to change channels stored on alyx as well as the stored key is not the same as the latest key if upload_alyx: if alignment_key != self.align_keys_sorted[0]: histology.register_aligned_track(self.eid, channels_mlapdv / 1e6, chn_coords=chns, one=self.one, overwrite=True, channels=self.channels_flag, brain_atlas=self.brain_atlas) ephys_traj = self.one.alyx.get(f'/trajectories?&probe_insertion={self.eid}' '&provenance=Ephys aligned histology track', clobber=True) patch_dict = {'json': self.alignments} self.one.alyx.rest('trajectories', 'partial_update', id=ephys_traj[0]['id'], data=patch_dict) files_to_register = [] if upload_flatiron: ftp_patcher = FTPPatcher(one=self.one) alf_path = self.one.eid2path(self.insertion['session']).joinpath('alf', self.insertion["name"]) alf_path.mkdir(exist_ok=True, parents=True) f_name = alf_path.joinpath('electrodeSites.mlapdv.npy') np.save(f_name, channels_mlapdv) files_to_register.append(f_name) f_name = alf_path.joinpath('electrodeSites.brainLocationIds_ccf_2017.npy') np.save(f_name, channels_atlas_id) files_to_register.append(f_name) f_name = alf_path.joinpath('electrodeSites.localCoordinates.npy') np.save(f_name, chns) files_to_register.append(f_name) probe_collections = self.one.list_collections(self.insertion['session'], filename='channels*', collection=f'alf/{self.insertion["name"]}*') for collection in probe_collections: chns = self.one.load_dataset(self.insertion['session'], 'channels.localCoordinates', collection=collection) ephysalign = EphysAlignment(self.xyz_picks, chns[:, 1], track_prev=track, feature_prev=feature, brain_atlas=self.brain_atlas) channels_mlapdv = np.int32(ephysalign.get_channel_locations(feature, track) * 1e6) channels_atlas_id = ephysalign.get_brain_locations(channels_mlapdv / 1e6)['id'] alf_path = self.one.eid2path(self.insertion['session']).joinpath(collection) alf_path.mkdir(exist_ok=True, parents=True) f_name = alf_path.joinpath('channels.mlapdv.npy') np.save(f_name, channels_mlapdv) files_to_register.append(f_name) f_name = alf_path.joinpath('channels.brainLocationIds_ccf_2017.npy') np.save(f_name, channels_atlas_id) files_to_register.append(f_name) self.log.info("Writing datasets to FlatIron") ftp_patcher.create_dataset(path=files_to_register, created_by=self.one.alyx.user) return files_to_register
def plot_alignment(insertion, traj, ind=None): depths = SITES_COORDINATES[:, 1] xyz_picks = np.array(insertion['json']['xyz_picks']) / 1e6 alignments = traj['json'].copy() k = list(alignments.keys())[-1] # if only I had a Walrus available ! alignments = {k: alignments[k]} # Create a figure and arrange using gridspec widths = [1, 2.5] heights = [1] * len(alignments) gs_kw = dict(width_ratios=widths, height_ratios=heights) fig, axis = plt.subplots(len(alignments), 2, constrained_layout=True, gridspec_kw=gs_kw, figsize=(8, 9)) # Iterate over all alignments for trajectory # 1. Plot brain regions that channel pass through # 2. Plot coronal slice along trajectory with location of channels shown as red points # 3. Save results for each alignment into a dict - channels channels = {} for iK, key in enumerate(alignments): # Location of reference lines used for alignmnet feature = np.array(alignments[key][0]) track = np.array(alignments[key][1]) chn_coords = SITES_COORDINATES # Instantiate EphysAlignment object ephysalign = EphysAlignment(xyz_picks, depths, track_prev=track, feature_prev=feature) # Find xyz location of all channels xyz_channels = ephysalign.get_channel_locations(feature, track) # Find brain region that each channel is located in brain_regions = ephysalign.get_brain_locations(xyz_channels) # Add extra keys to store all useful information as one bunch object brain_regions['xyz'] = xyz_channels brain_regions['lateral'] = chn_coords[:, 0] brain_regions['axial'] = chn_coords[:, 1] # Store brain regions result in channels dict with same key as in alignment channel_info = {key: brain_regions} channels.update(channel_info) # For plotting -> extract the boundaries of the brain regions, as well as CCF label and colour region, region_label, region_colour, _ = ephysalign.get_histology_regions( xyz_channels, depths) # Make plot that shows the brain regions that channels pass through ax_regions = fig.axes[iK * 2] for reg, col in zip(region, region_colour): height = np.abs(reg[1] - reg[0]) bottom = reg[0] color = col / 255 ax_regions.bar(x=0.5, height=height, width=1, color=color, bottom=reg[0], edgecolor='w') ax_regions.set_yticks(region_label[:, 0].astype(int)) ax_regions.yaxis.set_tick_params(labelsize=8) ax_regions.get_xaxis().set_visible(False) ax_regions.set_yticklabels(region_label[:, 1]) ax_regions.spines['right'].set_visible(False) ax_regions.spines['top'].set_visible(False) ax_regions.spines['bottom'].set_visible(False) ax_regions.hlines([0, 3840], *ax_regions.get_xlim(), linestyles='dashed', linewidth=3, colors='k') # ax_regions.plot(np.ones(channel_depths_track.shape), channel_depths_track, '*r') # Make plot that shows coronal slice that trajectory passes through with location of channels # shown in red ax_slice = fig.axes[iK * 2 + 1] brain_atlas.plot_tilted_slice(xyz_channels, axis=1, ax=ax_slice) ax_slice.plot(xyz_channels[:, 0] * 1e6, xyz_channels[:, 2] * 1e6, 'r*') ax_slice.title.set_text(insertion['id'] + '\n' + str(key)) # Make sure the plot displays plt.show()
for iK, key in enumerate(alignments): # Location of reference lines used for alignmnet feature = np.array(alignments[key][0]) track = np.array(alignments[key][1]) # Instantiate EphysAlignment object ephysalign = EphysAlignment(xyz_picks, depths, track_prev=track, feature_prev=feature) # Find xyz location of all channels xyz_channels = ephysalign.get_channel_locations(feature, track) # Find brain region that each channel is located in brain_regions = ephysalign.get_brain_locations(xyz_channels) # Add extra keys to store all useful information as one bunch object brain_regions['xyz'] = xyz_channels brain_regions['lateral'] = chn_coords[:, 0] brain_regions['axial'] = chn_coords[:, 1] # Store brain regions result in channels dict with same key as in alignment channel_info = {key: brain_regions} channels.update(channel_info) # For plotting -> extract the boundaries of the brain regions, as well as CCF label and colour region, region_label, region_colour, _ = ephysalign.get_histology_regions( xyz_channels, depths) channel_depths_track = (ephysalign.feature2track(depths, feature, track) - ephysalign.track_extent[0])