コード例 #1
0
ファイル: LOCtoolbox.py プロジェクト: ThomasWalter/rna-loc
def process_file(FQ_file,
                 img_size=(960, 960),
                 bin_prop=(0, 90, 20),
                 channels={'cells': 'C3-'},
                 data_category={'roi': ''},
                 annotation_extension='__RoiSet.zip',
                 img_extension='.tif',
                 show_plot=None,
                 Zrange=None,
                 dZ=2):
    '''
    Function uses annotations generated in FIJI and creates mask based
    on the specified parameters. The resulting files are zipped and be
    used for training of a neural network with ImJoy.

    Args:


        Zrange [tuple, 2 elements]. [Optional] Tuple specifying minimum and maximum z-value that is considered
        in analysis.

        bin_prop [Tuple, 3 elements]. Specifies the bins for the histograms (min, max,delta).

    '''
    # Get input args. Has to be FIRST call!
    input_args = locals()

    # Make sure input args are correct - assignments with 0 can come from ImJoy
    if Zrange[0] == 0 or Zrange[1] == 0:
        Zrange = None

    if bin_prop[1] == 0 or bin_prop[1] == 0:
        bin_prop = (0, 90, 20)

    ## Prepare folder to save results
    drive, path_and_file = os.path.splitdrive(FQ_file)
    path_results, file_results = os.path.split(path_and_file)
    file_base, ext = os.path.splitext(file_results)

    path_save = os.path.join(
        path_results, file_base,
        'MembDist_{}'.format(time.strftime("%y%m%d-%H%M", time.localtime())))
    if not os.path.isdir(path_save):
        os.makedirs(path_save)

    ## Open FQ results
    fq_dict = FQtoolbox.read_FQ_matlab(FQ_file)
    spots_all = FQtoolbox.get_rna(fq_dict)
    Zrna = spots_all[:, [18]]

    # Open annotations
    print('Open annotations')
    if 'RoiSet.zip' in annotation_extension:

        path_annot = os.path.join(path_results, 'zstack_segmentation')
        folderImporter = annotationImporter.FolderImporter(
            channels=channels,
            data_category=data_category,
            annot_ext=annotation_extension)
        annotDict = folderImporter.load(path_annot)
        print('average roi size:', annotDict['roi_size'])

        # Generate binary masks for a selected data-set
        binaryGen = maskGenerator.BinaryMaskGenerator(erose_size=5,
                                                      obj_size_rem=500,
                                                      save_indiv=True)

        # The generate function uses as an input the sub-dictionary for one data-category and one channel
        annotatFiles = annotDict['roi']['cells']
        maskDict = binaryGen.generate(annotatFiles)

        #Use a loop and the update function to add the mask dictionary to the loaded annotation dictonary\n",
        for k, v in annotatFiles.items():
            v.update(maskDict[k])

    # Bins of histogram
    binsHist = np.arange(bin_prop[0], bin_prop[1], bin_prop[2])
    width = 0.8 * (binsHist[1] - binsHist[0])
    center = (binsHist[:-1] + binsHist[1:]) / 2

    # Other parameters for calculation
    dist_membr_RNA = np.array([])
    dist_membr_pix = np.array([])
    idx = 0

    # Loop over all z-slices
    hist_slice = {}
    print('Loop over slices')
    for k, v in annotatFiles.items():

        print(f'Slice: {k}')
        # Get Z coordinate
        m = re.search('.*_Z([0-9]*)\.tif', k)
        Zmask = int(m.group(1))

        # Check if outside of specified z range
        if Zrange is not None:
            if (Zmask <= Zrange[0]) or (Zmask >= Zrange[1]):
                print('Slice outside of range')
                continue

        # Get z-range for loop
        Zloop = np.logical_and(Zrna <= Zmask + dZ,
                               Zrna >= Zmask - dZ).flatten()
        spots_loop = spots_all[Zloop, :]
        spots_loop_XY = spots_loop[:, [16, 17]].astype(int)

        # Distance transform
        dist_membr = ndimage.distance_transform_edt(
            ~v['mask_edge'])  # Negate mask

        # Indices have to be inversed to access array
        dist_membr_RNA_loop = dist_membr[spots_loop_XY[:, 0], spots_loop_XY[:,
                                                                            1]]

        # Get distance from membrane for all pixel in the cell
        mask_all = v['mask_fill'] + v['mask_edge']
        dist_membr_pix_loop = dist_membr[mask_all]

        # Save values
        if idx == 0:
            dist_membr_RNA = np.copy(dist_membr_RNA_loop)
            dist_membr_pix = np.copy(dist_membr_pix_loop)
        else:
            dist_membr_RNA = np.append(dist_membr_RNA,
                                       dist_membr_RNA_loop,
                                       axis=0)
            dist_membr_pix = np.append(dist_membr_pix,
                                       dist_membr_pix_loop,
                                       axis=0)
        idx += 1

        # Calculate histograms
        histRNA, bins = np.histogram(dist_membr_RNA_loop,
                                     binsHist,
                                     density=False)
        histpix, bins = np.histogram(dist_membr_pix_loop,
                                     binsHist,
                                     density=False)

        histRNAnorm = histRNA / histRNA.sum()
        histpixnorm = histpix / histpix.sum()

        histRNAnormPix = np.divide(histRNAnorm, histpixnorm)
        histRNAnormPix = np.nan_to_num(histRNAnormPix)

        hist_plot = {
            'width': width,
            'center': center,
            'bins': bins,
            'histRNA': histRNA,
            'histpix': histpix,
            'histRNAnormPix': histRNAnormPix
        }

        # Plot results
        name_save = os.path.join(path_save, f'Z-{Zmask}.png')
        plot_results_slice(Zmask, v, mask_all, spots_loop_XY, dist_membr,
                           hist_plot, name_save)

        hist_slice[f'Z{Zmask}'] = hist_plot

    # Analyze all slices
    histRNA_all, bins = np.histogram(dist_membr_RNA, binsHist, density=False)
    histRNA_all_norm = histRNA_all / histRNA_all.sum()

    # Renormalize with pixel counts
    histpix_all, bins = np.histogram(dist_membr_pix, binsHist, density=False)
    histpix_all_norm = histpix_all / histpix_all.sum()

    hist_RNA_all_normPix = np.divide(histRNA_all_norm, histpix_all_norm)
    hist_RNA_all_normPix = np.nan_to_num(hist_RNA_all_normPix)

    hist_plot_all = {
        'width': width,
        'center': center,
        'bins': bins,
        'histRNA_all': histRNA_all,
        'histRNA_all_norm': histRNA_all_norm,
        'histpix_all_norm': histpix_all_norm,
        'hist_RNA_all_normPix': hist_RNA_all_normPix
    }
    name_save = os.path.join(path_save, '_DistanceEnrichmentSummary.png')
    plot_results_all(hist_plot_all, name_save)
    if show_plot:
        show_plot(name_save)

    # Save entire analysis results as json
    input_args.pop('show_plot', None)
    analysis_results = {
        'args': input_args,
        'hist_all': hist_plot_all,
        'hist_slice': hist_slice
    }

    name_json = os.path.join(path_save, 'DataAll.json')

    with open(name_json, 'w') as fp:
        json.dump(analysis_results,
                  fp,
                  sort_keys=True,
                  indent=4,
                  cls=NumpyEncoder)

    # Save histogram of pooled data as csv
    name_csv = os.path.join(path_save, '_HistogramPooled.csv')
    hist_plot_all.pop('bins', None)
    hist_plot_all.pop('width', None)
    csv_header = ';'.join(hist_plot_all.keys())
    hist_values = np.array(list(hist_plot_all.values())).transpose()
    np.savetxt(name_csv,
               hist_values,
               delimiter=";",
               fmt='%f',
               header=csv_header,
               comments='')

    return analysis_results
