Exemple #1
0
    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
Exemple #2
0
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}
Exemple #3
0
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
Exemple #4
0
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 }
Exemple #5
0
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
    }