def get_slice_images(self, xyz_channels): # First see if the histology file exists before attempting to connect with FlatIron and # download hist_dir = Path(self.sess_path.parent.parent, 'histology') hist_path_rd = None hist_path_gr = None if hist_dir.exists(): path_to_rd_image = glob.glob(str(hist_dir) + '/*RD.tif') if path_to_rd_image: hist_path_rd = tif2nrrd(Path(path_to_rd_image[0])) else: files = download_histology_data(self.subj, self.lab) if files is not None: hist_path_rd = files[1] path_to_gr_image = glob.glob(str(hist_dir) + '/*GR.tif') if path_to_gr_image: hist_path_gr = tif2nrrd(Path(path_to_gr_image[0])) else: files = download_histology_data(self.subj, self.lab) if files is not None: hist_path_gr = files[0] else: files = download_histology_data(self.subj, self.lab) if files is not None: hist_path_gr = files[0] hist_path_rd = files[1] index = self.brain_atlas.bc.xyz2i( xyz_channels)[:, self.brain_atlas.xyz2dims] ccf_slice = self.brain_atlas.image[index[:, 0], :, index[:, 2]] ccf_slice = np.swapaxes(ccf_slice, 0, 1) label_slice = self.brain_atlas._label2rgb( self.brain_atlas.label[index[:, 0], :, index[:, 2]]) label_slice = np.swapaxes(label_slice, 0, 1) width = [self.brain_atlas.bc.i2x(0), self.brain_atlas.bc.i2x(456)] height = [ self.brain_atlas.bc.i2z(index[0, 2]), self.brain_atlas.bc.i2z(index[-1, 2]) ] if hist_path_rd: hist_atlas_rd = atlas.AllenAtlas(hist_path=hist_path_rd) hist_slice_rd = hist_atlas_rd.image[index[:, 0], :, index[:, 2]] hist_slice_rd = np.swapaxes(hist_slice_rd, 0, 1) else: print('Could not find red histology image for this subject') hist_slice_rd = np.copy(ccf_slice) if hist_path_gr: hist_atlas_gr = atlas.AllenAtlas(hist_path=hist_path_gr) hist_slice_gr = hist_atlas_gr.image[index[:, 0], :, index[:, 2]] hist_slice_gr = np.swapaxes(hist_slice_gr, 0, 1) else: print('Could not find green histology image for this subject') hist_slice_gr = np.copy(ccf_slice) slice_data = { 'hist_rd': hist_slice_rd, 'hist_gr': hist_slice_gr, 'ccf': ccf_slice, 'label': label_slice, 'scale': np.array([(width[-1] - width[0]) / ccf_slice.shape[0], (height[-1] - height[0]) / ccf_slice.shape[1]]), 'offset': np.array([width[0], height[0]]) } return slice_data
def plot_histology_traj(subject_ID, x, y, provenance='Histology track', project='ibl_neuropixel_brainwide_01', atlas_type = 'sample-autofl', altas_borders = False, colour='y', linewidth=1): # TESTING: #subject_ID = 'NYU-12' #x = -2243 #y = -2000 #provenance='Histology track' #project='ibl_neuropixel_brainwide_01' #atlas_type = 'sample-autofl' #altas_borders = False #colour='y' #linewidth=1 from one.api import ONE import ibllib.atlas as atlas from ibllib.atlas import Insertion import atlaselectrophysiology.load_histology as hist import numpy as np import matplotlib.pyplot as plt # connect to ONE one = ONE() # FIRST get the PLANNED TRAJECTORY for repeated site: x=2243, y=2000 # first pass - to get a session id and probe name! - can retrieve from ANY trajectory! trajs = one.alyx.rest('trajectories', 'list', x=x, y=y, project=project) # get the lab string subjs = [sess['session']['subject'] for sess in trajs] labs = [sess['session']['lab'] for sess in trajs] lab = labs[ subjs.index(subject_ID)] # this returns index in labs where subject_ID is in subjs # Fetch Repeated Site planned trajectory metadata: planned = one.alyx.rest('trajectories', 'list', session=trajs[0]['session']['id'], probe=trajs[0]['probe_name'], provenance='planned') # create insertion object of Repeated Site from planned trajectory: ins = Insertion.from_dict(planned[0]) # create a trajectory object from this insertion: traj = ins.trajectory # generate pyplots of the brain: fig1, cax = plt.subplots() # new figure and axes objects - CORONAL fig2, sax = plt.subplots() # new figure and axes objects - SAGITTAL if 'sample-autofl' in atlas_type: # get just the autofl data as an atlas #TODO must modify this method! hist_paths = hist.download_histology_data(subject_ID, lab) ba_gr = atlas.AllenAtlas(hist_path=hist_paths[0]) # green histology channel autofl. #ba_rd = atlas.AllenAtlas(hist_path=hist_paths[1]) # red histology channel cm-dii # implementing tilted slice here to modify its cmap # get tilted slice of the green and red channel brain atlases # using the .image data as this contains the signal gr_tslice, width, height, depth = ba_gr.tilted_slice(ins.xyz, 1, volume = ba_gr.image) width = width * 1e6 height = height * 1e6 depth = depth * 1e6 cmap = plt.get_cmap('bone') # get the transfer function from y-axis to squeezed axis for second axe ab = np.linalg.solve(np.c_[height, height * 0 + 1], depth) height * ab[0] + ab[1] # linearly scale the values in 2d numpy arrays to between 0-255 (8bit) # Using gr_tslice min and max to scale the image # weirdly rd_in has very large min and max (problem with the original data acquisition?) so best to scale whole RGB with gr_in! gr_in = np.interp(gr_tslice, (gr_tslice.min(), gr_tslice.max()), (0, 255)) # join together red, green, blue numpy arrays to form a RGB image ALONG A NEW DIMENSION # NOTE need a blue component, have added a set of zeros as blue channel should be BLANK # NOTE2: converted to unit8 bit, as pyplot imshow() method only reads this format Z = np.stack([ np.zeros(np.shape(gr_tslice)).astype(dtype=np.uint8), gr_in.astype(dtype=np.uint8), np.zeros(np.shape(gr_tslice)).astype(dtype=np.uint8) ]) # transpose the columns to the FIRST one is LAST # i.e the NEW DIMENSION [3] is the LAST DIMENSION Zt = np.transpose(Z, axes=[1,2,0]) # can now add the RGB array to imshow() cax.imshow(Zt, interpolation='none', aspect='auto', extent=np.r_[width, height], cmap=cmap, vmin=np.min(gr_in), vmax=np.max(gr_in) ) elif 'sample-cci' in atlas_type: print('sample-cci') elif 'sample' in atlas_type: print('sample') else: # invalid atlas choice - return error: print("INVALID ATLAS CHOICE - must be 'CCF' 'sample-autofl', 'sample-dii', 'sample'") #return None # add a line of the Insertion object onto ax1 (cax - coronal) # plotting PLANNED insertion cax.plot(ins.xyz[:, 0] * 1e6, ins.xyz[:, 2] * 1e6, colour, linewidth=linewidth) sax.plot(ins.xyz[:, 1] * 1e6, ins.xyz[:, 2] * 1e6, colour, linewidth=linewidth) return {'cax': fig1, 'sax': fig2, 'x': x, 'y': y}
def plot_probe_trajectory_histology_sagittal( x, y, subject_ID, provenance='Planned', project='ibl_neuropixel_brainwide_01', remove_primary_axis=False): """Plot slice of Histology data along the insertion at [x,y] for subject ID. The slice through the Histology data can be made along any of the provenances of the probe at [x,y] for subject ID - Planned, Micro-manipulator, Histology track, Ephys aligned histology track. """ from one.api import ONE import ibllib.atlas as atlas from ibllib.atlas import Insertion import atlaselectrophysiology.load_histology as hist import numpy as np from scipy import ndimage import sys import matplotlib.pyplot as plt # connect to ONE one = ONE() # get list of all trajectories at [x,y], for project trajs = one.alyx.rest('trajectories', 'list', x=x, y=y, project=project) # keeping subjs and labs for look-up later if needed.. subjs = [sess['session']['subject'] for sess in trajs] labs = [sess['session']['lab'] for sess in trajs] #aidx = subjs.index(atlas_ID) sidx = subjs.index(subject_ID) # Fetch trajectory metadata for traj: traj = one.alyx.rest('trajectories', 'list', session=trajs[sidx]['session']['id'], probe=trajs[sidx]['probe_name'], provenance=provenance) if traj == []: raise Exception("No trajectory found with provenance: " + provenance) # get insertion object from ANY (the first) trajectory ins = Insertion.from_dict(traj[0]) axis_labels = np.array(['ml (µm)', 'dv (µm)', 'ap (µm)']) fig1, ax1 = plt.subplots() # new figure and axes objects - SAGITTAL lab = labs[sidx] # this returns index in labs where subject_ID is in subjs hist_paths = hist.download_histology_data(subject_ID, lab) # create the brain atlases from the data ba_gr = atlas.AllenAtlas( hist_path=hist_paths[0]) # green histology channel autofl. ba_rd = atlas.AllenAtlas( hist_path=hist_paths[1]) # red histology channel cm-dii # implementing tilted slice here to modify its cmap # get tilted slice of the green and red channel brain atlases # using the .image data as this contains the signal gr_tslice, width, height, depth = ba_gr.tilted_slice(ins.xyz, 0, volume=ba_gr.image) rd_tslice, width, height, depth = ba_rd.tilted_slice(ins.xyz, 0, volume=ba_rd.image) # gaussian filtered image of the whole 3D GR stack gr_g4 = ndimage.gaussian_filter(ba_gr.image, 4) ## SET CONTRAST based on min() and max() of hippocampus & thalamus pixels ONLY # use the gaussian blurred image for pixel values, use ba_gr.label width = width * 1e6 height = height * 1e6 depth = depth * 1e6 cmap = plt.get_cmap('bone') # get the transfer function from y-axis to squeezed axis for second axe ab = np.linalg.solve(np.c_[height, height * 0 + 1], depth) height * ab[0] + ab[1] # linearly scale the values in 2d numpy arrays to between 0-255 (8bit) # Using MEDIAN FILTERED (radius 3) gr_tslice min and max to scale the image # weirdly rd_in has very large min and max (problem with the original data acquisition?) so best to scale whole RGB with gr_in/1.5! #gr_ts_m3 = ndimage.median_filter(gr_tslice, 3) #gr_ts_m6 = ndimage.median_filter(gr_tslice, 6) #gr_ts_m8 = ndimage.median_filter(gr_tslice, 8) #rd_ts_m3 = ndimage.median_filter(rd_tslice, 3) #gr_in = np.interp(gr_tslice, (gr_ts_m3.min(), gr_ts_m3.max()), (0, 255)) #gr_in = np.interp(gr_tslice, (gr_m4.min(), gr_m4.max()), (0, 255)) #gr_in = np.interp(gr_tslice, (gr_ts_m8.min(), gr_ts_m8.max()), (0, 255)) gr_in = np.interp(gr_tslice, (gr_g4.min(), gr_g4.max()), (0, 255)) rd_in = np.interp(rd_tslice, (rd_tslice.min(), rd_tslice.max() / 3), (0, 255)) # original normalisation gr_in = np.interp(gr_tslice, (gr_tslice.min(), gr_tslice.max()), (0, 255)) rd_in = np.interp(rd_tslice, (gr_tslice.min(), gr_tslice.max() / 1.5), (0, 255)) # join together red, green, blue numpy arrays to form a RGB image ALONG A NEW DIMENSION # NOTE need a blue component, have added a set of zeros as blue channel should be BLANK # NOTE2: converted to unit8 bit, as pyplot imshow() method only reads this format Z = np.stack([ rd_in.astype(dtype=np.uint8), gr_in.astype(dtype=np.uint8), np.zeros(np.shape(gr_tslice)).astype(dtype=np.uint8) ]) # transpose the columns to the FIRST one is LAST # i.e the NEW DIMENSION [3] is the LAST DIMENSION Zt = np.transpose(Z, axes=[1, 2, 0]) # can now add the RGB array to imshow() ax1.imshow(Zt, interpolation='none', aspect='auto', extent=np.r_[width, height], cmap=cmap, vmin=np.min(gr_in), vmax=np.max(gr_in)) sec_ax = ax1.secondary_yaxis('right', functions=(lambda x: x * ab[0] + ab[1], lambda y: (y - ab[1]) / ab[0])) ax1.set_xlabel(axis_labels[0], fontsize=8) ax1.set_ylabel(axis_labels[1], fontsize=8) sec_ax.set_ylabel(axis_labels[2], fontsize=8) #xmn = np.min(xCoords) - 500 #xmz = np.max(xCoords) + 500 xmn = np.min(ins.xyz[:, 0]) * 1e6 - 1000 xmz = np.max(ins.xyz[:, 0]) * 1e6 + 1000 ax1.set_xlim(xmn, xmz) # ensure the resized xlim is not stretched! ax1.axes.set_aspect('equal') ax1.tick_params(axis='x', labelrotation=90) ax1.tick_params(axis='x', labelsize=8) ax1.tick_params(axis='y', labelsize=8) sec_ax.tick_params(axis='y', labelsize=8) if remove_primary_axis: #ax1.get_xaxis().set_visible(False) ax1.get_yaxis().set_visible(False) plt.tight_layout() # tighten layout around xlabel & ylabel return fig1
def plot_atlas_traj(x, y, atlas_ID = 'CCF', provenance='Planned', subject_ID = 'Planned', remove_primary_axis = False, project='ibl_neuropixel_brainwide_01', altas_borders = False, colour='y', linewidth=1, axc = None, axs = None ): """Plot atlas trajectory Generates coronal and sagittal plots of the atlas along trajectory at x,y. Parameters ---------- x : int x insertion coord in µm. Eg. repeated site is -2243 y : int y insertion coord in µm. Eg. repeated site is -2000. atlas_ID : str, optional Atlas data to plot channels on: 'CCF' - Allen CCF, or sample data. If using sample data as atlas, must set this string to the subject ID to collect the data from flatiron. The default is 'CCF'. provenance : str, optional Trajectory provenance to use when generating the tilted slice. Choose from: Planned, Micro-manipulator, Histology, E-phys aligned. The default is 'Planned'. subject_ID : str, optional The subject which to retrieve the trajectory from. This trajectory defines the tilted slice through the atlas. The default is 'Planned', which means the planned trajectory is used (ignoring the provenance option below!). Can be set to any valid subject_ID with a trajectory at x,y. remove_primary_axis : bool, optional Boolean whether to remove the primary y-axis labels from the plot. Useful to remove if concatenating plots together. project : str, optional Project from which data should be retrieved. The default is 'ibl_neuropixel_brainwide_01'. atlas_borders : bool, optional Boolean whether to add the atlas borders to the atlas image. False by default. axc : AxesSubplot, None MUST pass an AxesSubplot object for plotting to! For coronal plot. axs : AxesSubplot, None MUST pass an AxesSubplot object for plotting to! For sagittal plot. Returns ------- fig_dict : dictionary Dictionary containing the pyplot Figure objects for coronal (cax) and cagittal (sax), and the insertion coordinates (x) and (y). """ # TESTING: #x = -2243 #y = -2000 #atlas_ID = 'CSHL052' #provenance='Histology track' #remove_primary_axis = False #subject_ID = 'NYUU-12' #project='ibl_neuropixel_brainwide_01' #altas_borders = False #colour='y' #linewidth=1 from one.api import ONE import ibllib.atlas as atlas from ibllib.atlas import Insertion import atlaselectrophysiology.load_histology as hist import numpy as np import sys import matplotlib.pyplot as plt # connect to ONE one = ONE() # get the PLANNED TRAJECTORY for x,y insertion trajs = one.alyx.rest('trajectories', 'list', x=x, y=y, project=project) # generate pyplots of the brain: #fig1, ax1 = plt.subplots() # new figure and axes objects - CORONAL #fig2, ax2 = plt.subplots() # new figure and axes objects - SAGITTAL ax1 = axc ax2 = axs axis_labels = np.array(['ml (µm)', 'dv (µm)', 'ap (µm)']) if 'CCF' in atlas_ID: # want to use the CCF data for the plot if subject_ID == 'Planned': sidx=0 provenance='Planned' # get the Planned trajectory from first subject! else: subjs = [sess['session']['subject'] for sess in trajs] labs = [sess['session']['lab'] for sess in trajs] sidx = subjs.index(subject_ID) # Fetch planned trajectory metadata for ANY of the traj in trajs (just use first index!): planned = one.alyx.rest('trajectories', 'list', session=trajs[sidx]['session']['id'], probe=trajs[0]['probe_name'], provenance=provenance) # create insertion object from planned trajectory: ins = Insertion.from_dict(planned[0]) # create a trajectory object from this insertion: traj = ins.trajectory # get CCF brain atlas for generating the figures: brain_atlas = atlas.AllenAtlas(res_um=25) # this is an instance of ibllib.atlas.atlas.AllenAtlas, sub-class of # ibllib.atlas.atlas.BrainAtlas # contains: # self.image: image volume (ap, ml, dv) # self.label: label volume (ap, ml, dv) # self.bc: atlas.BrainCoordinate object # self.regions: atlas.BrainRegions object # self.top: 2d np array (ap, ml) containing the z-coordinate (m) of the surface of the brain # self.dims2xyz and self.zyz2dims: map image axis order to xyz coordinates order # use method in BrainAtlas to plot a tilted slice onto ax1: ax1 = brain_atlas.plot_tilted_slice(ins.xyz, axis=1, ax=ax1) # CORONAL ax2 = brain_atlas.plot_tilted_slice(ins.xyz, axis=0, ax=ax2) # SAGITTAL if remove_primary_axis: #ax1.get_xaxis().set_visible(False) ax1.get_yaxis().set_visible(False) #ax2.get_xaxis().set_visible(False) ax2.get_yaxis().set_visible(False) else: # hopefully atlas_ID matches an ID in subjs! in which case, use THIS SUBJECTS FLUOESCENCE DATA! subject_ID = atlas_ID # ensure subject and atlas are the SAME # keeping subjs and labs for look-up later if needed.. subjs = [sess['session']['subject'] for sess in trajs] labs = [sess['session']['lab'] for sess in trajs] aidx = subjs.index(atlas_ID) sidx = subjs.index(subject_ID) # Fetch trajectory metadata for traj: traj = one.alyx.rest('trajectories', 'list', session=trajs[sidx]['session']['id'], probe=trajs[sidx]['probe_name'], provenance=provenance) if traj == []: raise Exception("No trajectory found with provenance: " + provenance) # create insertion object from planned trajectory: ins = Insertion.from_dict(traj[0]) # download the data - using Mayo's method! lab = labs[ aidx ] # this returns index in labs where atlas_ID is in subjs hist_paths = hist.download_histology_data(atlas_ID, lab) # create the brain atlases from the data ba_gr = atlas.AllenAtlas(hist_path=hist_paths[0]) # green histology channel autofl. ba_rd = atlas.AllenAtlas(hist_path=hist_paths[1]) # red histology channel cm-dii # implementing tilted slice here to modify its cmap # get tilted slice of the green and red channel brain atlases # using the .image data as this contains the signal gr_tslice, width, height, depth = ba_gr.tilted_slice(ins.xyz, 1, volume = ba_gr.image) rd_tslice, width, height, depth = ba_rd.tilted_slice(ins.xyz, 1, volume = ba_rd.image) width = width * 1e6 height = height * 1e6 depth = depth * 1e6 cmap = plt.get_cmap('bone') # get the transfer function from y-axis to squeezed axis for second axe ab = np.linalg.solve(np.c_[height, height * 0 + 1], depth) height * ab[0] + ab[1] # linearly scale the values in 2d numpy arrays to between 0-255 (8bit) # Using gr_tslice min and max to scale the image # weirdly rd_in has very large min and max (problem with the original data acquisition?) so best to scale whole RGB with gr_in/1.5! gr_in = np.interp(gr_tslice, (gr_tslice.min(), gr_tslice.max()), (0, 255)) rd_in = np.interp(rd_tslice, (gr_tslice.min(), gr_tslice.max()/1.5), (0, 255)) # join together red, green, blue numpy arrays to form a RGB image ALONG A NEW DIMENSION # NOTE need a blue component, have added a set of zeros as blue channel should be BLANK # NOTE2: converted to unit8 bit, as pyplot imshow() method only reads this format Z = np.stack([ rd_in.astype(dtype=np.uint8), gr_in.astype(dtype=np.uint8), np.zeros(np.shape(gr_tslice)).astype(dtype=np.uint8) ]) # transpose the columns to the FIRST one is LAST # i.e the NEW DIMENSION [3] is the LAST DIMENSION Zt = np.transpose(Z, axes=[1,2,0]) # can now add the RGB array to imshow() ax1.imshow(Zt, interpolation='none', aspect='auto', extent=np.r_[width, height], cmap=cmap, vmin=np.min(gr_in), vmax=np.max(gr_in) ) sec_ax = ax1.secondary_yaxis('right', functions=( lambda x: x * ab[0] + ab[1], lambda y: (y - ab[1]) / ab[0])) ax1.set_xlabel(axis_labels[0], fontsize=8) ax1.set_ylabel(axis_labels[1], fontsize=8) sec_ax.set_ylabel(axis_labels[2], fontsize=8) #xmn = np.min(xCoords) - 500 #xmz = np.max(xCoords) + 500 xmn = np.min(ins.xyz[:, 0]) * 1e6 - 1000 xmz = np.max(ins.xyz[:, 0]) *1e6 + 1000 ax1.set_xlim(xmn, xmz) # ensure the resized xlim is not stretched! ax1.axes.set_aspect('equal') ax1.tick_params(axis='x', labelrotation = 90) ax1.tick_params(axis='x', labelsize = 8) ax1.tick_params(axis='y', labelsize = 8) sec_ax.tick_params(axis='y', labelsize = 8) if remove_primary_axis: #ax1.get_xaxis().set_visible(False) ax1.get_yaxis().set_visible(False) gr_tslice, width, height, depth = ba_gr.tilted_slice(ins.xyz, 0, volume = ba_gr.image) rd_tslice, width, height, depth = ba_rd.tilted_slice(ins.xyz, 0, volume = ba_rd.image) width = width * 1e6 height = height * 1e6 depth = depth * 1e6 cmap = plt.get_cmap('bone') # get the transfer function from y-axis to squeezed axis for second axe ab = np.linalg.solve(np.c_[height, height * 0 + 1], depth) height * ab[0] + ab[1] # linearly scale the values in 2d numpy arrays to between 0-255 (8bit) # Using gr_tslice min and max to scale the image # weirdly rd_in has very large min and max (problem with the original data acquisition?) so best to scale whole RGB with gr_in/1.5! gr_in = np.interp(gr_tslice, (gr_tslice.min(), gr_tslice.max()), (0, 255)) rd_in = np.interp(rd_tslice, (gr_tslice.min(), gr_tslice.max()/1.5), (0, 255)) # join together red, green, blue numpy arrays to form a RGB image ALONG A NEW DIMENSION # NOTE need a blue component, have added a set of zeros as blue channel should be BLANK # NOTE2: converted to unit8 bit, as pyplot imshow() method only reads this format Z = np.stack([ rd_in.astype(dtype=np.uint8), gr_in.astype(dtype=np.uint8), np.zeros(np.shape(gr_tslice)).astype(dtype=np.uint8) ]) # transpose the columns to the FIRST one is LAST # i.e the NEW DIMENSION [3] is the LAST DIMENSION Zt = np.transpose(Z, axes=[1,2,0]) # can now add the RGB array to imshow() ax2.imshow(Zt, interpolation='none', aspect='auto', extent=np.r_[width, height], cmap=cmap, vmin=np.min(gr_in), vmax=np.max(gr_in) ) #start = ins.xyz[:, 1] * 1e6 #end = ins.xyz[:, 2] * 1e6 #xCoords = np.array([start[0], end[0]]) sec_ax = ax2.secondary_yaxis('right', functions=( lambda x: x * ab[0] + ab[1], lambda y: (y - ab[1]) / ab[0])) ax2.set_xlabel(axis_labels[2], fontsize=8) ax2.set_ylabel(axis_labels[1], fontsize=8) sec_ax.set_ylabel(axis_labels[0], fontsize=8) xmn = np.min(ins.xyz[:, 1]) * 1e6 - 1000 xmz = np.max(ins.xyz[:, 1]) *1e6 + 1000 ax2.set_xlim(xmn, xmz) # ensure the resized xlim is not stretched! ax2.axes.set_aspect('equal') ax2.tick_params(axis='x', labelrotation = 90) ax2.tick_params(axis='x', labelsize = 8) ax2.tick_params(axis='y', labelsize = 8) sec_ax.tick_params(axis='y', labelsize = 8) if remove_primary_axis: #ax2.get_xaxis().set_visible(False) ax2.get_yaxis().set_visible(False) #plt.tight_layout() # tighten layout around xlabel & ylabel # add a line of the Insertion object onto ax1 (cax - coronal) # plotting PLANNED insertion #ax1.plot(ins.xyz[:, 0] * 1e6, ins.xyz[:, 2] * 1e6, colour, linewidth=linewidth) #ax2.plot(ins.xyz[:, 1] * 1e6, ins.xyz[:, 2] * 1e6, colour, linewidth=linewidth) return {'cax': ax1, 'sax': ax2, 'x': x, 'y': y, 'atlas_ID': atlas_ID, 'provenance': provenance, 'subject_id': subject_ID }
def plot_probe_trajectory_histology(x, y, subject_ID, axc, axs, provenance='Planned', project='ibl_neuropixel_brainwide_01', gr_percentile_min=0.2, rd_percentile_min=1, rd_percentile_max=99.99, font_size=8, label_size=8): """Plot slices of Histology data along the insertion at [x,y] for subject ID. Slices made in coronal and sagittal planes. The slices through the Histology data can be made along any of the provenances of the probe at [x,y] for subject ID - Planned, Micro-manipulator, Histology track, Ephys aligned histology track. axc : AxesSubplot, None MUST pass an AxesSubplot object for plotting to! For coronal plot. axs : AxesSubplot, None MUST pass an AxesSubplot object for plotting to! For sagittal plot. """ from one.api import ONE import ibllib.atlas as atlas from ibllib.atlas import Insertion import atlaselectrophysiology.load_histology as hist import numpy as np from scipy import ndimage import sys import matplotlib.pyplot as plt # connect to ONE one = ONE() # get list of all trajectories at [x,y], for project trajs = one.alyx.rest('trajectories', 'list', x=x, y=y, project=project) # keeping subjs and labs for look-up later if needed.. subjs = [sess['session']['subject'] for sess in trajs] labs = [sess['session']['lab'] for sess in trajs] #aidx = subjs.index(atlas_ID) sidx = subjs.index(subject_ID) # Fetch trajectory metadata for traj: traj = one.alyx.rest('trajectories', 'list', session=trajs[sidx]['session']['id'], probe=trajs[sidx]['probe_name'], provenance=provenance) if traj == []: raise Exception("No trajectory found with provenance: " + provenance) # get insertion object from ANY (the first) trajectory ins = Insertion.from_dict(traj[0]) axis_labels = np.array(['ml (µm)', 'dv (µm)', 'ap (µm)']) #fig1, ax1 = plt.subplots() # new figure and axes objects - CORONAL #fig2, ax2 = plt.subplots() # new figure and axes objects - SAGITTAL # set axes to local variables ax1 = axc ax2 = axs lab = labs[sidx] # this returns index in labs where subject_ID is in subjs hist_paths = hist.download_histology_data(subject_ID, lab) # create the brain atlases from the data ba_gr = atlas.AllenAtlas( hist_path=hist_paths[0]) # green histology channel autofl. ba_rd = atlas.AllenAtlas( hist_path=hist_paths[1]) # red histology channel cm-dii # CORONAL # implementing tilted slice here to modify its cmap # get tilted slice of the green and red channel brain atlases # using the .image data as this contains the signal gr_tslice, width, height, depth = ba_gr.tilted_slice(ins.xyz, 1, volume=ba_gr.image) rd_tslice, width, height, depth = ba_rd.tilted_slice(ins.xyz, 1, volume=ba_rd.image) gr_tslice_roi = gr_tslice[ 120:240, 150:300] # isolate large slice over thalamus for max pixel value rd_tslice_roi = rd_tslice[120:240, 150:300] width = width * 1e6 height = height * 1e6 depth = depth * 1e6 cmap = plt.get_cmap('bone') # get the transfer function from y-axis to squeezed axis for second axe ab = np.linalg.solve(np.c_[height, height * 0 + 1], depth) height * ab[0] + ab[1] # linearly scale the values in 2d numpy arrays to between 0-255 (8bit) # Using gr_tslice min and gr_tslice_roi max to scale autofl. # using rd_tslice min and percentile (99.99 default) to scale CM-DiI gr_in = np.interp( gr_tslice, (np.percentile(gr_tslice, gr_percentile_min), gr_tslice_roi.max()), (0, 255)) rd_in = np.interp(rd_tslice, (np.percentile(rd_tslice, rd_percentile_min), np.percentile(rd_tslice, rd_percentile_max)), (0, 255)) # join together red, green, blue numpy arrays to form a RGB image ALONG A NEW DIMENSION # NOTE need a blue component, have added a set of zeros as blue channel should be BLANK # NOTE2: converted to unit8 bit, as pyplot imshow() method only reads this format Z = np.stack([ rd_in.astype(dtype=np.uint8), gr_in.astype(dtype=np.uint8), np.zeros(np.shape(gr_tslice)).astype(dtype=np.uint8) ]) # transpose the columns to the FIRST one is LAST # i.e the NEW DIMENSION [3] is the LAST DIMENSION Zt = np.transpose(Z, axes=[1, 2, 0]) # can now add the RGB array to imshow() ax1.imshow(Zt, interpolation='none', aspect='auto', extent=np.r_[width, height], cmap=cmap, vmin=np.min(gr_in), vmax=np.max(gr_in)) sec_ax = ax1.secondary_yaxis('right', functions=(lambda x: x * ab[0] + ab[1], lambda y: (y - ab[1]) / ab[0])) ax1.set_xlabel(axis_labels[0], fontsize=font_size) ax1.set_ylabel(axis_labels[1], fontsize=font_size) sec_ax.set_ylabel(axis_labels[2], fontsize=font_size) ax1.tick_params(axis='x', labelrotation=90) ax1.tick_params(axis='x', labelsize=label_size) ax1.tick_params(axis='y', labelsize=label_size) sec_ax.tick_params(axis='y', labelsize=label_size) # SAGITTAL # implementing tilted slice here to modify its cmap # get tilted slice of the green and red channel brain atlases # using the .image data as this contains the signal gr_tslice, width, height, depth = ba_gr.tilted_slice(ins.xyz, 0, volume=ba_gr.image) rd_tslice, width, height, depth = ba_rd.tilted_slice(ins.xyz, 0, volume=ba_rd.image) width = width * 1e6 height = height * 1e6 depth = depth * 1e6 cmap = plt.get_cmap('bone') # get the transfer function from y-axis to squeezed axis for second axe ab = np.linalg.solve(np.c_[height, height * 0 + 1], depth) height * ab[0] + ab[1] # linearly scale the values in 2d numpy arrays to between 0-255 (8bit) # Using gr_tslice min and max to scale the image # weirdly rd_in has very large min and max (problem with the original data acquisition?) so best to scale whole RGB with gr_in/1.5! gr_in = np.interp(gr_tslice, (gr_tslice.min(), gr_tslice.max()), (0, 255)) rd_in = np.interp(rd_tslice, (gr_tslice.min(), gr_tslice.max() / 1.5), (0, 255)) # join together red, green, blue numpy arrays to form a RGB image ALONG A NEW DIMENSION # NOTE need a blue component, have added a set of zeros as blue channel should be BLANK # NOTE2: converted to unit8 bit, as pyplot imshow() method only reads this format Z = np.stack([ rd_in.astype(dtype=np.uint8), gr_in.astype(dtype=np.uint8), np.zeros(np.shape(gr_tslice)).astype(dtype=np.uint8) ]) # transpose the columns to the FIRST one is LAST # i.e the NEW DIMENSION [3] is the LAST DIMENSION Zt = np.transpose(Z, axes=[1, 2, 0]) # can now add the RGB array to ax2 via imshow() ax2.imshow(Zt, interpolation='none', aspect='auto', extent=np.r_[width, height], cmap=cmap, vmin=np.min(gr_in), vmax=np.max(gr_in)) #start = ins.xyz[:, 1] * 1e6 #end = ins.xyz[:, 2] * 1e6 #xCoords = np.array([start[0], end[0]]) sec_ax = ax2.secondary_yaxis('right', functions=(lambda x: x * ab[0] + ab[1], lambda y: (y - ab[1]) / ab[0])) ax2.set_xlabel(axis_labels[2], fontsize=font_size) ax2.set_ylabel(axis_labels[1], fontsize=font_size) sec_ax.set_ylabel(axis_labels[0], fontsize=font_size) ax2.tick_params(axis='x', labelrotation=90) ax2.tick_params(axis='x', labelsize=label_size) ax2.tick_params(axis='y', labelsize=label_size) sec_ax.tick_params(axis='y', labelsize=label_size) plt.tight_layout() # tighten layout around xlabel & ylabel # add a line of the Insertion object onto ax1 (cax - coronal) # plotting PLANNED insertion #ax1.plot(ins.xyz[:, 0] * 1e6, ins.xyz[:, 2] * 1e6, colour, linewidth=linewidth) #ax2.plot(ins.xyz[:, 1] * 1e6, ins.xyz[:, 2] * 1e6, colour, linewidth=linewidth) return { 'coronal-slice': ax1, 'sagittal-slice': ax2, 'x': x, 'y': y, 'provenance': provenance, 'subject_id': subject_ID }