コード例 #2
0
def calc_nuclear_enrichment(FQ_file, binsHist):

    ## Get folder
    drive, path_and_file = os.path.splitdrive(FQ_file)
    path_results, file_results = os.path.split(path_and_file)

    # *************************************************************************
    # Load nuclear outline

    # Generate binary masks for a selected data-set
    binaryGen = maskGenerator.BinaryMaskGenerator(erose_size=5,
                                                  obj_size_rem=500,
                                                  save_indiv=True,
                                                  progress_callback=None)

    ## Import annotations for nuclei
    path_annot = os.path.join(drive, path_results, 'zstack_segmentation')
    folderImporter = annotationImporter.FolderImporter(
        channels={'nuclei': 'C4-'},
        data_category={'roi': ''},
        annot_ext='__RoiSet.zip',
        progress_callback=None)
    annotDict = folderImporter.load(path_annot)
    print('average roi size:', annotDict['roi_size'])

    # The generate function uses as an input the sub-dictionary for one data-category and one channel
    annotatFiles = annotDict['roi']['nuclei']
    mask_dict_nuclei = binaryGen.generate(annotatFiles)

    keys_delete = []
    for k, v in annotatFiles.items():

        # Make sure that key in present in mask, otherwise delete
        if k in mask_dict_nuclei:
            v.update(mask_dict_nuclei[k])

        else:
            keys_delete.append(k)

    # *************************************************************************
    #  Load embryo outline
    file_embryo = os.path.join(drive, path_results, 'embryo_contour.roi')

    # Conver dictionary & get size of ROIS
    roi_import = read_roi_file(file_embryo)
    roi_dict = {}
    roi_dict['embryo'] = {}
    roi_dict['embryo']['type'] = roi_import['embryo_contour']['type']
    roi_dict['embryo']['pos'] = np.column_stack(
        (roi_import['embryo_contour']['y'], roi_import['embryo_contour']['x']))

    # Assemble structure to call mask generator
    image_size = annotatFiles.values().__iter__().__next__()['image'].shape
    image_fake = np.zeros(image_size, dtype=np.uint8)

    annotat_files_embryo = {}
    annotat_files_embryo['embryo_contour'] = {}
    annotat_files_embryo['embryo_contour']['roi'] = roi_dict
    annotat_files_embryo['embryo_contour']['image'] = image_fake

    mask_dict_embryo = binaryGen.generate(annotat_files_embryo)
    mask_embryo = mask_dict_embryo['embryo_contour']['mask_fill']

    # *************************************************************************
    #  Load and analyze FQ results

    fq_dict = FQtoolbox.read_FQ_matlab(file_load)
    spots_all = FQtoolbox.get_rna(fq_dict)

    # Z position in pixel
    Zrna = np.divide(spots_all[:, [2]],
                     fq_dict['settings']['microscope']['pix_z']).astype(int)

    # Other parameters for calculation
    dist_membr_RNA = np.array([])
    dist_membr_pix = np.array([])
    idx = 0

    # Loop over all z-slices
    print(' == Loop over slices')

    for idx_file, (k_annot, v_annot) in enumerate(annotatFiles.items()):

        print(f'Slice: {k_annot}')

        # Get Z coordinate
        m = re.search('.*_Z([0-9]*)\.tif', k_annot)
        Zmask = int(m.group(1))

        # Check if outside of specified z range
        if Zrange is not None:
            if (Zmask < Zrange[0]) or (Zmask > Zrange[1]):
                print(f'Z-slice outside of specified range: {Zmask}')
                continue

        # Get z-range for loop
        Zloop = np.logical_and(Zrna <= Zmask + dZ,
                               Zrna >= Zmask - dZ).flatten()
        Zloop = (Zrna == Zmask).flatten()
        spots_loop = spots_all[Zloop, :]
        spots_loop_XY = np.divide(
            spots_loop[:, [0, 1]],
            fq_dict['settings']['microscope']['pix_xy']).astype(int)

        # Distance transform
        dist_nuc_outside = ndimage.distance_transform_edt(
            ~v_annot['mask_fill'])
        dist_nuc_inside = ndimage.distance_transform_edt(
            v_annot['mask_fill'])  # Negate mask
        dist_nuc = dist_nuc_outside - dist_nuc_inside

        # Indices have to be inversed to access array
        dist_nuc_RNA_loop = dist_nuc[spots_loop_XY[:, 0], spots_loop_XY[:, 1]]

        # Get distance from membrane for all pixel in the cell
        dist_membr_pix_loop = dist_nuc[mask_embryo.astype(bool)]

        # Save values
        if idx == 0:
            dist_membr_RNA = np.copy(dist_nuc_RNA_loop)
            dist_membr_pix = np.copy(dist_membr_pix_loop)
        else:
            dist_membr_RNA = np.append(dist_membr_RNA,
                                       dist_nuc_RNA_loop,
                                       axis=0)
            dist_membr_pix = np.append(dist_membr_pix,
                                       dist_membr_pix_loop,
                                       axis=0)
        idx += 1

    # *************************************************************************
    #  Load and analyze FQ results
    xTicks = binsHist[:-1]
    width = 0.9 * np.diff(binsHist)
    width_full = np.diff(binsHist)
    center = (binsHist[:-1] + binsHist[1:]) / 2

    histRNA_all, bins = np.histogram(dist_membr_RNA, binsHist, density=False)
    histPIX_all, bins = np.histogram(dist_membr_pix, binsHist, density=False)
    histRNA_norm = np.divide(histRNA_all, histPIX_all)
    counts_total = np.nansum(np.multiply(histRNA_norm, width_full))
    histRNA_norm = np.divide(histRNA_norm, counts_total)

    fig1, ax = plt.subplots(3, 1)
    ax[0].bar(center, histRNA_all, align='center', width=width)
    ax[0].set_xlabel('Dist to nuc')
    ax[0].set_ylabel('# RNAs')
    ax[0].set_xticks(xTicks)
    ax[0].set_xticklabels(xTicks.astype(int))

    ax[1].bar(center, histPIX_all, align='center', width=width)
    ax[1].set_xlabel('Dist to nuc')
    ax[1].set_ylabel('# pixels')
    ax[1].set_xticks(xTicks)
    ax[1].set_xticklabels(xTicks.astype(int))

    ax[2].bar(center, histRNA_norm, align='center', width=width)
    ax[2].set_xlabel('Distance to nuc')
    ax[2].set_ylabel('RNA counts [a.u.]')
    ax[2].set_xticks(xTicks)
    ax[2].set_xticklabels(xTicks.astype(int))

    ax[0].title.set_text('RNAs')
    ax[1].title.set_text('All pixel')
    ax[2].title.set_text('RNA renormalized with pixels')

    plt.tight_layout()
コード例 #3
0
#%% Read nuclear outlines
importlib.reload(annotationImporter)
importlib.reload(maskGenerator)

## Open FQ results
file_load = '/Volumes/PILON_HD2/fmueller/Documents/Data/ImJoy/rna-loc/NucMembEnrichment/C1-N2_imb-2-670_NG-610_04_R3D_res_GMM.txt'

## Get folders
drive, path_and_file = os.path.splitdrive(file_load)
path_results, file_results = os.path.split(path_and_file)

## Import annotations
path_annot = os.path.join(drive, path_results, 'zstack_segmentation')
folderImporter = annotationImporter.FolderImporter(channels={'nuclei': 'C4-'},
                                                   data_category={'roi': ''},
                                                   annot_ext='__RoiSet.zip',
                                                   progress_callback=None)
annotDict = folderImporter.load(path_annot)
print('average roi size:', annotDict['roi_size'])

# Generate binary masks for a selected data-set
binaryGen = maskGenerator.BinaryMaskGenerator(erose_size=5,
                                              obj_size_rem=500,
                                              save_indiv=True,
                                              progress_callback=None)

# The generate function uses as an input the sub-dictionary for one data-category and one channel
annotatFiles = annotDict['roi']['nuclei']
maskDict = binaryGen.generate(annotatFiles)

# Use a loop and the update function to add the mask dictionary to the loaded annotation dictionary
コード例 #4
0
def process_folder_fiji(path_open, channels, img_ext, annot_ext, masks_save):
    '''
    Function uses annotations generated in FIJI and creates mask based
    on the specified parameters. The resulting files are zipped and be
    used for training of a neural network with ImJoy
    '''

    ## Create folder to save results
    path_save_unet = os.path.join(path_open, 'unet_data_tmp')
    create_folder(path_save_unet)

    # Load data with FolderImporter
    folderImporter = annotationImporter.FolderImporter(channels=channels,
                                                       data_category={
                                                           'train': 'train',
                                                           'test': 'test'
                                                       },
                                                       img_ext=img_ext,
                                                       annot_ext=annot_ext)
    annotDict = folderImporter.load(path_open)
    print('average roi size:', annotDict['roi_size'])

    # Generate binary masks
    binaryGen = maskGenerator.BinaryMaskGenerator(erose_size=5,
                                                  obj_size_rem=500,
                                                  save_indiv=False)

    # Loop over data categories and verify if corresponding folder exists
    for key_categ, categ in annotDict['config']['data_category'].items():

        # Folder to save category
        path_save_categ = os.path.join(path_save_unet, key_categ)
        create_folder(path_save_categ)

        # Loop over channels in data-categ
        for key_channel, channel in annotDict['config']['channels'].items():

            # The generate function uses as an input the sub-dictionary for one data-category and one channel
            maskDict = binaryGen.generate(annotDict[key_categ][key_channel])

            # Loop over masks and save specified ones
            for key_file, v in maskDict.items():
                for key_mask_sel in masks_save[key_channel]:

                    ## Get file name without extension
                    file_base, ext = os.path.splitext(key_file)

                    ## Save label
                    img_save = maskDict[key_file][key_mask_sel]
                    file_name_save = os.path.join(
                        path_save_categ,
                        '{}_{}.png'.format(file_base, key_mask_sel))
                    imsave(file_name_save, img_save)

                    ## Save image
                    img_save = annotDict[key_categ][key_channel][key_file][
                        'image']
                    file_name_save = os.path.join(path_save_categ, key_file)
                    imsave(file_name_save, img_save)

    # Create zip file and delete original folder
    file_name_zip = os.path.join(path_open, 'unet_data')
    shutil.make_archive(file_name_zip, 'zip', path_save_unet)

    if os.path.isdir(path_save_unet):
        shutil.rmtree(path_save_unet)
コード例 #5
0
def process_file(FQ_file,
                 bin_prop=(0, 90, 20),
                 channels={'cells': 'C3-'},
                 data_category={'roi': ''},
                 annotation_extension='__RoiSet.zip',
                 img_extension='.tif',
                 show_plots=False,
                 Zrange=None,
                 dZ=2,
                 plot_callback=None,
                 progress_callback=None,
                 log_callback=None):
    '''
    Enrichment along the CELL MEMBRANE
    Function uses annotations generated in FIJI and creates mask based
    on the specified parameters.

    Args:

        plot_callback ... callback function to plot results (e.g. in ImJoy interface)

        Zrange [tuple, 2 elements]. [Optional] Tuple specifying minimum and maximum z-value that is considered
        in analysis.

        bin_prop [Tuple, 3 elements]. Specifies the bins for the histograms (min, max,delta).

    '''

    # Get input args. Has to be FIRST call!
    input_args = locals()
    input_args['plot_callback'] = str(input_args['plot_callback'])
    input_args['progress_callback'] = str(input_args['progress_callback'])
    input_args['log_callback'] = str(input_args['log_callback'])

    # Show function name and input arguments
    function_name = sys._getframe().f_code.co_name
    utils.log_message(
        f"Function ({function_name}) called with:\n {str(input_args)} ",
        callback_fun=log_callback)

    # Make sure input args are correct - assignments with 0 can come from ImJoy
    if Zrange[0] == 0 or Zrange[1] == 0:
        Zrange = None

    if bin_prop[1] == 0 or bin_prop[1] == 0:
        bin_prop = (0, 90, 20)

    ## Prepare folder to save results
    drive, path_and_file = os.path.splitdrive(FQ_file)
    path_results, file_results = os.path.split(path_and_file)
    file_base, ext = os.path.splitext(file_results)

    path_save = os.path.join(
        drive, path_results, file_base,
        'MembDist_{}'.format(time.strftime("%y%m%d-%H%M", time.localtime())))
    utils.log_message(f"Save results in folder: {path_save}",
                      callback_fun=log_callback)
    if not os.path.isdir(path_save):
        os.makedirs(path_save)

    ## Open FQ results
    fq_dict = FQtoolbox.read_FQ_matlab(FQ_file)
    spots_all = FQtoolbox.get_rna(fq_dict)
    Zrna = spots_all[:, [18]]

    # Open annotations
    utils.log_message(f'\n== Open annotations', callback_fun=log_callback)

    if 'RoiSet.zip' in annotation_extension:

        path_annot = os.path.join(drive, path_results, 'zstack_segmentation')
        utils.log_message(f"Opening annotation folder: {path_annot}",
                          callback_fun=log_callback)

        folderImporter = annotationImporter.FolderImporter(
            channels=channels,
            data_category=data_category,
            annot_ext=annotation_extension,
            progress_callback=progress_callback)
        annotDict = folderImporter.load(path_annot)
        str_size = str(annotDict['roi_size'])
        utils.log_message(f'Average roi size: {str_size}',
                          callback_fun=log_callback)

        #utils.log_message(f'{annotDict['roi_size']}', callback_fun=log_callback)
        # Generate binary masks for a selected data-set
        binaryGen = maskGenerator.BinaryMaskGenerator(
            erose_size=5,
            obj_size_rem=500,
            save_indiv=True,
            progress_callback=progress_callback)

        # The generate function uses as an input the sub-dictionary for one data-category and one channel
        annotatFiles = annotDict['roi']['cells']
        maskDict = binaryGen.generate(annotatFiles)

        # Use a loop and the update function to add the mask dictionary to the loaded annotation dictionary
        #utils.log_message(str(maskDict.keys()), callback_fun=log_callback)
        utils.log_message(f"Keys of mask dictionary: {str(maskDict.keys())} ",
                          callback_fun=log_callback)

        keys_delete = []
        for k, v in annotatFiles.items():

            # Make sure that key in present in mask, otherwise delete
            if k in maskDict:
                v.update(maskDict[k])

            else:
                keys_delete.append(k)

        utils.log_message(
            f"Deleted keys of mask dictionary: {str(keys_delete)} ",
            callback_fun=log_callback)

    # Bins of histogram
    binsHist = np.arange(bin_prop[0], bin_prop[1], bin_prop[2])
    width = 0.8 * (binsHist[1] - binsHist[0])
    center = (binsHist[:-1] + binsHist[1:]) / 2

    # Other parameters for calculation
    dist_membr_RNA = np.array([])
    dist_membr_pix = np.array([])
    idx = 0

    # Loop over all z-slices
    utils.log_message(f'\n==  Loop over slices', callback_fun=log_callback)
    hist_slice = {}
    N_annot = len(annotatFiles)

    for idx_file, (k_annot, v_annot) in enumerate(annotatFiles.items()):

        # Indicate progress via callback
        if progress_callback:
            perc = int(100 * (idx_file + 1) / (N_annot))
            progress_callback({
                "task": "analyze_slices",
                "text": f"{perc}%, {k_annot}",
                "progress": perc
            })
        else:
            #print(f'Slice {idx_file+1}/{N_annot}: {k_annot}')
            utils.log_message(f'Slice {idx_file+1}/{N_annot}: {k_annot}',
                              callback_fun=log_callback)
        # Get Z coordinate
        m = re.search('.*_Z([0-9]*)\.tif', k_annot)
        Zmask = int(m.group(1))

        # Check if outside of specified z range
        if Zrange is not None:
            if (Zmask <= Zrange[0]) or (Zmask >= Zrange[1]):
                print('Slice outside of range')
                continue

        # Get z-range for loop
        if dZ > 0:
            Zloop = np.logical_and(Zrna <= Zmask + dZ,
                                   Zrna >= Zmask - dZ).flatten()
        else:
            Zloop = (Zrna == Zmask).flatten()

        spots_loop = spots_all[Zloop, :]
        spots_loop_XY = spots_loop[:, [16, 17]].astype(int)

        # Distance transform
        dist_membr = ndimage.distance_transform_edt(
            ~v_annot['mask_edge'])  # Negate mask

        # Indices have to be inversed to access array
        dist_membr_RNA_loop = dist_membr[spots_loop_XY[:, 0], spots_loop_XY[:,
                                                                            1]]

        # Get distance from membrane for all pixel in the cell
        mask_all = v_annot['mask_fill'] + v_annot['mask_edge']
        dist_membr_pix_loop = dist_membr[mask_all]

        # Save values
        if idx == 0:
            dist_membr_RNA = np.copy(dist_membr_RNA_loop)
            dist_membr_pix = np.copy(dist_membr_pix_loop)
        else:
            dist_membr_RNA = np.append(dist_membr_RNA,
                                       dist_membr_RNA_loop,
                                       axis=0)
            dist_membr_pix = np.append(dist_membr_pix,
                                       dist_membr_pix_loop,
                                       axis=0)
        idx += 1

        # Calculate histograms
        histRNA, bins = np.histogram(dist_membr_RNA_loop,
                                     binsHist,
                                     density=False)
        histpix, bins = np.histogram(dist_membr_pix_loop,
                                     binsHist,
                                     density=False)

        histRNAnorm = histRNA / histRNA.sum()
        histpixnorm = histpix / histpix.sum()

        histRNAnormPix = np.divide(histRNAnorm, histpixnorm)
        histRNAnormPix = np.nan_to_num(histRNAnormPix)

        hist_plot = {
            'width': width,
            'center': center,
            'bins': bins,
            'histRNA': histRNA,
            'histpix': histpix,
            'histRNAnormPix': histRNAnormPix
        }
        hist_slice[f'Z{Zmask}'] = hist_plot

        # Plot results
        name_save = os.path.join(path_save, f'Z-{Zmask}.png')
        plot_results_slice(Zmask, v_annot, mask_all, spots_loop_XY, dist_membr,
                           hist_plot, name_save, show_plots)

    # Analyze all slices
    histRNA_all, bins = np.histogram(dist_membr_RNA, binsHist, density=False)
    histRNA_all_norm = histRNA_all / histRNA_all.sum()

    # Renormalize with pixel counts
    histpix_all, bins = np.histogram(dist_membr_pix, binsHist, density=False)
    histpix_all_norm = histpix_all / histpix_all.sum()

    hist_RNA_all_normPix = np.divide(histRNA_all_norm, histpix_all_norm)
    hist_RNA_all_normPix = np.nan_to_num(hist_RNA_all_normPix)

    hist_plot_all = {
        'width': width,
        'center': center,
        'bins': bins,
        'histRNA_all': histRNA_all,
        'histRNA_all_norm': histRNA_all_norm,
        'histpix_all_norm': histpix_all_norm,
        'hist_RNA_all_normPix': hist_RNA_all_normPix
    }
    name_save = os.path.join(path_save, '_DistanceEnrichmentSummary.png')
    plot_results_all(hist_plot_all, name_save, show_plots)

    if plot_callback:
        plot_callback(name_save)

    if progress_callback:
        with open(name_save, 'rb') as f:
            data = f.read()
            result = base64.b64encode(data).decode('ascii')
            imgurl = 'data:image/png;base64,' + result
            progress_callback({"task": "show_results", "src": imgurl})

    # Save entire analysis results as json (remove callback functions, since those cause errors)
    input_args.pop('show_plot', None)
    input_args.pop('plot_callback', None)
    input_args.pop('progress_callback', None)
    input_args.pop('log_callback', None)

    analysis_results = {
        'args': input_args,
        'hist_all': hist_plot_all,
        'hist_slice': hist_slice
    }

    name_json = os.path.join(path_save, 'DataAll.json')

    with open(name_json, 'w') as fp:
        json.dump(analysis_results,
                  fp,
                  sort_keys=True,
                  indent=4,
                  cls=utils.NumpyEncoder)

    # Save histogram of pooled data as csv
    name_csv = os.path.join(path_save, '_HistogramPooled.csv')
    hist_plot_all.pop('bins', None)
    hist_plot_all.pop('width', None)
    csv_header = ';'.join(hist_plot_all.keys())
    hist_values = np.array(list(hist_plot_all.values())).transpose()
    np.savetxt(name_csv,
               hist_values,
               delimiter=";",
               fmt='%f',
               header=csv_header,
               comments='')

    return analysis_results
コード例 #6
0
def calc_nuclear_enrichment(FQ_file,
                            binsHist,
                            channels={'nuclei': ''},
                            show_plots=False,
                            Zrange=None,
                            dZ=2,
                            plot_callback=None,
                            progress_callback=None,
                            log_callback=None):
    """
    Enrichment at the nuclear MEMBRANE
    Function uses annotations generated in FIJI and creates mask based
    on the specified parameters.
    """

    # Get input args. Has to be FIRST call!
    input_args = locals()

    # Get folder
    drive, path_and_file = os.path.splitdrive(FQ_file)
    path_results, file_results = os.path.split(path_and_file)
    file_base, ext = os.path.splitext(file_results)

    path_save = os.path.join(
        drive, path_results, file_base, 'NucEnvelopDist_{}'.format(
            time.strftime("%y%m%d-%H%M", time.localtime())))
    if not os.path.isdir(path_save):
        os.makedirs(path_save)

    # *************************************************************************
    # Load nuclear outline
    utils.log_message(f'Reading segmentation masks of nuclei',
                      callback_fun=log_callback)

    # Generate binary masks for a selected data-set
    binaryGen = maskGenerator.BinaryMaskGenerator(
        erose_size=5,
        obj_size_rem=500,
        save_indiv=True,
        progress_callback=progress_callback)

    # Import annotations for nuclei
    path_annot = os.path.join(drive, path_results, 'zstack_segmentation')
    folderImporter = annotationImporter.FolderImporter(
        channels=channels,
        data_category={'roi': ''},
        annot_ext='__RoiSet.zip',
        progress_callback=progress_callback)
    annotDict = folderImporter.load(path_annot)

    # The generate function uses as an input the sub-dictionary for one data-category and one channel
    annotatFiles = annotDict['roi']['nuclei']
    mask_dict_nuclei = binaryGen.generate(annotatFiles)

    keys_delete = []
    for k, v in annotatFiles.items():

        # Make sure that key in present in mask, otherwise delete
        if k in mask_dict_nuclei:
            v.update(mask_dict_nuclei[k])

        else:
            keys_delete.append(k)

    # *************************************************************************
    #  Load embryo outline
    file_embryo = os.path.join(drive, path_results, 'embryo_contour.roi')

    # Convert dictionary & get size of ROIS
    roi_import = read_roi_file(file_embryo)
    roi_dict = {}
    roi_dict['embryo'] = {}
    roi_dict['embryo']['type'] = roi_import['embryo_contour']['type']
    roi_dict['embryo']['pos'] = np.column_stack(
        (roi_import['embryo_contour']['y'], roi_import['embryo_contour']['x']))

    # Assemble structure to call mask generator
    image_size = annotatFiles.values().__iter__().__next__()['image'].shape
    image_fake = np.zeros(image_size, dtype=np.uint8)

    annotat_files_embryo = {}
    annotat_files_embryo['embryo_contour'] = {}
    annotat_files_embryo['embryo_contour']['roi'] = roi_dict
    annotat_files_embryo['embryo_contour']['image'] = image_fake

    mask_dict_embryo = binaryGen.generate(annotat_files_embryo)
    mask_embryo = mask_dict_embryo['embryo_contour']['mask_fill']

    # *************************************************************************
    #  Load and analyze FQ results

    fq_dict = FQtoolbox.read_FQ_matlab(FQ_file)
    spots_all = FQtoolbox.get_rna(fq_dict)

    # Z position in pixel
    Zrna = np.divide(spots_all[:, [2]],
                     fq_dict['settings']['microscope']['pix_z']).astype(int)

    # Other parameters for calculation
    dist_membr_RNA = np.array([])
    dist_membr_pix = np.array([])
    idx = 0

    # Loop over all z-slices
    utils.log_message(f'Loop over z-slices', callback_fun=log_callback)

    N_annot = len(annotatFiles)
    for idx_file, (k_annot, v_annot) in enumerate(annotatFiles.items()):

        # Indicate progress via callback
        if progress_callback:
            perc = int(100 * (idx_file + 1) / (N_annot))
            progress_callback({
                "task": "analyze_slices",
                "text": f"{perc}%, {k_annot}",
                "progress": perc
            })
        else:
            print(f'Slice: {k_annot}')

        # Get Z coordinate
        m = re.search('.*_Z([0-9]*)\.tif', k_annot)
        Zmask = int(m.group(1))

        # Check if outside of specified z range
        if Zrange is not None:
            if not (Zrange[0] == 0 and Zrange[1] == 0):
                if (Zmask < Zrange[0]) or (Zmask > Zrange[1]):
                    print(f'Z-slice outside of specified range: {Zmask}')
                    continue

        # Get z-range for loop
        if dZ == 0:
            Zloop = np.logical_and(Zrna <= Zmask + dZ,
                                   Zrna >= Zmask - dZ).flatten()
        else:
            Zloop = (Zrna == Zmask).flatten()

        spots_loop = spots_all[Zloop, :]
        spots_loop_XY = np.divide(
            spots_loop[:, [0, 1]],
            fq_dict['settings']['microscope']['pix_xy']).astype(int)

        # Distance transform
        dist_nuc_outside = ndimage.distance_transform_edt(
            ~v_annot['mask_fill'])
        dist_nuc_inside = ndimage.distance_transform_edt(
            v_annot['mask_fill'])  # Negate mask
        dist_nuc = dist_nuc_outside - dist_nuc_inside

        # Indices have to be inverted to access array
        dist_nuc_RNA_loop = dist_nuc[spots_loop_XY[:, 0], spots_loop_XY[:, 1]]

        # Get distance from membrane for all pixel in the cell
        dist_membr_pix_loop = dist_nuc[mask_embryo.astype(bool)]

        # Save values
        if idx == 0:
            dist_membr_RNA = np.copy(dist_nuc_RNA_loop)
            dist_membr_pix = np.copy(dist_membr_pix_loop)
        else:
            dist_membr_RNA = np.append(dist_membr_RNA,
                                       dist_nuc_RNA_loop,
                                       axis=0)
            dist_membr_pix = np.append(dist_membr_pix,
                                       dist_membr_pix_loop,
                                       axis=0)
        idx += 1

    # *************************************************************************
    #  Load and analyze FQ results
    utils.log_message(f'Analyzing smFISH data', callback_fun=log_callback)

    x_ticks = binsHist[:-1]
    width = 0.9 * np.diff(binsHist)
    width_full = np.diff(binsHist)
    center = (binsHist[:-1] + binsHist[1:]) / 2

    #histRNA_all, bins = np.histogram(dist_membr_RNA,binsHist ,density=False)
    #histPIX_all, bins = np.histogram(dist_membr_pix,binsHist ,density=False)
    #histRNA_norm = np.divide(histRNA_all,histPIX_all)
    #counts_total = np.nansum(np.multiply(histRNA_norm,width_full))
    #histRNA_norm = np.divide(histRNA_norm,counts_total)

    # Distance of all pixel from distance map
    hist_pix_all, bins = np.histogram(dist_membr_pix, binsHist, density=False)
    hist_pix_all_norm = hist_pix_all / hist_pix_all.sum()

    # Distance of all RNAs
    hist_rna_all, bins = np.histogram(dist_membr_RNA, binsHist, density=False)
    hist_rna_all_norm = hist_rna_all / hist_rna_all.sum()

    # Re-normalize RNA distances
    hist_rna_all_norm_pix = np.divide(hist_rna_all_norm, hist_pix_all_norm)
    hist_rna_all_norm_pix = np.nan_to_num(hist_rna_all_norm_pix)

    # Save file with histogram
    histo_dist = {
        'center': center,
        'width': width_full,
        'bins': binsHist,
        'x_ticks': x_ticks,
        'hist_pix_all': hist_pix_all,
        'hist_pix_all_norm': hist_pix_all_norm,
        'hist_rna_all': hist_rna_all,
        'hist_rna_all_norm': hist_rna_all_norm,
        'hist_rna_all_norm_pix': hist_rna_all_norm_pix
    }

    # Save entire analysis results as json
    input_args.pop('show_plot', None)
    input_args.pop('plot_callback', None)
    input_args.pop('progress_callback', None)
    input_args.pop('log_callback', None)

    analysis_results = {
        'args': input_args,
        'histogram': histo_dist,
    }

    name_json = os.path.join(path_save, 'DataAnalysis.json')

    with open(name_json, 'w') as fp:
        json.dump(analysis_results,
                  fp,
                  sort_keys=True,
                  indent=4,
                  cls=utils.NumpyEncoder)

    # Save histogram of pooled data as csv
    name_csv = os.path.join(path_save, '_HistogramDistances.csv')
    histo_dist.pop('bins', None)
    csv_header = ';'.join(histo_dist.keys())
    hist_values = np.array(list(histo_dist.values())).transpose()
    np.savetxt(name_csv,
               hist_values,
               delimiter=";",
               fmt='%f',
               header=csv_header,
               comments='')

    # *************************************************************************
    # Plot results
    # Don't show plots when they are saved
    if not show_plots:
        plt.ioff()

    fig1, ax = plt.subplots(3, 1)
    ax[0].bar(center, hist_rna_all, align='center', width=width)
    ax[0].set_xlabel('Dist to nuc')
    ax[0].set_ylabel('# RNAs')
    ax[0].set_xticks(x_ticks)
    ax[0].set_xticklabels(x_ticks.astype(int))

    ax[1].bar(center, hist_pix_all, align='center', width=width)
    ax[1].set_xlabel('Dist to nuc')
    ax[1].set_ylabel('# pixels')
    ax[1].set_xticks(x_ticks)
    ax[1].set_xticklabels(x_ticks.astype(int))

    ax[2].bar(center, hist_rna_all_norm_pix, align='center', width=width)
    ax[2].set_xlabel('Distance to nuc')
    ax[2].set_ylabel('RNA counts [a.u.]')
    ax[2].set_xticks(x_ticks)
    ax[2].set_xticklabels(x_ticks.astype(int))

    ax[0].title.set_text('RNAs')
    ax[1].title.set_text('All pixel in images')
    ax[2].title.set_text('RNAs renormalized with pixels')

    plt.tight_layout()

    # Save and close if display not required
    name_save = os.path.join(path_save, '_DistanceEnrichmentSummary.png')
    plt.savefig(name_save, dpi=300)

    if not show_plots:
        plt.close()

    if plot_callback:
        plot_callback(name_save)

    if progress_callback:
        with open(name_save, 'rb') as f:
            data = f.read()
            result = base64.b64encode(data).decode('ascii')
            img_url = 'data:image/png;base64,' + result
            progress_callback({"task": "show_results", "src": img_url})